Explorar o código

Merge tag 'usb-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB patches from Greg Kroah-Hartman:
 "Here's the big USB merge for 3.9-rc1

  Nothing major, lots of gadget fixes, and of course, xhci stuff.

  All of this has been in linux-next for a while, with the exception of
  the last 3 patches, which were reverts of patches in the tree that
  caused problems, they went in yesterday."

* tag 'usb-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (190 commits)
  Revert "USB: EHCI: make ehci-vt8500 a separate driver"
  Revert "USB: EHCI: make ehci-orion a separate driver"
  Revert "USB: update host controller Kconfig entries"
  USB: update host controller Kconfig entries
  USB: EHCI: make ehci-orion a separate driver
  USB: EHCI: make ehci-vt8500 a separate driver
  USB: usb-storage: unusual_devs update for Super TOP SATA bridge
  USB: ehci-omap: Fix autoloading of module
  USB: ehci-omap: Don't free gpios that we didn't request
  USB: option: add Huawei "ACM" devices using protocol = vendor
  USB: serial: fix null-pointer dereferences on disconnect
  USB: option: add Yota / Megafon M100-1 4g modem
  drivers/usb: add missing GENERIC_HARDIRQS dependencies
  USB: storage: properly handle the endian issues of idProduct
  testusb: remove all mentions of 'usbfs'
  usb: gadget: imx_udc: make it depend on BROKEN
  usb: omap_control_usb: fix compile warning
  ARM: OMAP: USB: Add phy binding information
  ARM: OMAP2: MUSB: Specify omap4 has mailbox
  ARM: OMAP: devices: create device for usb part of control module
  ...
Linus Torvalds %!s(int64=12) %!d(string=hai) anos
pai
achega
74e1a2a393
Modificáronse 100 ficheiros con 2848 adicións e 1806 borrados
  1. 9 0
      Documentation/ABI/testing/sysfs-bus-usb
  2. 22 0
      Documentation/devicetree/bindings/usb/dwc3.txt
  3. 33 1
      Documentation/devicetree/bindings/usb/omap-usb.txt
  4. 55 0
      Documentation/devicetree/bindings/usb/samsung-usbphy.txt
  5. 30 5
      Documentation/devicetree/bindings/usb/usb-phy.txt
  6. 20 0
      Documentation/devicetree/bindings/usb/usb3503.txt
  7. 2 1
      MAINTAINERS
  8. 2 0
      arch/arm/mach-omap2/board-2430sdp.c
  9. 2 0
      arch/arm/mach-omap2/board-3430sdp.c
  10. 2 0
      arch/arm/mach-omap2/board-4430sdp.c
  11. 2 0
      arch/arm/mach-omap2/board-cm-t35.c
  12. 2 0
      arch/arm/mach-omap2/board-devkit8000.c
  13. 2 0
      arch/arm/mach-omap2/board-igep0020.c
  14. 2 0
      arch/arm/mach-omap2/board-ldp.c
  15. 2 0
      arch/arm/mach-omap2/board-omap3beagle.c
  16. 2 0
      arch/arm/mach-omap2/board-omap3evm.c
  17. 2 0
      arch/arm/mach-omap2/board-omap3logic.c
  18. 2 0
      arch/arm/mach-omap2/board-omap3pandora.c
  19. 2 0
      arch/arm/mach-omap2/board-omap3stalker.c
  20. 2 0
      arch/arm/mach-omap2/board-omap3touchbook.c
  21. 2 0
      arch/arm/mach-omap2/board-omap4panda.c
  22. 2 0
      arch/arm/mach-omap2/board-overo.c
  23. 2 0
      arch/arm/mach-omap2/board-rm680.c
  24. 2 0
      arch/arm/mach-omap2/board-zoom-peripherals.c
  25. 45 0
      arch/arm/mach-omap2/devices.c
  26. 0 13
      arch/arm/mach-omap2/omap_hwmod_44xx_data.c
  27. 3 0
      arch/arm/mach-omap2/usb-musb.c
  28. 1 0
      drivers/base/power/qos.c
  29. 1 1
      drivers/usb/c67x00/c67x00-ll-hpi.c
  30. 1 1
      drivers/usb/chipidea/ci13xxx_imx.h
  31. 1 1
      drivers/usb/chipidea/core.c
  32. 1 0
      drivers/usb/core/Makefile
  33. 10 3
      drivers/usb/core/devices.c
  34. 2 1
      drivers/usb/core/devio.c
  35. 1 1
      drivers/usb/core/generic.c
  36. 4 1
      drivers/usb/core/hcd.c
  37. 344 272
      drivers/usb/core/hub.c
  38. 122 0
      drivers/usb/core/hub.h
  39. 1 1
      drivers/usb/core/message.c
  40. 202 0
      drivers/usb/core/port.c
  41. 22 9
      drivers/usb/core/sysfs.c
  42. 12 0
      drivers/usb/core/usb.h
  43. 30 1
      drivers/usb/dwc3/Kconfig
  44. 8 2
      drivers/usb/dwc3/Makefile
  45. 25 6
      drivers/usb/dwc3/core.c
  46. 20 4
      drivers/usb/dwc3/core.h
  47. 14 24
      drivers/usb/dwc3/debugfs.c
  48. 26 31
      drivers/usb/dwc3/dwc3-exynos.c
  49. 93 59
      drivers/usb/dwc3/dwc3-omap.c
  50. 179 113
      drivers/usb/dwc3/gadget.c
  51. 1 1
      drivers/usb/dwc3/host.c
  52. 23 1
      drivers/usb/gadget/Kconfig
  53. 7 1
      drivers/usb/gadget/Makefile
  54. 31 11
      drivers/usb/gadget/acm_ms.c
  55. 14 45
      drivers/usb/gadget/amd5536udc.c
  56. 2 0
      drivers/usb/gadget/amd5536udc.h
  57. 2 3
      drivers/usb/gadget/at91_udc.c
  58. 27 9
      drivers/usb/gadget/cdc2.c
  59. 268 58
      drivers/usb/gadget/composite.c
  60. 8 6
      drivers/usb/gadget/dbgp.c
  61. 104 49
      drivers/usb/gadget/f_acm.c
  62. 2 3
      drivers/usb/gadget/f_fs.c
  63. 54 49
      drivers/usb/gadget/f_loopback.c
  64. 5 32
      drivers/usb/gadget/f_mass_storage.c
  65. 9 9
      drivers/usb/gadget/f_ncm.c
  66. 0 4
      drivers/usb/gadget/f_obex.c
  67. 0 4
      drivers/usb/gadget/f_serial.c
  68. 125 75
      drivers/usb/gadget/f_sourcesink.c
  69. 2 7
      drivers/usb/gadget/f_uac2.c
  70. 2 1
      drivers/usb/gadget/f_uvc.c
  71. 1 1
      drivers/usb/gadget/fsl_qe_udc.c
  72. 12 48
      drivers/usb/gadget/fsl_udc_core.c
  73. 116 0
      drivers/usb/gadget/functions.c
  74. 19 48
      drivers/usb/gadget/fusb300_udc.c
  75. 2 0
      drivers/usb/gadget/fusb300_udc.h
  76. 27 8
      drivers/usb/gadget/g_zero.h
  77. 1 1
      drivers/usb/gadget/gmidi.c
  78. 14 56
      drivers/usb/gadget/goku_udc.c
  79. 1 0
      drivers/usb/gadget/goku_udc.h
  80. 20 52
      drivers/usb/gadget/m66592-udc.c
  81. 1 0
      drivers/usb/gadget/m66592-udc.h
  82. 56 15
      drivers/usb/gadget/multi.c
  83. 99 147
      drivers/usb/gadget/mv_udc_core.c
  84. 15 0
      drivers/usb/gadget/net2280.c
  85. 31 12
      drivers/usb/gadget/nokia.c
  86. 13 38
      drivers/usb/gadget/omap_udc.c
  87. 14 53
      drivers/usb/gadget/pch_udc.c
  88. 14 48
      drivers/usb/gadget/pxa25x_udc.c
  89. 1 0
      drivers/usb/gadget/pxa25x_udc.h
  90. 15 46
      drivers/usb/gadget/pxa27x_udc.c
  91. 1 0
      drivers/usb/gadget/pxa27x_udc.h
  92. 1 1
      drivers/usb/gadget/r8a66597-udc.c
  93. 29 15
      drivers/usb/gadget/s3c-hsotg.c
  94. 6 7
      drivers/usb/gadget/s3c-hsudc.c
  95. 12 53
      drivers/usb/gadget/s3c2410_udc.c
  96. 1 0
      drivers/usb/gadget/s3c2410_udc.h
  97. 100 18
      drivers/usb/gadget/serial.c
  98. 0 61
      drivers/usb/gadget/storage_common.c
  99. 157 156
      drivers/usb/gadget/u_serial.c
  100. 10 3
      drivers/usb/gadget/u_serial.h

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

@@ -227,3 +227,12 @@ Contact:	Lan Tianyu <tianyu.lan@intel.com>
 Description:
 Description:
 		The /sys/bus/usb/devices/.../(hub interface)/portX
 		The /sys/bus/usb/devices/.../(hub interface)/portX
 		is usb port device's sysfs directory.
 		is usb port device's sysfs directory.
+
+What:		/sys/bus/usb/devices/.../(hub interface)/portX/connect_type
+Date:		January 2013
+Contact:	Lan Tianyu <tianyu.lan@intel.com>
+Description:
+		Some platforms provide usb port connect types through ACPI.
+		This attribute is to expose these information to user space.
+		The file will read "hotplug", "wired" and "not used" if the
+		information is available, and "unknown" otherwise.

+ 22 - 0
Documentation/devicetree/bindings/usb/dwc3.txt

@@ -0,0 +1,22 @@
+synopsys DWC3 CORE
+
+DWC3- USB3 CONTROLLER
+
+Required properties:
+ - compatible: must be "synopsys,dwc3"
+ - reg : Address and length of the register set for the device
+ - interrupts: Interrupts used by the dwc3 controller.
+ - usb-phy : array of phandle for the PHY device
+
+Optional properties:
+ - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
+
+This is usually a subnode to DWC3 glue to which it is connected.
+
+dwc3@4a030000 {
+	compatible = "synopsys,dwc3";
+	reg = <0x4a030000 0xcfff>;
+	interrupts = <0 92 4>
+	usb-phy = <&usb2_phy>, <&usb3,phy>;
+	tx-fifo-resize;
+};

+ 33 - 1
Documentation/devicetree/bindings/usb/omap-usb.txt

@@ -1,8 +1,11 @@
-OMAP GLUE
+OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS
 
 
 OMAP MUSB GLUE
 OMAP MUSB GLUE
  - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
  - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
  - ti,hwmods : must be "usb_otg_hs"
  - ti,hwmods : must be "usb_otg_hs"
+ - ti,has-mailbox : to specify that omap uses an external mailbox
+   (in control module) to communicate with the musb core during device connect
+   and disconnect.
  - multipoint : Should be "1" indicating the musb controller supports
  - multipoint : Should be "1" indicating the musb controller supports
    multipoint. This is a MUSB configuration-specific setting.
    multipoint. This is a MUSB configuration-specific setting.
  - num_eps : Specifies the number of endpoints. This is also a
  - num_eps : Specifies the number of endpoints. This is also a
@@ -16,13 +19,19 @@ OMAP MUSB GLUE
  - power : Should be "50". This signifies the controller can supply upto
  - power : Should be "50". This signifies the controller can supply upto
    100mA when operating in host mode.
    100mA when operating in host mode.
 
 
+Optional properties:
+ - ctrl-module : phandle of the control module this glue uses to write to
+   mailbox
+
 SOC specific device node entry
 SOC specific device node entry
 usb_otg_hs: usb_otg_hs@4a0ab000 {
 usb_otg_hs: usb_otg_hs@4a0ab000 {
 	compatible = "ti,omap4-musb";
 	compatible = "ti,omap4-musb";
 	ti,hwmods = "usb_otg_hs";
 	ti,hwmods = "usb_otg_hs";
+	ti,has-mailbox;
 	multipoint = <1>;
 	multipoint = <1>;
 	num_eps = <16>;
 	num_eps = <16>;
 	ram_bits = <12>;
 	ram_bits = <12>;
+	ctrl-module = <&omap_control_usb>;
 };
 };
 
 
 Board specific device node entry
 Board specific device node entry
@@ -31,3 +40,26 @@ Board specific device node entry
 	mode = <3>;
 	mode = <3>;
 	power = <50>;
 	power = <50>;
 };
 };
+
+OMAP CONTROL USB
+
+Required properties:
+ - compatible: Should be "ti,omap-control-usb"
+ - reg : Address and length of the register set for the device. It contains
+   the address of "control_dev_conf" and "otghs_control" or "phy_power_usb"
+   depending upon omap4 or omap5.
+ - reg-names: The names of the register addresses corresponding to the registers
+   filled in "reg".
+ - ti,type: This is used to differentiate whether the control module has
+   usb mailbox or usb3 phy power. omap4 has usb mailbox in control module to
+   notify events to the musb core and omap5 has usb3 phy power register to
+   power on usb3 phy. Should be "1" if it has mailbox and "2" if it has usb3
+   phy power.
+
+omap_control_usb: omap-control-usb@4a002300 {
+	compatible = "ti,omap-control-usb";
+	reg = <0x4a002300 0x4>,
+	      <0x4a00233c 0x4>;
+	reg-names = "control_dev_conf", "otghs_control";
+	ti,type = <1>;
+};

+ 55 - 0
Documentation/devicetree/bindings/usb/samsung-usbphy.txt

@@ -0,0 +1,55 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb phy for
+s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
+across Samsung SOCs.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+
+Exynos4210:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
+
+Exynos5250:
+- compatible : should be "samsung,exynos5250-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
+
+Optional properties:
+- #address-cells: should be '1' when usbphy node has a child node with 'reg'
+		  property.
+- #size-cells: should be '1' when usbphy node has a child node with 'reg'
+	       property.
+- ranges: allows valid translation between child's address space and parent's
+	  address space.
+
+- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
+  interface for usb-phy. It should provide the following information required by
+  usb-phy controller to control phy.
+  - reg : base physical address of PHY_CONTROL registers.
+	  The size of this register is the total sum of size of all PHY_CONTROL
+	  registers that the SoC has. For example, the size will be
+	  '0x4' in case we have only one PHY_CONTROL register (e.g.
+	  OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
+	  and, '0x8' in case we have two PHY_CONTROL registers (e.g.
+	  USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
+	  and so on.
+
+Example:
+ - Exynos4210
+
+	usbphy@125B0000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "samsung,exynos4210-usbphy";
+		reg = <0x125B0000 0x100>;
+		ranges;
+
+		usbphy-sys {
+			/* USB device and host PHY_CONTROL registers */
+			reg = <0x10020704 0x8>;
+		};
+	};

+ 30 - 5
Documentation/devicetree/bindings/usb/usb-phy.txt

@@ -4,14 +4,39 @@ OMAP USB2 PHY
 
 
 Required properties:
 Required properties:
  - compatible: Should be "ti,omap-usb2"
  - compatible: Should be "ti,omap-usb2"
- - reg : Address and length of the register set for the device. Also
-add the address of control module dev conf register until a driver for
-control module is added
+ - reg : Address and length of the register set for the device.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+   the PHY.
 
 
 This is usually a subnode of ocp2scp to which it is connected.
 This is usually a subnode of ocp2scp to which it is connected.
 
 
 usb2phy@4a0ad080 {
 usb2phy@4a0ad080 {
 	compatible = "ti,omap-usb2";
 	compatible = "ti,omap-usb2";
-	reg = <0x4a0ad080 0x58>,
-	      <0x4a002300 0x4>;
+	reg = <0x4a0ad080 0x58>;
+	ctrl-module = <&omap_control_usb>;
+};
+
+OMAP USB3 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb3"
+ - reg : Address and length of the register set for the device.
+ - reg-names: The names of the register addresses corresponding to the registers
+   filled in "reg".
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+   the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb3phy@4a084400 {
+	compatible = "ti,omap-usb3";
+	reg = <0x4a084400 0x80>,
+	      <0x4a084800 0x64>,
+	      <0x4a084c00 0x40>;
+	reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+	ctrl-module = <&omap_control_usb>;
 };
 };

+ 20 - 0
Documentation/devicetree/bindings/usb/usb3503.txt

@@ -0,0 +1,20 @@
+SMSC USB3503 High-Speed Hub Controller
+
+Required properties:
+- compatible: Should be "smsc,usb3503".
+- reg: Specifies the i2c slave address, it should be 0x08.
+- connect-gpios: Should specify GPIO for connect.
+- intn-gpios: Should specify GPIO for interrupt.
+- reset-gpios: Should specify GPIO for reset.
+- initial-mode: Should specify initial mode.
+                (1 for HUB mode, 2 for STANDBY mode)
+
+Examples:
+	usb3503@08 {
+		compatible = "smsc,usb3503";
+		reg = <0x08>;
+		connect-gpios = <&gpx3 0 1>;
+		intn-gpios = <&gpx3 4 1>;
+		reset-gpios = <&gpx3 5 1>;
+		initial-mode = <1>;
+	};

+ 2 - 1
MAINTAINERS

@@ -7927,9 +7927,10 @@ F:	drivers/net/wireless/ath/ar5523/
 USB ATTACHED SCSI
 USB ATTACHED SCSI
 M:	Matthew Wilcox <willy@linux.intel.com>
 M:	Matthew Wilcox <willy@linux.intel.com>
 M:	Sarah Sharp <sarah.a.sharp@linux.intel.com>
 M:	Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M:	Gerd Hoffmann <kraxel@redhat.com>
 L:	linux-usb@vger.kernel.org
 L:	linux-usb@vger.kernel.org
 L:	linux-scsi@vger.kernel.org
 L:	linux-scsi@vger.kernel.org
-S:	Supported
+S:	Maintained
 F:	drivers/usb/storage/uas.c
 F:	drivers/usb/storage/uas.c
 
 
 USB CDC ETHERNET DRIVER
 USB CDC ETHERNET DRIVER

+ 2 - 0
arch/arm/mach-omap2/board-2430sdp.c

@@ -27,6 +27,7 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -263,6 +264,7 @@ static void __init omap_2430sdp_init(void)
 	omap_hsmmc_init(mmc);
 	omap_hsmmc_init(mmc);
 
 
 	omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
 	omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 
 
 	board_smc91x_init();
 	board_smc91x_init();

+ 2 - 0
arch/arm/mach-omap2/board-3430sdp.c

@@ -25,6 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -579,6 +580,7 @@ static void __init omap_3430sdp_init(void)
 	omap_ads7846_init(1, gpio_pendown, 310, NULL);
 	omap_ads7846_init(1, gpio_pendown, 310, NULL);
 	omap_serial_init();
 	omap_serial_init();
 	omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
 	omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	board_smc91x_init();
 	board_smc91x_init();
 	board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
 	board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);

+ 2 - 0
arch/arm/mach-omap2/board-4430sdp.c

@@ -28,6 +28,7 @@
 #include <linux/leds_pwm.h>
 #include <linux/leds_pwm.h>
 #include <linux/platform_data/omap4-keypad.h>
 #include <linux/platform_data/omap4-keypad.h>
 #include <linux/usb/musb.h>
 #include <linux/usb/musb.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/hardware/gic.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -696,6 +697,7 @@ static void __init omap_4430sdp_init(void)
 	omap4_sdp4430_wifi_init();
 	omap4_sdp4430_wifi_init();
 	omap4_twl6030_hsmmc_init(mmc);
 	omap4_twl6030_hsmmc_init(mmc);
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
 	usb_musb_init(&musb_board_data);
 	usb_musb_init(&musb_board_data);
 
 
 	status = omap_ethernet_init();
 	status = omap_ethernet_init();

+ 2 - 0
arch/arm/mach-omap2/board-cm-t35.c

@@ -30,6 +30,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/tdo24m.h>
 #include <linux/spi/tdo24m.h>
@@ -724,6 +725,7 @@ static void __init cm_t3x_common_init(void)
 	cm_t35_init_display();
 	cm_t35_init_display();
 	omap_twl4030_audio_init("cm-t3x");
 	omap_twl4030_audio_init("cm-t3x");
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	cm_t35_init_usbh();
 	cm_t35_init_usbh();
 	cm_t35_init_camera();
 	cm_t35_init_camera();

+ 2 - 0
arch/arm/mach-omap2/board-devkit8000.c

@@ -29,6 +29,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
@@ -622,6 +623,7 @@ static void __init devkit8000_init(void)
 
 
 	omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
 	omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	board_nand_init(devkit8000_nand_partitions,
 	board_nand_init(devkit8000_nand_partitions,

+ 2 - 0
arch/arm/mach-omap2/board-igep0020.c

@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/input.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/fixed.h>
@@ -625,6 +626,7 @@ static void __init igep_init(void)
 	omap_serial_init();
 	omap_serial_init();
 	omap_sdrc_init(m65kxxxxam_sdrc_params,
 	omap_sdrc_init(m65kxxxxam_sdrc_params,
 				  m65kxxxxam_sdrc_params);
 				  m65kxxxxam_sdrc_params);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 
 
 	igep_flash_init();
 	igep_flash_init();

+ 2 - 0
arch/arm/mach-omap2/board-ldp.c

@@ -28,6 +28,7 @@
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 #include <linux/smsc911x.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -418,6 +419,7 @@ static void __init omap_ldp_init(void)
 	omap_ads7846_init(1, 54, 310, NULL);
 	omap_ads7846_init(1, 54, 310, NULL);
 	omap_serial_init();
 	omap_serial_init();
 	omap_sdrc_init(NULL, NULL);
 	omap_sdrc_init(NULL, NULL);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
 	board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
 			ZOOM_NAND_CS, 0, nand_default_timings);
 			ZOOM_NAND_CS, 0, nand_default_timings);

+ 2 - 0
arch/arm/mach-omap2/board-omap3beagle.c

@@ -30,6 +30,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
@@ -519,6 +520,7 @@ static void __init omap3_beagle_init(void)
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params,
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params,
 				  mt46h32m32lf6_sdrc_params);
 				  mt46h32m32lf6_sdrc_params);
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	board_nand_init(omap3beagle_nand_partitions,
 	board_nand_init(omap3beagle_nand_partitions,

+ 2 - 0
arch/arm/mach-omap2/board-omap3evm.c

@@ -41,6 +41,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/export.h>
 #include <linux/export.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -734,6 +735,7 @@ static void __init omap3_evm_init(void)
 		omap_mux_init_gpio(135, OMAP_PIN_OUTPUT);
 		omap_mux_init_gpio(135, OMAP_PIN_OUTPUT);
 		usbhs_bdata.reset_gpio_port[1] = 135;
 		usbhs_bdata.reset_gpio_port[1] = 135;
 	}
 	}
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(&musb_board_data);
 	usb_musb_init(&musb_board_data);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	board_nand_init(omap3evm_nand_partitions,
 	board_nand_init(omap3evm_nand_partitions,

+ 2 - 0
arch/arm/mach-omap2/board-omap3logic.c

@@ -29,6 +29,7 @@
 
 
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -215,6 +216,7 @@ static void __init omap3logic_init(void)
 	board_mmc_init();
 	board_mmc_init();
 	board_smsc911x_init();
 	board_smsc911x_init();
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	/* Ensure SDRC pins are mux'd for self-refresh */

+ 2 - 0
arch/arm/mach-omap2/board-omap3pandora.c

@@ -35,6 +35,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/fixed.h>
+#include <linux/usb/phy.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -601,6 +602,7 @@ static void __init omap3pandora_init(void)
 			ARRAY_SIZE(omap3pandora_spi_board_info));
 			ARRAY_SIZE(omap3pandora_spi_board_info));
 	omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
 	omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	gpmc_nand_init(&pandora_nand_data, NULL);
 	gpmc_nand_init(&pandora_nand_data, NULL);
 
 

+ 2 - 0
arch/arm/mach-omap2/board-omap3stalker.c

@@ -33,6 +33,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/smsc911x.h>
 #include <linux/smsc911x.h>
 #include <linux/i2c/at24.h>
 #include <linux/i2c/at24.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -404,6 +405,7 @@ static void __init omap3_stalker_init(void)
 
 
 	omap_serial_init();
 	omap_serial_init();
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL);
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);
 	omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);

+ 2 - 0
arch/arm/mach-omap2/board-omap3touchbook.c

@@ -28,6 +28,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
@@ -365,6 +366,7 @@ static void __init omap3_touchbook_init(void)
 
 
 	/* Touchscreen and accelerometer */
 	/* Touchscreen and accelerometer */
 	omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
 	omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	board_nand_init(omap3touchbook_nand_partitions,
 	board_nand_init(omap3touchbook_nand_partitions,

+ 2 - 0
arch/arm/mach-omap2/board-omap4panda.c

@@ -30,6 +30,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/fixed.h>
 #include <linux/ti_wilink_st.h>
 #include <linux/ti_wilink_st.h>
 #include <linux/usb/musb.h>
 #include <linux/usb/musb.h>
+#include <linux/usb/phy.h>
 #include <linux/wl12xx.h>
 #include <linux/wl12xx.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 
 
@@ -447,6 +448,7 @@ static void __init omap4_panda_init(void)
 	omap_sdrc_init(NULL, NULL);
 	omap_sdrc_init(NULL, NULL);
 	omap4_twl6030_hsmmc_init(mmc);
 	omap4_twl6030_hsmmc_init(mmc);
 	omap4_ehci_init();
 	omap4_ehci_init();
+	usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
 	usb_musb_init(&musb_board_data);
 	usb_musb_init(&musb_board_data);
 	omap4_panda_display_init();
 	omap4_panda_display_init();
 }
 }

+ 2 - 0
arch/arm/mach-omap2/board-overo.c

@@ -36,6 +36,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
 
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 #include <linux/platform_data/mtd-nand-omap2.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
@@ -499,6 +500,7 @@ static void __init overo_init(void)
 				  mt46h32m32lf6_sdrc_params);
 				  mt46h32m32lf6_sdrc_params);
 	board_nand_init(overo_nand_partitions,
 	board_nand_init(overo_nand_partitions,
 			ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
 			ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	usbhs_init(&usbhs_bdata);
 	overo_spi_init();
 	overo_spi_init();

+ 2 - 0
arch/arm/mach-omap2/board-rm680.c

@@ -18,6 +18,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -134,6 +135,7 @@ static void __init rm680_init(void)
 	sdrc_params = nokia_get_sdram_timings();
 	sdrc_params = nokia_get_sdram_timings();
 	omap_sdrc_init(sdrc_params, sdrc_params);
 	omap_sdrc_init(sdrc_params, sdrc_params);
 
 
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	rm680_peripherals_init();
 	rm680_peripherals_init();
 }
 }

+ 2 - 0
arch/arm/mach-omap2/board-zoom-peripherals.c

@@ -20,6 +20,7 @@
 #include <linux/wl12xx.h>
 #include <linux/wl12xx.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/gpio-omap.h>
+#include <linux/usb/phy.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -298,6 +299,7 @@ void __init zoom_peripherals_init(void)
 	omap_hsmmc_init(mmc);
 	omap_hsmmc_init(mmc);
 	omap_i2c_init();
 	omap_i2c_init();
 	platform_device_register(&omap_vwlan_device);
 	platform_device_register(&omap_vwlan_device);
+	usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
 	usb_musb_init(NULL);
 	usb_musb_init(NULL);
 	enable_board_wakeup_source();
 	enable_board_wakeup_source();
 	omap_serial_init();
 	omap_serial_init();

+ 45 - 0
arch/arm/mach-omap2/devices.c

@@ -20,6 +20,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/omap4-keypad.h>
 #include <linux/platform_data/omap4-keypad.h>
 #include <linux/platform_data/omap_ocp2scp.h>
 #include <linux/platform_data/omap_ocp2scp.h>
+#include <linux/usb/omap_control_usb.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 #include <asm/mach/map.h>
@@ -254,6 +255,49 @@ static inline void omap_init_camera(void)
 #endif
 #endif
 }
 }
 
 
+#if IS_ENABLED(CONFIG_OMAP_CONTROL_USB)
+static struct omap_control_usb_platform_data omap4_control_usb_pdata = {
+	.type = 1,
+};
+
+struct resource omap4_control_usb_res[] = {
+	{
+		.name	= "control_dev_conf",
+		.start	= 0x4a002300,
+		.end	= 0x4a002303,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "otghs_control",
+		.start	= 0x4a00233c,
+		.end	= 0x4a00233f,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap4_control_usb = {
+	.name = "omap-control-usb",
+	.id = -1,
+	.dev = {
+		.platform_data = &omap4_control_usb_pdata,
+	},
+	.num_resources = 2,
+	.resource = omap4_control_usb_res,
+};
+
+static inline void __init omap_init_control_usb(void)
+{
+	if (!cpu_is_omap44xx())
+		return;
+
+	if (platform_device_register(&omap4_control_usb))
+		pr_err("Error registering omap_control_usb device\n");
+}
+
+#else
+static inline void omap_init_control_usb(void) { }
+#endif /* CONFIG_OMAP_CONTROL_USB */
+
 int __init omap4_keyboard_init(struct omap4_keypad_platform_data
 int __init omap4_keyboard_init(struct omap4_keypad_platform_data
 			*sdp4430_keypad_data, struct omap_board_data *bdata)
 			*sdp4430_keypad_data, struct omap_board_data *bdata)
 {
 {
@@ -721,6 +765,7 @@ static int __init omap2_init_devices(void)
 	omap_init_mbox();
 	omap_init_mbox();
 	/* If dtb is there, the devices will be created dynamically */
 	/* If dtb is there, the devices will be created dynamically */
 	if (!of_have_populated_dt()) {
 	if (!of_have_populated_dt()) {
+		omap_init_control_usb();
 		omap_init_dmic();
 		omap_init_dmic();
 		omap_init_mcpdm();
 		omap_init_mcpdm();
 		omap_init_mcspi();
 		omap_init_mcspi();

+ 0 - 13
arch/arm/mach-omap2/omap_hwmod_44xx_data.c

@@ -2702,13 +2702,6 @@ static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
 		.end		= 0x4a0ae000,
 		.end		= 0x4a0ae000,
 		.flags		= IORESOURCE_MEM,
 		.flags		= IORESOURCE_MEM,
 	},
 	},
-	{
-		/* XXX: Remove this once control module driver is in place */
-		.name		= "ctrl_dev",
-		.start		= 0x4a002300,
-		.end		= 0x4a002303,
-		.flags		= IORESOURCE_MEM,
-	},
 	{ }
 	{ }
 };
 };
 
 
@@ -6156,12 +6149,6 @@ static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
 		.pa_end		= 0x4a0ab7ff,
 		.pa_end		= 0x4a0ab7ff,
 		.flags		= ADDR_TYPE_RT
 		.flags		= ADDR_TYPE_RT
 	},
 	},
-	{
-		/* XXX: Remove this once control module driver is in place */
-		.pa_start	= 0x4a00233c,
-		.pa_end		= 0x4a00233f,
-		.flags		= ADDR_TYPE_RT
-	},
 	{ }
 	{ }
 };
 };
 
 

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

@@ -85,6 +85,9 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
 	musb_plat.mode = board_data->mode;
 	musb_plat.mode = board_data->mode;
 	musb_plat.extvbus = board_data->extvbus;
 	musb_plat.extvbus = board_data->extvbus;
 
 
+	if (cpu_is_omap44xx())
+		musb_plat.has_mailbox = true;
+
 	if (soc_is_am35xx()) {
 	if (soc_is_am35xx()) {
 		oh_name = "am35x_otg_hs";
 		oh_name = "am35x_otg_hs";
 		name = "musb-am35x";
 		name = "musb-am35x";

+ 1 - 0
drivers/base/power/qos.c

@@ -91,6 +91,7 @@ enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
 
 
 	return ret;
 	return ret;
 }
 }
+EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
 
 
 /**
 /**
  * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
  * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.

+ 1 - 1
drivers/usb/c67x00/c67x00-ll-hpi.c

@@ -237,7 +237,7 @@ void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* Transactions */
 /* Transactions */
 
 
-static inline u16 ll_recv_msg(struct c67x00_device *dev)
+static inline int ll_recv_msg(struct c67x00_device *dev)
 {
 {
 	u16 res;
 	u16 res;
 
 

+ 1 - 1
drivers/usb/chipidea/ci13xxx_imx.h

@@ -19,7 +19,7 @@ struct usbmisc_usb_device {
 	struct device *dev; /* usb controller device */
 	struct device *dev; /* usb controller device */
 	int index;
 	int index;
 
 
-	int disable_oc:1; /* over current detect disabled */
+	unsigned int disable_oc:1; /* over current detect disabled */
 };
 };
 
 
 int usbmisc_set_ops(const struct usbmisc_ops *ops);
 int usbmisc_set_ops(const struct usbmisc_ops *ops);

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

@@ -411,7 +411,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	base = devm_request_and_ioremap(dev, res);
 	base = devm_request_and_ioremap(dev, res);
-	if (!res) {
+	if (!base) {
 		dev_err(dev, "can't request and ioremap resource\n");
 		dev_err(dev, "can't request and ioremap resource\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}

+ 1 - 0
drivers/usb/core/Makefile

@@ -7,6 +7,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
 usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
 usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
 usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
 usbcore-y += devio.o notify.o generic.o quirks.o devices.o
 usbcore-y += devio.o notify.o generic.o quirks.o devices.o
+usbcore-y += port.o
 
 
 usbcore-$(CONFIG_PCI)		+= hcd-pci.o
 usbcore-$(CONFIG_PCI)		+= hcd-pci.o
 usbcore-$(CONFIG_ACPI)		+= usb-acpi.o
 usbcore-$(CONFIG_ACPI)		+= usb-acpi.o

+ 10 - 3
drivers/usb/core/devices.c

@@ -316,17 +316,23 @@ static char *usb_dump_iad_descriptor(char *start, char *end,
  */
  */
 static char *usb_dump_config_descriptor(char *start, char *end,
 static char *usb_dump_config_descriptor(char *start, char *end,
 				const struct usb_config_descriptor *desc,
 				const struct usb_config_descriptor *desc,
-				int active)
+				int active, int speed)
 {
 {
+	int mul;
+
 	if (start > end)
 	if (start > end)
 		return start;
 		return start;
+	if (speed == USB_SPEED_SUPER)
+		mul = 8;
+	else
+		mul = 2;
 	start += sprintf(start, format_config,
 	start += sprintf(start, format_config,
 			 /* mark active/actual/current cfg. */
 			 /* mark active/actual/current cfg. */
 			 active ? '*' : ' ',
 			 active ? '*' : ' ',
 			 desc->bNumInterfaces,
 			 desc->bNumInterfaces,
 			 desc->bConfigurationValue,
 			 desc->bConfigurationValue,
 			 desc->bmAttributes,
 			 desc->bmAttributes,
-			 desc->bMaxPower * 2);
+			 desc->bMaxPower * mul);
 	return start;
 	return start;
 }
 }
 
 
@@ -342,7 +348,8 @@ static char *usb_dump_config(int speed, char *start, char *end,
 	if (!config)
 	if (!config)
 		/* getting these some in 2.3.7; none in 2.3.6 */
 		/* getting these some in 2.3.7; none in 2.3.6 */
 		return start + sprintf(start, "(null Cfg. desc.)\n");
 		return start + sprintf(start, "(null Cfg. desc.)\n");
-	start = usb_dump_config_descriptor(start, end, &config->desc, active);
+	start = usb_dump_config_descriptor(start, end, &config->desc, active,
+			speed);
 	for (i = 0; i < USB_MAXIADS; i++) {
 	for (i = 0; i < USB_MAXIADS; i++) {
 		if (config->intf_assoc[i] == NULL)
 		if (config->intf_assoc[i] == NULL)
 			break;
 			break;

+ 2 - 1
drivers/usb/core/devio.c

@@ -40,6 +40,7 @@
 #include <linux/signal.h>
 #include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/string.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usb/hcd.h>	/* for usbcore internals */
 #include <linux/usb/hcd.h>	/* for usbcore internals */
@@ -1077,7 +1078,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 	if (!intf || !intf->dev.driver)
 	if (!intf || !intf->dev.driver)
 		ret = -ENODATA;
 		ret = -ENODATA;
 	else {
 	else {
-		strncpy(gd.driver, intf->dev.driver->name,
+		strlcpy(gd.driver, intf->dev.driver->name,
 				sizeof(gd.driver));
 				sizeof(gd.driver));
 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
 	}
 	}

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

@@ -100,7 +100,7 @@ int usb_choose_configuration(struct usb_device *udev)
 		 */
 		 */
 
 
 		/* Rule out configs that draw too much bus current */
 		/* Rule out configs that draw too much bus current */
-		if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+		if (usb_get_max_power(udev, c) > udev->bus_mA) {
 			insufficient_power++;
 			insufficient_power++;
 			continue;
 			continue;
 		}
 		}

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

@@ -620,6 +620,10 @@ nongeneric:
 		status = hcd->driver->hub_control (hcd,
 		status = hcd->driver->hub_control (hcd,
 			typeReq, wValue, wIndex,
 			typeReq, wValue, wIndex,
 			tbuf, wLength);
 			tbuf, wLength);
+
+		if (typeReq == GetHubDescriptor)
+			usb_hub_adjust_deviceremovable(hcd->self.root_hub,
+				(struct usb_hub_descriptor *)tbuf);
 		break;
 		break;
 error:
 error:
 		/* "protocol stall" on error */
 		/* "protocol stall" on error */
@@ -2550,7 +2554,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	}
 	}
 
 
 	/* starting here, usbcore will pay attention to this root hub */
 	/* starting here, usbcore will pay attention to this root hub */
-	rhdev->bus_mA = min(500u, hcd->power_budget);
 	if ((retval = register_root_hub(hcd)) != 0)
 	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 		goto err_register_root_hub;
 
 

+ 344 - 272
drivers/usb/core/hub.c

@@ -26,11 +26,12 @@
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <linux/freezer.h>
 #include <linux/random.h>
 #include <linux/random.h>
+#include <linux/pm_qos.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 
 
-#include "usb.h"
+#include "hub.h"
 
 
 /* if we are in debug mode, always announce new devices */
 /* if we are in debug mode, always announce new devices */
 #ifdef DEBUG
 #ifdef DEBUG
@@ -42,62 +43,6 @@
 #define USB_VENDOR_GENESYS_LOGIC		0x05e3
 #define USB_VENDOR_GENESYS_LOGIC		0x05e3
 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01
 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01
 
 
-struct usb_port {
-	struct usb_device *child;
-	struct device dev;
-	struct dev_state *port_owner;
-	enum usb_port_connect_type connect_type;
-};
-
-struct usb_hub {
-	struct device		*intfdev;	/* the "interface" device */
-	struct usb_device	*hdev;
-	struct kref		kref;
-	struct urb		*urb;		/* for interrupt polling pipe */
-
-	/* buffer for urb ... with extra space in case of babble */
-	char			(*buffer)[8];
-	union {
-		struct usb_hub_status	hub;
-		struct usb_port_status	port;
-	}			*status;	/* buffer for status reports */
-	struct mutex		status_mutex;	/* for the status buffer */
-
-	int			error;		/* last reported error */
-	int			nerrors;	/* track consecutive errors */
-
-	struct list_head	event_list;	/* hubs w/data or errs ready */
-	unsigned long		event_bits[1];	/* status change bitmask */
-	unsigned long		change_bits[1];	/* ports with logical connect
-							status change */
-	unsigned long		busy_bits[1];	/* ports being reset or
-							resumed */
-	unsigned long		removed_bits[1]; /* ports with a "removed"
-							device present */
-	unsigned long		wakeup_bits[1];	/* ports that have signaled
-							remote wakeup */
-#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
-#error event_bits[] is too short!
-#endif
-
-	struct usb_hub_descriptor *descriptor;	/* class descriptor */
-	struct usb_tt		tt;		/* Transaction Translator */
-
-	unsigned		mA_per_port;	/* current for each child */
-
-	unsigned		limited_power:1;
-	unsigned		quiescing:1;
-	unsigned		disconnected:1;
-
-	unsigned		quirk_check_port_auto_suspend:1;
-
-	unsigned		has_indicators:1;
-	u8			indicator[USB_MAXCHILDREN];
-	struct delayed_work	leds;
-	struct delayed_work	init_work;
-	struct usb_port		**ports;
-};
-
 static inline int hub_is_superspeed(struct usb_device *hdev)
 static inline int hub_is_superspeed(struct usb_device *hdev)
 {
 {
 	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
 	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
@@ -164,13 +109,10 @@ MODULE_PARM_DESC(use_both_schemes,
 DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
 DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
 EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
 EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
 
 
-#define HUB_DEBOUNCE_TIMEOUT	1500
+#define HUB_DEBOUNCE_TIMEOUT	2000
 #define HUB_DEBOUNCE_STEP	  25
 #define HUB_DEBOUNCE_STEP	  25
 #define HUB_DEBOUNCE_STABLE	 100
 #define HUB_DEBOUNCE_STABLE	 100
 
 
-#define to_usb_port(_dev) \
-	container_of(_dev, struct usb_port, dev)
-
 static int usb_reset_and_verify_device(struct usb_device *udev);
 static int usb_reset_and_verify_device(struct usb_device *udev);
 
 
 static inline char *portspeed(struct usb_hub *hub, int portstatus)
 static inline char *portspeed(struct usb_hub *hub, int portstatus)
@@ -186,7 +128,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)
 }
 }
 
 
 /* Note that hdev or one of its children must be locked! */
 /* Note that hdev or one of its children must be locked! */
-static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
+struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
 {
 {
 	if (!hdev || !hdev->actconfig || !hdev->maxchild)
 	if (!hdev || !hdev->actconfig || !hdev->maxchild)
 		return NULL;
 		return NULL;
@@ -360,7 +302,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
 	if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
 	if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
 		return;
 		return;
 
 
-	hub = hdev_to_hub(udev->parent);
+	hub = usb_hub_to_struct_hub(udev->parent);
 	/* It doesn't take time to transition the roothub into U0, since it
 	/* It doesn't take time to transition the roothub into U0, since it
 	 * doesn't have an upstream link.
 	 * doesn't have an upstream link.
 	 */
 	 */
@@ -452,7 +394,7 @@ static int clear_hub_feature(struct usb_device *hdev, int feature)
 /*
 /*
  * USB 2.0 spec Section 11.24.2.2
  * USB 2.0 spec Section 11.24.2.2
  */
  */
-static int clear_port_feature(struct usb_device *hdev, int port1, int feature)
+int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature)
 {
 {
 	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 	return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
 		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
@@ -645,7 +587,7 @@ static void kick_khubd(struct usb_hub *hub)
 
 
 void usb_kick_khubd(struct usb_device *hdev)
 void usb_kick_khubd(struct usb_device *hdev)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	if (hub)
 	if (hub)
 		kick_khubd(hub);
 		kick_khubd(hub);
@@ -667,7 +609,7 @@ void usb_wakeup_notification(struct usb_device *hdev,
 	if (!hdev)
 	if (!hdev)
 		return;
 		return;
 
 
-	hub = hdev_to_hub(hdev);
+	hub = usb_hub_to_struct_hub(hdev);
 	if (hub) {
 	if (hub) {
 		set_bit(portnum, hub->wakeup_bits);
 		set_bit(portnum, hub->wakeup_bits);
 		kick_khubd(hub);
 		kick_khubd(hub);
@@ -773,6 +715,32 @@ static void hub_tt_work(struct work_struct *work)
 	spin_unlock_irqrestore (&hub->tt.lock, flags);
 	spin_unlock_irqrestore (&hub->tt.lock, flags);
 }
 }
 
 
+/**
+ * usb_hub_set_port_power - control hub port's power state
+ * @hdev: target hub
+ * @port1: port index
+ * @set: expected status
+ *
+ * call this function to control port's power via setting or
+ * clearing the port's PORT_POWER feature.
+ */
+int usb_hub_set_port_power(struct usb_device *hdev, int port1,
+		bool set)
+{
+	int ret;
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+	struct usb_port *port_dev = hub->ports[port1 - 1];
+
+	if (set)
+		ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+	else
+		ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+
+	if (!ret)
+		port_dev->power_is_on = set;
+	return ret;
+}
+
 /**
 /**
  * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
  * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
  * @urb: an URB associated with the failed or incomplete split transaction
  * @urb: an URB associated with the failed or incomplete split transaction
@@ -849,7 +817,11 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
 		dev_dbg(hub->intfdev, "trying to enable port power on "
 		dev_dbg(hub->intfdev, "trying to enable port power on "
 				"non-switchable hub\n");
 				"non-switchable hub\n");
 	for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
 	for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
-		set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+		if (hub->ports[port1 - 1]->power_is_on)
+			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+		else
+			usb_clear_port_feature(hub->hdev, port1,
+						USB_PORT_FEAT_POWER);
 
 
 	/* Wait at least 100 msec for power to become stable */
 	/* Wait at least 100 msec for power to become stable */
 	delay = max(pgood_delay, (unsigned) 100);
 	delay = max(pgood_delay, (unsigned) 100);
@@ -943,7 +915,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
 		if (hub_is_superspeed(hub->hdev))
 		if (hub_is_superspeed(hub->hdev))
 			ret = hub_usb3_port_disable(hub, port1);
 			ret = hub_usb3_port_disable(hub, port1);
 		else
 		else
-			ret = clear_port_feature(hdev, port1,
+			ret = usb_clear_port_feature(hdev, port1,
 					USB_PORT_FEAT_ENABLE);
 					USB_PORT_FEAT_ENABLE);
 	}
 	}
 	if (ret)
 	if (ret)
@@ -992,7 +964,7 @@ int usb_remove_device(struct usb_device *udev)
 
 
 	if (!udev->parent)	/* Can't remove a root hub */
 	if (!udev->parent)	/* Can't remove a root hub */
 		return -EINVAL;
 		return -EINVAL;
-	hub = hdev_to_hub(udev->parent);
+	hub = usb_hub_to_struct_hub(udev->parent);
 	intf = to_usb_interface(hub->intfdev);
 	intf = to_usb_interface(hub->intfdev);
 
 
 	usb_autopm_get_interface(intf);
 	usb_autopm_get_interface(intf);
@@ -1124,7 +1096,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 			 * Do not disable USB3 protocol ports.
 			 * Do not disable USB3 protocol ports.
 			 */
 			 */
 			if (!hub_is_superspeed(hdev)) {
 			if (!hub_is_superspeed(hdev)) {
-				clear_port_feature(hdev, port1,
+				usb_clear_port_feature(hdev, port1,
 						   USB_PORT_FEAT_ENABLE);
 						   USB_PORT_FEAT_ENABLE);
 				portstatus &= ~USB_PORT_STAT_ENABLE;
 				portstatus &= ~USB_PORT_STAT_ENABLE;
 			} else {
 			} else {
@@ -1136,18 +1108,18 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 		/* Clear status-change flags; we'll debounce later */
 		/* Clear status-change flags; we'll debounce later */
 		if (portchange & USB_PORT_STAT_C_CONNECTION) {
 		if (portchange & USB_PORT_STAT_C_CONNECTION) {
 			need_debounce_delay = true;
 			need_debounce_delay = true;
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_CONNECTION);
 					USB_PORT_FEAT_C_CONNECTION);
 		}
 		}
 		if (portchange & USB_PORT_STAT_C_ENABLE) {
 		if (portchange & USB_PORT_STAT_C_ENABLE) {
 			need_debounce_delay = true;
 			need_debounce_delay = true;
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_ENABLE);
 					USB_PORT_FEAT_C_ENABLE);
 		}
 		}
 		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
 		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
 				hub_is_superspeed(hub->hdev)) {
 				hub_is_superspeed(hub->hdev)) {
 			need_debounce_delay = true;
 			need_debounce_delay = true;
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 		}
 		}
 		/* We can forget about a "removed" device when there's a
 		/* We can forget about a "removed" device when there's a
@@ -1181,10 +1153,16 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 				set_bit(port1, hub->change_bits);
 				set_bit(port1, hub->change_bits);
 
 
 		} else if (udev->persist_enabled) {
 		} else if (udev->persist_enabled) {
+			struct usb_port *port_dev = hub->ports[port1 - 1];
+
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 			udev->reset_resume = 1;
 			udev->reset_resume = 1;
 #endif
 #endif
-			set_bit(port1, hub->change_bits);
+			/* Don't set the change_bits when the device
+			 * was powered off.
+			 */
+			if (port_dev->power_is_on)
+				set_bit(port1, hub->change_bits);
 
 
 		} else {
 		} else {
 			/* The power session is gone; tell khubd */
 			/* The power session is gone; tell khubd */
@@ -1294,52 +1272,6 @@ static int hub_post_reset(struct usb_interface *intf)
 	return 0;
 	return 0;
 }
 }
 
 
-static void usb_port_device_release(struct device *dev)
-{
-	struct usb_port *port_dev = to_usb_port(dev);
-
-	kfree(port_dev);
-}
-
-static void usb_hub_remove_port_device(struct usb_hub *hub,
-				       int port1)
-{
-	device_unregister(&hub->ports[port1 - 1]->dev);
-}
-
-struct device_type usb_port_device_type = {
-	.name =		"usb_port",
-	.release =	usb_port_device_release,
-};
-
-static int usb_hub_create_port_device(struct usb_hub *hub,
-				      int port1)
-{
-	struct usb_port *port_dev = NULL;
-	int retval;
-
-	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
-	if (!port_dev) {
-		retval = -ENOMEM;
-		goto exit;
-	}
-
-	hub->ports[port1 - 1] = port_dev;
-	port_dev->dev.parent = hub->intfdev;
-	port_dev->dev.type = &usb_port_device_type;
-	dev_set_name(&port_dev->dev, "port%d", port1);
-
-	retval = device_register(&port_dev->dev);
-	if (retval)
-		goto error_register;
-	return 0;
-
-error_register:
-	put_device(&port_dev->dev);
-exit:
-	return retval;
-}
-
 static int hub_configure(struct usb_hub *hub,
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 	struct usb_endpoint_descriptor *endpoint)
 {
 {
@@ -1351,6 +1283,8 @@ static int hub_configure(struct usb_hub *hub,
 	unsigned int pipe;
 	unsigned int pipe;
 	int maxp, ret, i;
 	int maxp, ret, i;
 	char *message = "out of memory";
 	char *message = "out of memory";
+	unsigned unit_load;
+	unsigned full_load;
 
 
 	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
 	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
 	if (!hub->buffer) {
 	if (!hub->buffer) {
@@ -1397,6 +1331,13 @@ static int hub_configure(struct usb_hub *hub,
 	}
 	}
 
 
 	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+	if (hub_is_superspeed(hdev)) {
+		unit_load = 150;
+		full_load = 900;
+	} else {
+		unit_load = 100;
+		full_load = 500;
+	}
 
 
 	/* FIXME for USB 3.0, skip for now */
 	/* FIXME for USB 3.0, skip for now */
 	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
 	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
@@ -1516,40 +1457,44 @@ static int hub_configure(struct usb_hub *hub,
 		goto fail;
 		goto fail;
 	}
 	}
 	le16_to_cpus(&hubstatus);
 	le16_to_cpus(&hubstatus);
+	hcd = bus_to_hcd(hdev->bus);
 	if (hdev == hdev->bus->root_hub) {
 	if (hdev == hdev->bus->root_hub) {
-		if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
-			hub->mA_per_port = 500;
+		if (hcd->power_budget > 0)
+			hdev->bus_mA = hcd->power_budget;
+		else
+			hdev->bus_mA = full_load * hdev->maxchild;
+		if (hdev->bus_mA >= full_load)
+			hub->mA_per_port = full_load;
 		else {
 		else {
 			hub->mA_per_port = hdev->bus_mA;
 			hub->mA_per_port = hdev->bus_mA;
 			hub->limited_power = 1;
 			hub->limited_power = 1;
 		}
 		}
 	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
 	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+		int remaining = hdev->bus_mA -
+			hub->descriptor->bHubContrCurrent;
+
 		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
 		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
 			hub->descriptor->bHubContrCurrent);
 			hub->descriptor->bHubContrCurrent);
 		hub->limited_power = 1;
 		hub->limited_power = 1;
-		if (hdev->maxchild > 0) {
-			int remaining = hdev->bus_mA -
-					hub->descriptor->bHubContrCurrent;
 
 
-			if (remaining < hdev->maxchild * 100)
-				dev_warn(hub_dev,
+		if (remaining < hdev->maxchild * unit_load)
+			dev_warn(hub_dev,
 					"insufficient power available "
 					"insufficient power available "
 					"to use all downstream ports\n");
 					"to use all downstream ports\n");
-			hub->mA_per_port = 100;		/* 7.2.1.1 */
-		}
+		hub->mA_per_port = unit_load;	/* 7.2.1 */
+
 	} else {	/* Self-powered external hub */
 	} else {	/* Self-powered external hub */
 		/* FIXME: What about battery-powered external hubs that
 		/* FIXME: What about battery-powered external hubs that
 		 * provide less current per port? */
 		 * provide less current per port? */
-		hub->mA_per_port = 500;
+		hub->mA_per_port = full_load;
 	}
 	}
-	if (hub->mA_per_port < 500)
+	if (hub->mA_per_port < full_load)
 		dev_dbg(hub_dev, "%umA bus power budget for each child\n",
 		dev_dbg(hub_dev, "%umA bus power budget for each child\n",
 				hub->mA_per_port);
 				hub->mA_per_port);
 
 
 	/* Update the HCD's internal representation of this hub before khubd
 	/* Update the HCD's internal representation of this hub before khubd
 	 * starts getting port status changes for devices under the hub.
 	 * starts getting port status changes for devices under the hub.
 	 */
 	 */
-	hcd = bus_to_hcd(hdev->bus);
 	if (hcd->driver->update_hub_device) {
 	if (hcd->driver->update_hub_device) {
 		ret = hcd->driver->update_hub_device(hcd, hdev,
 		ret = hcd->driver->update_hub_device(hcd, hdev,
 				&hub->tt, GFP_KERNEL);
 				&hub->tt, GFP_KERNEL);
@@ -1605,6 +1550,8 @@ static int hub_configure(struct usb_hub *hub,
 			dev_err(hub->intfdev,
 			dev_err(hub->intfdev,
 				"couldn't create port%d device.\n", i + 1);
 				"couldn't create port%d device.\n", i + 1);
 
 
+	usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
+
 	hub_activate(hub, HUB_INIT);
 	hub_activate(hub, HUB_INIT);
 	return 0;
 	return 0;
 
 
@@ -1659,6 +1606,7 @@ static void hub_disconnect(struct usb_interface *intf)
 	kfree(hub->status);
 	kfree(hub->status);
 	kfree(hub->buffer);
 	kfree(hub->buffer);
 
 
+	pm_suspend_ignore_children(&intf->dev, false);
 	kref_put(&hub->kref, hub_release);
 	kref_put(&hub->kref, hub_release);
 }
 }
 
 
@@ -1761,6 +1709,7 @@ descriptor_error:
 
 
 	usb_set_intfdata (intf, hub);
 	usb_set_intfdata (intf, hub);
 	intf->needs_remote_wakeup = 1;
 	intf->needs_remote_wakeup = 1;
+	pm_suspend_ignore_children(&intf->dev, true);
 
 
 	if (hdev->speed == USB_SPEED_HIGH)
 	if (hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs++;
 		highspeed_hubs++;
@@ -1779,7 +1728,7 @@ static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
 {
 	struct usb_device *hdev = interface_to_usbdev (intf);
 	struct usb_device *hdev = interface_to_usbdev (intf);
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	/* assert ifno == 0 (part of hub spec) */
 	/* assert ifno == 0 (part of hub spec) */
 	switch (code) {
 	switch (code) {
@@ -1825,7 +1774,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
 	/* This assumes that devices not managed by the hub driver
 	/* This assumes that devices not managed by the hub driver
 	 * will always have maxchild equal to 0.
 	 * will always have maxchild equal to 0.
 	 */
 	 */
-	*ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner);
+	*ppowner = &(usb_hub_to_struct_hub(hdev)->ports[port1 - 1]->port_owner);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1862,7 +1811,7 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
 
 
 void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
 void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 	int n;
 	int n;
 
 
 	for (n = 0; n < hdev->maxchild; n++) {
 	for (n = 0; n < hdev->maxchild; n++) {
@@ -1879,13 +1828,13 @@ bool usb_device_is_owned(struct usb_device *udev)
 
 
 	if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
 	if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
 		return false;
 		return false;
-	hub = hdev_to_hub(udev->parent);
+	hub = usb_hub_to_struct_hub(udev->parent);
 	return !!hub->ports[udev->portnum - 1]->port_owner;
 	return !!hub->ports[udev->portnum - 1]->port_owner;
 }
 }
 
 
 static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(udev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(udev);
 	int i;
 	int i;
 
 
 	for (i = 0; i < udev->maxchild; ++i) {
 	for (i = 0; i < udev->maxchild; ++i) {
@@ -2054,7 +2003,7 @@ static void hub_free_dev(struct usb_device *udev)
 void usb_disconnect(struct usb_device **pdev)
 void usb_disconnect(struct usb_device **pdev)
 {
 {
 	struct usb_device	*udev = *pdev;
 	struct usb_device	*udev = *pdev;
-	struct usb_hub		*hub = hdev_to_hub(udev);
+	struct usb_hub		*hub = usb_hub_to_struct_hub(udev);
 	int			i;
 	int			i;
 
 
 	/* mark the device as inactive, so any further urb submissions for
 	/* mark the device as inactive, so any further urb submissions for
@@ -2081,6 +2030,19 @@ void usb_disconnect(struct usb_device **pdev)
 	usb_disable_device(udev, 0);
 	usb_disable_device(udev, 0);
 	usb_hcd_synchronize_unlinks(udev);
 	usb_hcd_synchronize_unlinks(udev);
 
 
+	if (udev->parent) {
+		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+		struct usb_port	*port_dev = hub->ports[udev->portnum - 1];
+
+		sysfs_remove_link(&udev->dev.kobj, "port");
+		sysfs_remove_link(&port_dev->dev.kobj, "device");
+
+		if (!port_dev->did_runtime_put)
+			pm_runtime_put(&port_dev->dev);
+		else
+			port_dev->did_runtime_put = false;
+	}
+
 	usb_remove_ep_devs(&udev->ep0);
 	usb_remove_ep_devs(&udev->ep0);
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 
 
@@ -2267,7 +2229,7 @@ static void set_usb_port_removable(struct usb_device *udev)
 	if (!hdev)
 	if (!hdev)
 		return;
 		return;
 
 
-	hub = hdev_to_hub(udev->parent);
+	hub = usb_hub_to_struct_hub(udev->parent);
 
 
 	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 
 
@@ -2373,6 +2335,26 @@ int usb_new_device(struct usb_device *udev)
 		goto fail;
 		goto fail;
 	}
 	}
 
 
+	/* Create link files between child device and usb port device. */
+	if (udev->parent) {
+		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+		struct usb_port	*port_dev = hub->ports[udev->portnum - 1];
+
+		err = sysfs_create_link(&udev->dev.kobj,
+				&port_dev->dev.kobj, "port");
+		if (err)
+			goto fail;
+
+		err = sysfs_create_link(&port_dev->dev.kobj,
+				&udev->dev.kobj, "device");
+		if (err) {
+			sysfs_remove_link(&udev->dev.kobj, "port");
+			goto fail;
+		}
+
+		pm_runtime_get_sync(&port_dev->dev);
+	}
+
 	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
 	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
 	usb_mark_last_busy(udev);
 	usb_mark_last_busy(udev);
 	pm_runtime_put_sync_autosuspend(&udev->dev);
 	pm_runtime_put_sync_autosuspend(&udev->dev);
@@ -2535,77 +2517,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 			return ret;
 			return ret;
 
 
 		/* The port state is unknown until the reset completes. */
 		/* The port state is unknown until the reset completes. */
-		if ((portstatus & USB_PORT_STAT_RESET))
-			goto delay;
-
-		/*
-		 * Some buggy devices require a warm reset to be issued even
-		 * when the port appears not to be connected.
-		 */
-		if (!warm) {
-			/*
-			 * Some buggy devices can cause an NEC host controller
-			 * to transition to the "Error" state after a hot port
-			 * reset.  This will show up as the port state in
-			 * "Inactive", and the port may also report a
-			 * disconnect.  Forcing a warm port reset seems to make
-			 * the device work.
-			 *
-			 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
-			 */
-			if (hub_port_warm_reset_required(hub, portstatus)) {
-				int ret;
-
-				if ((portchange & USB_PORT_STAT_C_CONNECTION))
-					clear_port_feature(hub->hdev, port1,
-							USB_PORT_FEAT_C_CONNECTION);
-				if (portchange & USB_PORT_STAT_C_LINK_STATE)
-					clear_port_feature(hub->hdev, port1,
-							USB_PORT_FEAT_C_PORT_LINK_STATE);
-				if (portchange & USB_PORT_STAT_C_RESET)
-					clear_port_feature(hub->hdev, port1,
-							USB_PORT_FEAT_C_RESET);
-				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
-						port1);
-				ret = hub_port_reset(hub, port1,
-						udev, HUB_BH_RESET_TIME,
-						true);
-				if ((portchange & USB_PORT_STAT_C_CONNECTION))
-					clear_port_feature(hub->hdev, port1,
-							USB_PORT_FEAT_C_CONNECTION);
-				return ret;
-			}
-			/* Device went away? */
-			if (!(portstatus & USB_PORT_STAT_CONNECTION))
-				return -ENOTCONN;
-
-			/* bomb out completely if the connection bounced */
-			if ((portchange & USB_PORT_STAT_C_CONNECTION))
-				return -ENOTCONN;
-
-			if ((portstatus & USB_PORT_STAT_ENABLE)) {
-				if (hub_is_wusb(hub))
-					udev->speed = USB_SPEED_WIRELESS;
-				else if (hub_is_superspeed(hub->hdev))
-					udev->speed = USB_SPEED_SUPER;
-				else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
-					udev->speed = USB_SPEED_HIGH;
-				else if (portstatus & USB_PORT_STAT_LOW_SPEED)
-					udev->speed = USB_SPEED_LOW;
-				else
-					udev->speed = USB_SPEED_FULL;
-				return 0;
-			}
-		} else {
-			if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
-					hub_port_warm_reset_required(hub,
-						portstatus))
-				return -ENOTCONN;
-
-			return 0;
-		}
+		if (!(portstatus & USB_PORT_STAT_RESET))
+			break;
 
 
-delay:
 		/* switch to the long delay after two short delay failures */
 		/* switch to the long delay after two short delay failures */
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 			delay = HUB_LONG_RESET_TIME;
 			delay = HUB_LONG_RESET_TIME;
@@ -2615,20 +2529,54 @@ delay:
 			port1, warm ? "warm " : "", delay);
 			port1, warm ? "warm " : "", delay);
 	}
 	}
 
 
-	return -EBUSY;
+	if ((portstatus & USB_PORT_STAT_RESET))
+		return -EBUSY;
+
+	if (hub_port_warm_reset_required(hub, portstatus))
+		return -ENOTCONN;
+
+	/* Device went away? */
+	if (!(portstatus & USB_PORT_STAT_CONNECTION))
+		return -ENOTCONN;
+
+	/* bomb out completely if the connection bounced.  A USB 3.0
+	 * connection may bounce if multiple warm resets were issued,
+	 * but the device may have successfully re-connected. Ignore it.
+	 */
+	if (!hub_is_superspeed(hub->hdev) &&
+			(portchange & USB_PORT_STAT_C_CONNECTION))
+		return -ENOTCONN;
+
+	if (!(portstatus & USB_PORT_STAT_ENABLE))
+		return -EBUSY;
+
+	if (!udev)
+		return 0;
+
+	if (hub_is_wusb(hub))
+		udev->speed = USB_SPEED_WIRELESS;
+	else if (hub_is_superspeed(hub->hdev))
+		udev->speed = USB_SPEED_SUPER;
+	else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+		udev->speed = USB_SPEED_HIGH;
+	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+		udev->speed = USB_SPEED_LOW;
+	else
+		udev->speed = USB_SPEED_FULL;
+	return 0;
 }
 }
 
 
 static void hub_port_finish_reset(struct usb_hub *hub, int port1,
 static void hub_port_finish_reset(struct usb_hub *hub, int port1,
-			struct usb_device *udev, int *status, bool warm)
+			struct usb_device *udev, int *status)
 {
 {
 	switch (*status) {
 	switch (*status) {
 	case 0:
 	case 0:
-		if (!warm) {
-			struct usb_hcd *hcd;
-			/* TRSTRCY = 10 ms; plus some extra */
-			msleep(10 + 40);
+		/* TRSTRCY = 10 ms; plus some extra */
+		msleep(10 + 40);
+		if (udev) {
+			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
 			update_devnum(udev, 0);
 			update_devnum(udev, 0);
-			hcd = bus_to_hcd(udev->bus);
 			/* The xHC may think the device is already reset,
 			/* The xHC may think the device is already reset,
 			 * so ignore the status.
 			 * so ignore the status.
 			 */
 			 */
@@ -2638,16 +2586,17 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
 		/* FALL THROUGH */
 		/* FALL THROUGH */
 	case -ENOTCONN:
 	case -ENOTCONN:
 	case -ENODEV:
 	case -ENODEV:
-		clear_port_feature(hub->hdev,
+		usb_clear_port_feature(hub->hdev,
 				port1, USB_PORT_FEAT_C_RESET);
 				port1, USB_PORT_FEAT_C_RESET);
-		/* FIXME need disconnect() for NOTATTACHED device */
 		if (hub_is_superspeed(hub->hdev)) {
 		if (hub_is_superspeed(hub->hdev)) {
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 					USB_PORT_FEAT_C_BH_PORT_RESET);
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
+			usb_clear_port_feature(hub->hdev, port1,
+					USB_PORT_FEAT_C_CONNECTION);
 		}
 		}
-		if (!warm)
+		if (udev)
 			usb_set_device_state(udev, *status
 			usb_set_device_state(udev, *status
 					? USB_STATE_NOTATTACHED
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT);
 					: USB_STATE_DEFAULT);
@@ -2660,18 +2609,30 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 			struct usb_device *udev, unsigned int delay, bool warm)
 			struct usb_device *udev, unsigned int delay, bool warm)
 {
 {
 	int i, status;
 	int i, status;
+	u16 portchange, portstatus;
 
 
-	if (!warm) {
-		/* Block EHCI CF initialization during the port reset.
-		 * Some companion controllers don't like it when they mix.
-		 */
-		down_read(&ehci_cf_port_reset_rwsem);
-	} else {
-		if (!hub_is_superspeed(hub->hdev)) {
+	if (!hub_is_superspeed(hub->hdev)) {
+		if (warm) {
 			dev_err(hub->intfdev, "only USB3 hub support "
 			dev_err(hub->intfdev, "only USB3 hub support "
 						"warm reset\n");
 						"warm reset\n");
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
+		/* Block EHCI CF initialization during the port reset.
+		 * Some companion controllers don't like it when they mix.
+		 */
+		down_read(&ehci_cf_port_reset_rwsem);
+	} else if (!warm) {
+		/*
+		 * If the caller hasn't explicitly requested a warm reset,
+		 * double check and see if one is needed.
+		 */
+		status = hub_port_status(hub, port1,
+					&portstatus, &portchange);
+		if (status < 0)
+			goto done;
+
+		if (hub_port_warm_reset_required(hub, portstatus))
+			warm = true;
 	}
 	}
 
 
 	/* Reset the port */
 	/* Reset the port */
@@ -2692,10 +2653,33 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 						status);
 						status);
 		}
 		}
 
 
-		/* return on disconnect or reset */
+		/* Check for disconnect or reset */
 		if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
 		if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
-			hub_port_finish_reset(hub, port1, udev, &status, warm);
-			goto done;
+			hub_port_finish_reset(hub, port1, udev, &status);
+
+			if (!hub_is_superspeed(hub->hdev))
+				goto done;
+
+			/*
+			 * If a USB 3.0 device migrates from reset to an error
+			 * state, re-issue the warm reset.
+			 */
+			if (hub_port_status(hub, port1,
+					&portstatus, &portchange) < 0)
+				goto done;
+
+			if (!hub_port_warm_reset_required(hub, portstatus))
+				goto done;
+
+			/*
+			 * If the port is in SS.Inactive or Compliance Mode, the
+			 * hot or warm reset failed.  Try another warm reset.
+			 */
+			if (!warm) {
+				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
+						port1);
+				warm = true;
+			}
 		}
 		}
 
 
 		dev_dbg (hub->intfdev,
 		dev_dbg (hub->intfdev,
@@ -2709,7 +2693,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		port1);
 		port1);
 
 
 done:
 done:
-	if (!warm)
+	if (!hub_is_superspeed(hub->hdev))
 		up_read(&ehci_cf_port_reset_rwsem);
 		up_read(&ehci_cf_port_reset_rwsem);
 
 
 	return status;
 	return status;
@@ -2783,10 +2767,10 @@ static int check_port_resume_type(struct usb_device *udev,
 
 
 		/* Late port handoff can set status-change bits */
 		/* Late port handoff can set status-change bits */
 		if (portchange & USB_PORT_STAT_C_CONNECTION)
 		if (portchange & USB_PORT_STAT_C_CONNECTION)
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_CONNECTION);
 					USB_PORT_FEAT_C_CONNECTION);
 		if (portchange & USB_PORT_STAT_C_ENABLE)
 		if (portchange & USB_PORT_STAT_C_ENABLE)
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_ENABLE);
 					USB_PORT_FEAT_C_ENABLE);
 	}
 	}
 
 
@@ -2904,7 +2888,9 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
  */
  */
 int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 {
 {
-	struct usb_hub	*hub = hdev_to_hub(udev->parent);
+	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
+	struct usb_port *port_dev = hub->ports[udev->portnum - 1];
+	enum pm_qos_flags_status pm_qos_stat;
 	int		port1 = udev->portnum;
 	int		port1 = udev->portnum;
 	int		status;
 	int		status;
 
 
@@ -2962,9 +2948,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 
 
 	/* see 7.1.7.6 */
 	/* see 7.1.7.6 */
 	if (hub_is_superspeed(hub->hdev))
 	if (hub_is_superspeed(hub->hdev))
-		status = set_port_feature(hub->hdev,
-				port1 | (USB_SS_PORT_LS_U3 << 3),
-				USB_PORT_FEAT_LINK_STATE);
+		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
 	else
 	else
 		status = set_port_feature(hub->hdev, port1,
 		status = set_port_feature(hub->hdev, port1,
 						USB_PORT_FEAT_SUSPEND);
 						USB_PORT_FEAT_SUSPEND);
@@ -3006,6 +2990,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		udev->port_is_suspended = 1;
 		udev->port_is_suspended = 1;
 		msleep(10);
 		msleep(10);
 	}
 	}
+
+	/*
+	 * Check whether current status meets the requirement of
+	 * usb port power off mechanism
+	 */
+	pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
+			PM_QOS_FLAG_NO_POWER_OFF);
+	if (!udev->do_remote_wakeup
+			&& pm_qos_stat != PM_QOS_FLAGS_ALL
+			&& udev->persist_enabled
+			&& !status) {
+		pm_runtime_put_sync(&port_dev->dev);
+		port_dev->did_runtime_put = true;
+	}
+
 	usb_mark_last_busy(hub->hdev);
 	usb_mark_last_busy(hub->hdev);
 	return status;
 	return status;
 }
 }
@@ -3141,11 +3140,22 @@ static int finish_port_resume(struct usb_device *udev)
  */
  */
 int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 {
 {
-	struct usb_hub	*hub = hdev_to_hub(udev->parent);
+	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
+	struct usb_port *port_dev = hub->ports[udev->portnum  - 1];
 	int		port1 = udev->portnum;
 	int		port1 = udev->portnum;
 	int		status;
 	int		status;
 	u16		portchange, portstatus;
 	u16		portchange, portstatus;
 
 
+	if (port_dev->did_runtime_put) {
+		status = pm_runtime_get_sync(&port_dev->dev);
+		port_dev->did_runtime_put = false;
+		if (status < 0) {
+			dev_dbg(&udev->dev, "can't resume usb port, status %d\n",
+					status);
+			return status;
+		}
+	}
+
 	/* Skip the initial Clear-Suspend step for a remote wakeup */
 	/* Skip the initial Clear-Suspend step for a remote wakeup */
 	status = hub_port_status(hub, port1, &portstatus, &portchange);
 	status = hub_port_status(hub, port1, &portstatus, &portchange);
 	if (status == 0 && !port_is_suspended(hub, portstatus))
 	if (status == 0 && !port_is_suspended(hub, portstatus))
@@ -3157,11 +3167,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 
 
 	/* see 7.1.7.7; affects power usage, but not budgeting */
 	/* see 7.1.7.7; affects power usage, but not budgeting */
 	if (hub_is_superspeed(hub->hdev))
 	if (hub_is_superspeed(hub->hdev))
-		status = set_port_feature(hub->hdev,
-				port1 | (USB_SS_PORT_LS_U0 << 3),
-				USB_PORT_FEAT_LINK_STATE);
+		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0);
 	else
 	else
-		status = clear_port_feature(hub->hdev,
+		status = usb_clear_port_feature(hub->hdev,
 				port1, USB_PORT_FEAT_SUSPEND);
 				port1, USB_PORT_FEAT_SUSPEND);
 	if (status) {
 	if (status) {
 		dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
 		dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
@@ -3187,11 +3195,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 		udev->port_is_suspended = 0;
 		udev->port_is_suspended = 0;
 		if (hub_is_superspeed(hub->hdev)) {
 		if (hub_is_superspeed(hub->hdev)) {
 			if (portchange & USB_PORT_STAT_C_LINK_STATE)
 			if (portchange & USB_PORT_STAT_C_LINK_STATE)
-				clear_port_feature(hub->hdev, port1,
+				usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
 					USB_PORT_FEAT_C_PORT_LINK_STATE);
 		} else {
 		} else {
 			if (portchange & USB_PORT_STAT_C_SUSPEND)
 			if (portchange & USB_PORT_STAT_C_SUSPEND)
-				clear_port_feature(hub->hdev, port1,
+				usb_clear_port_feature(hub->hdev, port1,
 						USB_PORT_FEAT_C_SUSPEND);
 						USB_PORT_FEAT_C_SUSPEND);
 		}
 		}
 	}
 	}
@@ -3247,7 +3255,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 
 
 int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 {
 {
-	struct usb_hub	*hub = hdev_to_hub(udev->parent);
+	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
 	int		port1 = udev->portnum;
 	int		port1 = udev->portnum;
 	int		status;
 	int		status;
 	u16		portchange, portstatus;
 	u16		portchange, portstatus;
@@ -3826,7 +3834,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm);
  * every 25ms for transient disconnects.  When the port status has been
  * every 25ms for transient disconnects.  When the port status has been
  * unchanged for 100ms it returns the port status.
  * unchanged for 100ms it returns the port status.
  */
  */
-static int hub_port_debounce(struct usb_hub *hub, int port1)
+int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)
 {
 {
 	int ret;
 	int ret;
 	int total_time, stable_time = 0;
 	int total_time, stable_time = 0;
@@ -3840,7 +3848,9 @@ static int hub_port_debounce(struct usb_hub *hub, int port1)
 
 
 		if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
 		if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
 		     (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
 		     (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
-			stable_time += HUB_DEBOUNCE_STEP;
+			if (!must_be_connected ||
+			     (connection == USB_PORT_STAT_CONNECTION))
+				stable_time += HUB_DEBOUNCE_STEP;
 			if (stable_time >= HUB_DEBOUNCE_STABLE)
 			if (stable_time >= HUB_DEBOUNCE_STABLE)
 				break;
 				break;
 		} else {
 		} else {
@@ -3849,7 +3859,7 @@ static int hub_port_debounce(struct usb_hub *hub, int port1)
 		}
 		}
 
 
 		if (portchange & USB_PORT_STAT_C_CONNECTION) {
 		if (portchange & USB_PORT_STAT_C_CONNECTION) {
-			clear_port_feature(hub->hdev, port1,
+			usb_clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_CONNECTION);
 					USB_PORT_FEAT_C_CONNECTION);
 		}
 		}
 
 
@@ -4246,16 +4256,23 @@ hub_power_remaining (struct usb_hub *hub)
 	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
 	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
 		struct usb_device	*udev = hub->ports[port1 - 1]->child;
 		struct usb_device	*udev = hub->ports[port1 - 1]->child;
 		int			delta;
 		int			delta;
+		unsigned		unit_load;
 
 
 		if (!udev)
 		if (!udev)
 			continue;
 			continue;
+		if (hub_is_superspeed(udev))
+			unit_load = 150;
+		else
+			unit_load = 100;
 
 
-		/* Unconfigured devices may not use more than 100mA,
-		 * or 8mA for OTG ports */
+		/*
+		 * Unconfigured devices may not use more than one unit load,
+		 * or 8mA for OTG ports
+		 */
 		if (udev->actconfig)
 		if (udev->actconfig)
-			delta = udev->actconfig->desc.bMaxPower * 2;
+			delta = usb_get_max_power(udev, udev->actconfig);
 		else if (port1 != udev->bus->otg_port || hdev->parent)
 		else if (port1 != udev->bus->otg_port || hdev->parent)
-			delta = 100;
+			delta = unit_load;
 		else
 		else
 			delta = 8;
 			delta = 8;
 		if (delta > hub->mA_per_port)
 		if (delta > hub->mA_per_port)
@@ -4290,6 +4307,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 			le16_to_cpu(hub->descriptor->wHubCharacteristics);
 			le16_to_cpu(hub->descriptor->wHubCharacteristics);
 	struct usb_device *udev;
 	struct usb_device *udev;
 	int status, i;
 	int status, i;
+	unsigned unit_load;
 
 
 	dev_dbg (hub_dev,
 	dev_dbg (hub_dev,
 		"port %d, status %04x, change %04x, %s\n",
 		"port %d, status %04x, change %04x, %s\n",
@@ -4353,7 +4371,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
 
 	if (portchange & (USB_PORT_STAT_C_CONNECTION |
 	if (portchange & (USB_PORT_STAT_C_CONNECTION |
 				USB_PORT_STAT_C_ENABLE)) {
 				USB_PORT_STAT_C_ENABLE)) {
-		status = hub_port_debounce(hub, port1);
+		status = hub_port_debounce_be_stable(hub, port1);
 		if (status < 0) {
 		if (status < 0) {
 			if (printk_ratelimit())
 			if (printk_ratelimit())
 				dev_err(hub_dev, "connect-debounce failed, "
 				dev_err(hub_dev, "connect-debounce failed, "
@@ -4379,6 +4397,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
   			goto done;
   			goto done;
 		return;
 		return;
 	}
 	}
+	if (hub_is_superspeed(hub->hdev))
+		unit_load = 150;
+	else
+		unit_load = 100;
 
 
 	for (i = 0; i < SET_CONFIG_TRIES; i++) {
 	for (i = 0; i < SET_CONFIG_TRIES; i++) {
 
 
@@ -4426,7 +4448,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 		 * on the parent.
 		 * on the parent.
 		 */
 		 */
 		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
 		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
-				&& udev->bus_mA <= 100) {
+				&& udev->bus_mA <= unit_load) {
 			u16	devstat;
 			u16	devstat;
 
 
 			status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
 			status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
@@ -4528,7 +4550,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
 	if (!hub_is_superspeed(hdev)) {
 	if (!hub_is_superspeed(hdev)) {
 		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
 		if (!(portchange & USB_PORT_STAT_C_SUSPEND))
 			return 0;
 			return 0;
-		clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
 	} else {
 	} else {
 		if (!udev || udev->state != USB_STATE_SUSPENDED ||
 		if (!udev || udev->state != USB_STATE_SUSPENDED ||
 				 (portstatus & USB_PORT_STAT_LINK_STATE) !=
 				 (portstatus & USB_PORT_STAT_LINK_STATE) !=
@@ -4656,7 +4678,7 @@ static void hub_events(void)
 				continue;
 				continue;
 
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				clear_port_feature(hdev, i,
+				usb_clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_CONNECTION);
 					USB_PORT_FEAT_C_CONNECTION);
 				connect_change = 1;
 				connect_change = 1;
 			}
 			}
@@ -4667,7 +4689,7 @@ static void hub_events(void)
 						"port %d enable change, "
 						"port %d enable change, "
 						"status %08x\n",
 						"status %08x\n",
 						i, portstatus);
 						i, portstatus);
-				clear_port_feature(hdev, i,
+				usb_clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_ENABLE);
 					USB_PORT_FEAT_C_ENABLE);
 
 
 				/*
 				/*
@@ -4698,7 +4720,7 @@ static void hub_events(void)
 
 
 				dev_dbg(hub_dev, "over-current change on port "
 				dev_dbg(hub_dev, "over-current change on port "
 					"%d\n", i);
 					"%d\n", i);
-				clear_port_feature(hdev, i,
+				usb_clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_OVER_CURRENT);
 					USB_PORT_FEAT_C_OVER_CURRENT);
 				msleep(100);	/* Cool down */
 				msleep(100);	/* Cool down */
 				hub_power_on(hub, true);
 				hub_power_on(hub, true);
@@ -4712,7 +4734,7 @@ static void hub_events(void)
 				dev_dbg (hub_dev,
 				dev_dbg (hub_dev,
 					"reset change on port %d\n",
 					"reset change on port %d\n",
 					i);
 					i);
-				clear_port_feature(hdev, i,
+				usb_clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_RESET);
 					USB_PORT_FEAT_C_RESET);
 			}
 			}
 			if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
 			if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
@@ -4720,18 +4742,18 @@ static void hub_events(void)
 				dev_dbg(hub_dev,
 				dev_dbg(hub_dev,
 					"warm reset change on port %d\n",
 					"warm reset change on port %d\n",
 					i);
 					i);
-				clear_port_feature(hdev, i,
+				usb_clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 			}
 			}
 			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
 			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
-				clear_port_feature(hub->hdev, i,
+				usb_clear_port_feature(hub->hdev, i,
 						USB_PORT_FEAT_C_PORT_LINK_STATE);
 						USB_PORT_FEAT_C_PORT_LINK_STATE);
 			}
 			}
 			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
 			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
 				dev_warn(hub_dev,
 				dev_warn(hub_dev,
 					"config error on port %d\n",
 					"config error on port %d\n",
 					i);
 					i);
-				clear_port_feature(hub->hdev, i,
+				usb_clear_port_feature(hub->hdev, i,
 						USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
 						USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
 			}
 			}
 
 
@@ -4740,12 +4762,21 @@ static void hub_events(void)
 			 */
 			 */
 			if (hub_port_warm_reset_required(hub, portstatus)) {
 			if (hub_port_warm_reset_required(hub, portstatus)) {
 				int status;
 				int status;
+				struct usb_device *udev =
+					hub->ports[i - 1]->child;
 
 
 				dev_dbg(hub_dev, "warm reset port %d\n", i);
 				dev_dbg(hub_dev, "warm reset port %d\n", i);
-				status = hub_port_reset(hub, i, NULL,
-						HUB_BH_RESET_TIME, true);
-				if (status < 0)
-					hub_port_disable(hub, i, 1);
+				if (!udev) {
+					status = hub_port_reset(hub, i,
+							NULL, HUB_BH_RESET_TIME,
+							true);
+					if (status < 0)
+						hub_port_disable(hub, i, 1);
+				} else {
+					usb_lock_device(udev);
+					status = usb_reset_device(udev);
+					usb_unlock_device(udev);
+				}
 				connect_change = 0;
 				connect_change = 0;
 			}
 			}
 
 
@@ -5006,7 +5037,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 		dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
 		dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
 		return -EISDIR;
 		return -EISDIR;
 	}
 	}
-	parent_hub = hdev_to_hub(parent_hdev);
+	parent_hub = usb_hub_to_struct_hub(parent_hdev);
 
 
 	/* Disable LPM and LTM while we reset the device and reinstall the alt
 	/* Disable LPM and LTM while we reset the device and reinstall the alt
 	 * settings.  Device-initiated LPM settings, and system exit latency
 	 * settings.  Device-initiated LPM settings, and system exit latency
@@ -5262,7 +5293,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device);
 struct usb_device *usb_hub_find_child(struct usb_device *hdev,
 struct usb_device *usb_hub_find_child(struct usb_device *hdev,
 		int port1)
 		int port1)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	if (port1 < 1 || port1 > hdev->maxchild)
 	if (port1 < 1 || port1 > hdev->maxchild)
 		return NULL;
 		return NULL;
@@ -5279,7 +5310,7 @@ EXPORT_SYMBOL_GPL(usb_hub_find_child);
 void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
 void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
 	enum usb_port_connect_type type)
 	enum usb_port_connect_type type)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	hub->ports[port1 - 1]->connect_type = type;
 	hub->ports[port1 - 1]->connect_type = type;
 }
 }
@@ -5295,11 +5326,52 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
 enum usb_port_connect_type
 enum usb_port_connect_type
 usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
 usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	return hub->ports[port1 - 1]->connect_type;
 	return hub->ports[port1 - 1]->connect_type;
 }
 }
 
 
+void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+		struct usb_hub_descriptor *desc)
+{
+	enum usb_port_connect_type connect_type;
+	int i;
+
+	if (!hub_is_superspeed(hdev)) {
+		for (i = 1; i <= hdev->maxchild; i++) {
+			connect_type = usb_get_hub_port_connect_type(hdev, i);
+
+			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+				u8 mask = 1 << (i%8);
+
+				if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) {
+					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n",
+						i);
+					desc->u.hs.DeviceRemovable[i/8]	|= mask;
+				}
+			}
+		}
+	} else {
+		u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);
+
+		for (i = 1; i <= hdev->maxchild; i++) {
+			connect_type = usb_get_hub_port_connect_type(hdev, i);
+
+			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+				u16 mask = 1 << i;
+
+				if (!(port_removable & mask)) {
+					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n",
+						i);
+					port_removable |= mask;
+				}
+			}
+		}
+
+		desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
+	}
+}
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_ACPI
 /**
 /**
  * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
  * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
@@ -5312,7 +5384,7 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
 acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
 acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
 	int port1)
 	int port1)
 {
 {
-	struct usb_hub *hub = hdev_to_hub(hdev);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
 
 
 	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
 	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
 }
 }

+ 122 - 0
drivers/usb/core/hub.h

@@ -0,0 +1,122 @@
+/*
+ * usb hub driver head file
+ *
+ * Copyright (C) 1999 Linus Torvalds
+ * Copyright (C) 1999 Johannes Erdfelt
+ * Copyright (C) 1999 Gregory P. Smith
+ * Copyright (C) 2001 Brad Hards (bhards@bigpond.net.au)
+ * Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com)
+ *
+ *  move struct usb_hub to this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+struct usb_hub {
+	struct device		*intfdev;	/* the "interface" device */
+	struct usb_device	*hdev;
+	struct kref		kref;
+	struct urb		*urb;		/* for interrupt polling pipe */
+
+	/* buffer for urb ... with extra space in case of babble */
+	u8			(*buffer)[8];
+	union {
+		struct usb_hub_status	hub;
+		struct usb_port_status	port;
+	}			*status;	/* buffer for status reports */
+	struct mutex		status_mutex;	/* for the status buffer */
+
+	int			error;		/* last reported error */
+	int			nerrors;	/* track consecutive errors */
+
+	struct list_head	event_list;	/* hubs w/data or errs ready */
+	unsigned long		event_bits[1];	/* status change bitmask */
+	unsigned long		change_bits[1];	/* ports with logical connect
+							status change */
+	unsigned long		busy_bits[1];	/* ports being reset or
+							resumed */
+	unsigned long		removed_bits[1]; /* ports with a "removed"
+							device present */
+	unsigned long		wakeup_bits[1];	/* ports that have signaled
+							remote wakeup */
+#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
+#error event_bits[] is too short!
+#endif
+
+	struct usb_hub_descriptor *descriptor;	/* class descriptor */
+	struct usb_tt		tt;		/* Transaction Translator */
+
+	unsigned		mA_per_port;	/* current for each child */
+
+	unsigned		limited_power:1;
+	unsigned		quiescing:1;
+	unsigned		disconnected:1;
+
+	unsigned		quirk_check_port_auto_suspend:1;
+
+	unsigned		has_indicators:1;
+	u8			indicator[USB_MAXCHILDREN];
+	struct delayed_work	leds;
+	struct delayed_work	init_work;
+	struct usb_port		**ports;
+};
+
+/**
+ * struct usb port - kernel's representation of a usb port
+ * @child: usb device attatched to the port
+ * @dev: generic device interface
+ * @port_owner: port's owner
+ * @connect_type: port's connect type
+ * @portnum: port index num based one
+ * @power_is_on: port's power state
+ * @did_runtime_put: port has done pm_runtime_put().
+ */
+struct usb_port {
+	struct usb_device *child;
+	struct device dev;
+	struct dev_state *port_owner;
+	enum usb_port_connect_type connect_type;
+	u8 portnum;
+	unsigned power_is_on:1;
+	unsigned did_runtime_put:1;
+};
+
+#define to_usb_port(_dev) \
+	container_of(_dev, struct usb_port, dev)
+
+extern int usb_hub_create_port_device(struct usb_hub *hub,
+		int port1);
+extern void usb_hub_remove_port_device(struct usb_hub *hub,
+		int port1);
+extern int usb_hub_set_port_power(struct usb_device *hdev,
+		int port1, bool set);
+extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
+extern int hub_port_debounce(struct usb_hub *hub, int port1,
+		bool must_be_connected);
+extern int usb_clear_port_feature(struct usb_device *hdev,
+		int port1, int feature);
+
+static inline int hub_port_debounce_be_connected(struct usb_hub *hub,
+		int port1)
+{
+	return hub_port_debounce(hub, port1, true);
+}
+
+static inline int hub_port_debounce_be_stable(struct usb_hub *hub,
+		int port1)
+{
+	return hub_port_debounce(hub, port1, false);
+}
+

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

@@ -1751,7 +1751,7 @@ free_interfaces:
 			}
 			}
 		}
 		}
 
 
-		i = dev->bus_mA - cp->desc.bMaxPower * 2;
+		i = dev->bus_mA - usb_get_max_power(dev, cp);
 		if (i < 0)
 		if (i < 0)
 			dev_warn(&dev->dev, "new config #%d exceeds power "
 			dev_warn(&dev->dev, "new config #%d exceeds power "
 					"limit by %dmA\n",
 					"limit by %dmA\n",

+ 202 - 0
drivers/usb/core/port.c

@@ -0,0 +1,202 @@
+/*
+ * usb port device code
+ *
+ * Copyright (C) 2012 Intel Corp
+ *
+ * Author: Lan Tianyu <tianyu.lan@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/pm_qos.h>
+
+#include "hub.h"
+
+static const struct attribute_group *port_dev_group[];
+
+static ssize_t show_port_connect_type(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+	char *result;
+
+	switch (port_dev->connect_type) {
+	case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+		result = "hotplug";
+		break;
+	case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+		result = "hardwired";
+		break;
+	case USB_PORT_NOT_USED:
+		result = "not used";
+		break;
+	default:
+		result = "unknown";
+		break;
+	}
+
+	return sprintf(buf, "%s\n", result);
+}
+static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type,
+		NULL);
+
+static struct attribute *port_dev_attrs[] = {
+	&dev_attr_connect_type.attr,
+	NULL,
+};
+
+static struct attribute_group port_dev_attr_grp = {
+	.attrs = port_dev_attrs,
+};
+
+static const struct attribute_group *port_dev_group[] = {
+	&port_dev_attr_grp,
+	NULL,
+};
+
+static void usb_port_device_release(struct device *dev)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+
+	dev_pm_qos_hide_flags(dev);
+	kfree(port_dev);
+}
+
+#ifdef CONFIG_USB_SUSPEND
+static int usb_port_runtime_resume(struct device *dev)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+	struct usb_device *hdev = to_usb_device(dev->parent->parent);
+	struct usb_interface *intf = to_usb_interface(dev->parent);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+	int port1 = port_dev->portnum;
+	int retval;
+
+	if (!hub)
+		return -EINVAL;
+
+	usb_autopm_get_interface(intf);
+	set_bit(port1, hub->busy_bits);
+
+	retval = usb_hub_set_port_power(hdev, port1, true);
+	if (port_dev->child && !retval) {
+		/*
+		 * Wait for usb hub port to be reconnected in order to make
+		 * the resume procedure successful.
+		 */
+		retval = hub_port_debounce_be_connected(hub, port1);
+		if (retval < 0) {
+			dev_dbg(&port_dev->dev, "can't get reconnection after setting port  power on, status %d\n",
+					retval);
+			goto out;
+		}
+		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
+
+		/* Set return value to 0 if debounce successful */
+		retval = 0;
+	}
+
+out:
+	clear_bit(port1, hub->busy_bits);
+	usb_autopm_put_interface(intf);
+	return retval;
+}
+
+static int usb_port_runtime_suspend(struct device *dev)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+	struct usb_device *hdev = to_usb_device(dev->parent->parent);
+	struct usb_interface *intf = to_usb_interface(dev->parent);
+	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+	int port1 = port_dev->portnum;
+	int retval;
+
+	if (!hub)
+		return -EINVAL;
+
+	if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)
+			== PM_QOS_FLAGS_ALL)
+		return -EAGAIN;
+
+	usb_autopm_get_interface(intf);
+	set_bit(port1, hub->busy_bits);
+	retval = usb_hub_set_port_power(hdev, port1, false);
+	usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
+	usb_clear_port_feature(hdev, port1,	USB_PORT_FEAT_C_ENABLE);
+	clear_bit(port1, hub->busy_bits);
+	usb_autopm_put_interface(intf);
+	return retval;
+}
+#endif
+
+static const struct dev_pm_ops usb_port_pm_ops = {
+#ifdef CONFIG_USB_SUSPEND
+	.runtime_suspend =	usb_port_runtime_suspend,
+	.runtime_resume =	usb_port_runtime_resume,
+	.runtime_idle =		pm_generic_runtime_idle,
+#endif
+};
+
+struct device_type usb_port_device_type = {
+	.name =		"usb_port",
+	.release =	usb_port_device_release,
+	.pm =		&usb_port_pm_ops,
+};
+
+int usb_hub_create_port_device(struct usb_hub *hub, int port1)
+{
+	struct usb_port *port_dev = NULL;
+	int retval;
+
+	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
+	if (!port_dev) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	hub->ports[port1 - 1] = port_dev;
+	port_dev->portnum = port1;
+	port_dev->power_is_on = true;
+	port_dev->dev.parent = hub->intfdev;
+	port_dev->dev.groups = port_dev_group;
+	port_dev->dev.type = &usb_port_device_type;
+	dev_set_name(&port_dev->dev, "port%d", port1);
+
+	retval = device_register(&port_dev->dev);
+	if (retval)
+		goto error_register;
+
+	pm_runtime_set_active(&port_dev->dev);
+
+	/* It would be dangerous if user space couldn't
+	 * prevent usb device from being powered off. So don't
+	 * enable port runtime pm if failed to expose port's pm qos.
+	 */
+	if (!dev_pm_qos_expose_flags(&port_dev->dev,
+			PM_QOS_FLAG_NO_POWER_OFF))
+		pm_runtime_enable(&port_dev->dev);
+
+	device_enable_async_suspend(&port_dev->dev);
+	return 0;
+
+error_register:
+	put_device(&port_dev->dev);
+exit:
+	return retval;
+}
+
+void usb_hub_remove_port_device(struct usb_hub *hub,
+				       int port1)
+{
+	device_unregister(&hub->ports[port1 - 1]->dev);
+}
+

+ 22 - 9
drivers/usb/core/sysfs.c

@@ -17,7 +17,7 @@
 #include "usb.h"
 #include "usb.h"
 
 
 /* Active configuration fields */
 /* Active configuration fields */
-#define usb_actconfig_show(field, multiplier, format_string)		\
+#define usb_actconfig_show(field, format_string)			\
 static ssize_t  show_##field(struct device *dev,			\
 static ssize_t  show_##field(struct device *dev,			\
 		struct device_attribute *attr, char *buf)		\
 		struct device_attribute *attr, char *buf)		\
 {									\
 {									\
@@ -28,18 +28,31 @@ static ssize_t  show_##field(struct device *dev,			\
 	actconfig = udev->actconfig;					\
 	actconfig = udev->actconfig;					\
 	if (actconfig)							\
 	if (actconfig)							\
 		return sprintf(buf, format_string,			\
 		return sprintf(buf, format_string,			\
-				actconfig->desc.field * multiplier);	\
+				actconfig->desc.field);			\
 	else								\
 	else								\
 		return 0;						\
 		return 0;						\
 }									\
 }									\
 
 
-#define usb_actconfig_attr(field, multiplier, format_string)		\
-usb_actconfig_show(field, multiplier, format_string)			\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+#define usb_actconfig_attr(field, format_string)		\
+	usb_actconfig_show(field, format_string)		\
+	static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_actconfig_attr(bNumInterfaces, "%2d\n")
+usb_actconfig_attr(bmAttributes, "%2x\n")
 
 
-usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr(bmAttributes, 1, "%2x\n")
-usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
+static ssize_t show_bMaxPower(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+	struct usb_host_config *actconfig;
+
+	udev = to_usb_device(dev);
+	actconfig = udev->actconfig;
+	if (!actconfig)
+		return 0;
+	return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
+}
+static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL);
 
 
 static ssize_t show_configuration_string(struct device *dev,
 static ssize_t show_configuration_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
 		struct device_attribute *attr, char *buf)
@@ -56,7 +69,7 @@ static ssize_t show_configuration_string(struct device *dev,
 static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 
 
 /* configuration value is always present, and r/w */
 /* configuration value is always present, and r/w */
-usb_actconfig_show(bConfigurationValue, 1, "%u\n");
+usb_actconfig_show(bConfigurationValue, "%u\n");
 
 
 static ssize_t
 static ssize_t
 set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
 set_bConfigurationValue(struct device *dev, struct device_attribute *attr,

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

@@ -1,6 +1,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/acpi.h>
 #include <linux/acpi.h>
 
 
+struct usb_hub_descriptor;
 struct dev_state;
 struct dev_state;
 
 
 /* Functions local to drivers/usb/core/ */
 /* Functions local to drivers/usb/core/ */
@@ -38,6 +39,15 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_choose_configuration(struct usb_device *udev);
 extern int usb_choose_configuration(struct usb_device *udev);
 
 
+static inline unsigned usb_get_max_power(struct usb_device *udev,
+		struct usb_host_config *c)
+{
+	/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
+	unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
+
+	return c->desc.bMaxPower * mul;
+}
+
 extern void usb_kick_khubd(struct usb_device *dev);
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_one_id_intf(struct usb_device *dev,
 extern int usb_match_one_id_intf(struct usb_device *dev,
 				 struct usb_host_interface *intf,
 				 struct usb_host_interface *intf,
@@ -173,6 +183,8 @@ extern enum usb_port_connect_type
 	usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
 	usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
 extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
 extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
 	enum usb_port_connect_type type);
 	enum usb_port_connect_type type);
+extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+		struct usb_hub_descriptor *desc);
 
 
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_ACPI
 extern int usb_acpi_register(void);
 extern int usb_acpi_register(void);

+ 30 - 1
drivers/usb/dwc3/Kconfig

@@ -1,6 +1,6 @@
 config USB_DWC3
 config USB_DWC3
 	tristate "DesignWare USB3 DRD Core Support"
 	tristate "DesignWare USB3 DRD Core Support"
-	depends on (USB && USB_GADGET)
+	depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
 	select USB_OTG_UTILS
 	select USB_OTG_UTILS
 	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
 	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
 	help
 	help
@@ -12,6 +12,35 @@ config USB_DWC3
 
 
 if USB_DWC3
 if USB_DWC3
 
 
+choice
+	bool "DWC3 Mode Selection"
+	default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
+	default USB_DWC3_HOST if (USB && !USB_GADGET)
+	default USB_DWC3_GADGET if (!USB && USB_GADGET)
+
+config USB_DWC3_HOST
+	bool "Host only mode"
+	depends on USB
+	help
+	  Select this when you want to use DWC3 in host mode only,
+	  thereby the gadget feature will be regressed.
+
+config USB_DWC3_GADGET
+	bool "Gadget only mode"
+	depends on USB_GADGET
+	help
+	  Select this when you want to use DWC3 in gadget mode only,
+	  thereby the host feature will be regressed.
+
+config USB_DWC3_DUAL_ROLE
+	bool "Dual Role mode"
+	depends on (USB && USB_GADGET)
+	help
+	  This is the default mode of working of DWC3 controller where
+	  both host and gadget features are enabled.
+
+endchoice
+
 config USB_DWC3_DEBUG
 config USB_DWC3_DEBUG
 	bool "Enable Debugging Messages"
 	bool "Enable Debugging Messages"
 	help
 	help

+ 8 - 2
drivers/usb/dwc3/Makefile

@@ -4,8 +4,14 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 
 
 dwc3-y					:= core.o
 dwc3-y					:= core.o
-dwc3-y					+= host.o
-dwc3-y					+= gadget.o ep0.o
+
+ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
+	dwc3-y				+= host.o
+endif
+
+ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
+	dwc3-y				+= gadget.o ep0.o
+endif
 
 
 ifneq ($(CONFIG_DEBUG_FS),)
 ifneq ($(CONFIG_DEBUG_FS),)
 	dwc3-y				+= debugfs.o
 	dwc3-y				+= debugfs.o

+ 25 - 6
drivers/usb/dwc3/core.c

@@ -420,18 +420,27 @@ static int dwc3_probe(struct platform_device *pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (node) {
+		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
+		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+	} else {
+		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+	}
+
 	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
 	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
 		dev_err(dev, "no usb2 phy configured\n");
 		dev_err(dev, "no usb2 phy configured\n");
 		return -EPROBE_DEFER;
 		return -EPROBE_DEFER;
 	}
 	}
 
 
-	dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
 	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
 	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
 		dev_err(dev, "no usb3 phy configured\n");
 		dev_err(dev, "no usb3 phy configured\n");
 		return -EPROBE_DEFER;
 		return -EPROBE_DEFER;
 	}
 	}
 
 
+	usb_phy_set_suspend(dwc->usb2_phy, 0);
+	usb_phy_set_suspend(dwc->usb3_phy, 0);
+
 	spin_lock_init(&dwc->lock);
 	spin_lock_init(&dwc->lock);
 	platform_set_drvdata(pdev, dwc);
 	platform_set_drvdata(pdev, dwc);
 
 
@@ -450,8 +459,7 @@ static int dwc3_probe(struct platform_device *pdev)
 	else
 	else
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
 
-	if (of_get_property(node, "tx-fifo-resize", NULL))
-		dwc->needs_fifo_resize = true;
+	dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
 
 
 	pm_runtime_enable(dev);
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	pm_runtime_get_sync(dev);
@@ -550,9 +558,9 @@ err0:
 static int dwc3_remove(struct platform_device *pdev)
 static int dwc3_remove(struct platform_device *pdev)
 {
 {
 	struct dwc3	*dwc = platform_get_drvdata(pdev);
 	struct dwc3	*dwc = platform_get_drvdata(pdev);
-	struct resource	*res;
 
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	usb_phy_set_suspend(dwc->usb2_phy, 1);
+	usb_phy_set_suspend(dwc->usb3_phy, 1);
 
 
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -580,11 +588,22 @@ static int dwc3_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_dwc3_match[] = {
+	{
+		.compatible = "synopsys,dwc3"
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+#endif
+
 static struct platform_driver dwc3_driver = {
 static struct platform_driver dwc3_driver = {
 	.probe		= dwc3_probe,
 	.probe		= dwc3_probe,
 	.remove		= dwc3_remove,
 	.remove		= dwc3_remove,
 	.driver		= {
 	.driver		= {
 		.name	= "dwc3",
 		.name	= "dwc3",
+		.of_match_table	= of_match_ptr(of_dwc3_match),
 	},
 	},
 };
 };
 
 

+ 20 - 4
drivers/usb/dwc3/core.h

@@ -55,7 +55,9 @@
 #define DWC3_ENDPOINTS_NUM	32
 #define DWC3_ENDPOINTS_NUM	32
 #define DWC3_XHCI_RESOURCES_NUM	2
 #define DWC3_XHCI_RESOURCES_NUM	2
 
 
-#define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
+#define DWC3_EVENT_SIZE		4	/* bytes */
+#define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */
+#define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
 #define DWC3_EVENT_TYPE_MASK	0xfe
 #define DWC3_EVENT_TYPE_MASK	0xfe
 
 
 #define DWC3_EVENT_TYPE_DEV	0
 #define DWC3_EVENT_TYPE_DEV	0
@@ -405,7 +407,6 @@ struct dwc3_event_buffer {
  * @number: endpoint number (1 - 15)
  * @number: endpoint number (1 - 15)
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @resource_index: Resource transfer index
  * @resource_index: Resource transfer index
- * @current_uf: Current uf received through last event parameter
  * @interval: the intervall on which the ISOC transfer is started
  * @interval: the intervall on which the ISOC transfer is started
  * @name: a human readable name e.g. ep1out-bulk
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
  * @direction: true for TX, false for RX
@@ -439,7 +440,6 @@ struct dwc3_ep {
 	u8			number;
 	u8			number;
 	u8			type;
 	u8			type;
 	u8			resource_index;
 	u8			resource_index;
-	u16			current_uf;
 	u32			interval;
 	u32			interval;
 
 
 	char			name[20];
 	char			name[20];
@@ -581,6 +581,7 @@ struct dwc3_request {
 	struct usb_request	request;
 	struct usb_request	request;
 	struct list_head	list;
 	struct list_head	list;
 	struct dwc3_ep		*dep;
 	struct dwc3_ep		*dep;
+	u32			start_slot;
 
 
 	u8			epnum;
 	u8			epnum;
 	struct dwc3_trb		*trb;
 	struct dwc3_trb		*trb;
@@ -721,6 +722,7 @@ struct dwc3 {
 
 
 	struct dwc3_hwparams	hwparams;
 	struct dwc3_hwparams	hwparams;
 	struct dentry		*root;
 	struct dentry		*root;
+	struct debugfs_regset32	*regset;
 
 
 	u8			test_mode;
 	u8			test_mode;
 	u8			test_mode_nr;
 	u8			test_mode_nr;
@@ -862,10 +864,24 @@ union dwc3_event {
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 
+#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_host_init(struct dwc3 *dwc);
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
-
+#else
+static inline int dwc3_host_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_host_exit(struct dwc3 *dwc)
+{ }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_gadget_init(struct dwc3 *dwc);
 int dwc3_gadget_init(struct dwc3 *dwc);
 void dwc3_gadget_exit(struct dwc3 *dwc);
 void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc)
+{ }
+#endif
 
 
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
 #endif /* __DRIVERS_USB_DWC3_CORE_H */

+ 14 - 24
drivers/usb/dwc3/debugfs.c

@@ -59,7 +59,7 @@
 	.offset	= DWC3_ ##nm - DWC3_GLOBALS_REGS_START,	\
 	.offset	= DWC3_ ##nm - DWC3_GLOBALS_REGS_START,	\
 }
 }
 
 
-static const struct debugfs_reg32 dwc3_regs[] = {
+static struct debugfs_reg32 dwc3_regs[] = {
 	dump_register(GSBUSCFG0),
 	dump_register(GSBUSCFG0),
 	dump_register(GSBUSCFG1),
 	dump_register(GSBUSCFG1),
 	dump_register(GTXTHRCFG),
 	dump_register(GTXTHRCFG),
@@ -376,27 +376,6 @@ static const struct debugfs_reg32 dwc3_regs[] = {
 	dump_register(OSTS),
 	dump_register(OSTS),
 };
 };
 
 
-static int dwc3_regdump_show(struct seq_file *s, void *unused)
-{
-	struct dwc3		*dwc = s->private;
-
-	seq_printf(s, "DesignWare USB3 Core Register Dump\n");
-	debugfs_print_regs32(s, dwc3_regs, ARRAY_SIZE(dwc3_regs),
-			     dwc->regs, "");
-	return 0;
-}
-
-static int dwc3_regdump_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, dwc3_regdump_show, inode->i_private);
-}
-
-static const struct file_operations dwc3_regdump_fops = {
-	.open			= dwc3_regdump_open,
-	.read			= seq_read,
-	.release		= single_release,
-};
-
 static int dwc3_mode_show(struct seq_file *s, void *unused)
 static int dwc3_mode_show(struct seq_file *s, void *unused)
 {
 {
 	struct dwc3		*dwc = s->private;
 	struct dwc3		*dwc = s->private;
@@ -666,13 +645,23 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
 
 
 	dwc->root = root;
 	dwc->root = root;
 
 
-	file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
-			&dwc3_regdump_fops);
+	dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
+	if (!dwc->regset) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dwc->regset->regs = dwc3_regs;
+	dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
+	dwc->regset->base = dwc->regs;
+
+	file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
 	if (!file) {
 	if (!file) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err1;
 		goto err1;
 	}
 	}
 
 
+#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
 	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
 	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
 			dwc, &dwc3_mode_fops);
 			dwc, &dwc3_mode_fops);
 	if (!file) {
 	if (!file) {
@@ -693,6 +682,7 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err1;
 		goto err1;
 	}
 	}
+#endif
 
 
 	return 0;
 	return 0;
 
 

+ 26 - 31
drivers/usb/dwc3/dwc3-exynos.c

@@ -42,7 +42,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
 
 
 	memset(&pdata, 0x00, sizeof(pdata));
 	memset(&pdata, 0x00, sizeof(pdata));
 
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev)
 	if (!pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -53,7 +53,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
 	if (ret)
 	if (ret)
 		goto err1;
 		goto err1;
 
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev) {
 	if (!pdev) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err1;
 		goto err1;
@@ -95,13 +95,14 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
 	struct platform_device	*dwc3;
 	struct platform_device	*dwc3;
 	struct dwc3_exynos	*exynos;
 	struct dwc3_exynos	*exynos;
 	struct clk		*clk;
 	struct clk		*clk;
+	struct device		*dev = &pdev->dev;
 
 
 	int			ret = -ENOMEM;
 	int			ret = -ENOMEM;
 
 
-	exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
+	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
 	if (!exynos) {
 	if (!exynos) {
-		dev_err(&pdev->dev, "not enough memory\n");
-		goto err0;
+		dev_err(dev, "not enough memory\n");
+		return -ENOMEM;
 	}
 	}
 
 
 	/*
 	/*
@@ -116,30 +117,30 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
 
 
 	ret = dwc3_exynos_register_phys(exynos);
 	ret = dwc3_exynos_register_phys(exynos);
 	if (ret) {
 	if (ret) {
-		dev_err(&pdev->dev, "couldn't register PHYs\n");
-		goto err1;
+		dev_err(dev, "couldn't register PHYs\n");
+		return ret;
 	}
 	}
 
 
 	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 	if (!dwc3) {
 	if (!dwc3) {
-		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-		goto err1;
+		dev_err(dev, "couldn't allocate dwc3 device\n");
+		return -ENOMEM;
 	}
 	}
 
 
-	clk = clk_get(&pdev->dev, "usbdrd30");
+	clk = devm_clk_get(dev, "usbdrd30");
 	if (IS_ERR(clk)) {
 	if (IS_ERR(clk)) {
-		dev_err(&pdev->dev, "couldn't get clock\n");
+		dev_err(dev, "couldn't get clock\n");
 		ret = -EINVAL;
 		ret = -EINVAL;
-		goto err3;
+		goto err1;
 	}
 	}
 
 
-	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
 
-	dwc3->dev.parent = &pdev->dev;
-	dwc3->dev.dma_mask = pdev->dev.dma_mask;
-	dwc3->dev.dma_parms = pdev->dev.dma_parms;
+	dwc3->dev.parent = dev;
+	dwc3->dev.dma_mask = dev->dma_mask;
+	dwc3->dev.dma_parms = dev->dma_parms;
 	exynos->dwc3	= dwc3;
 	exynos->dwc3	= dwc3;
-	exynos->dev	= &pdev->dev;
+	exynos->dev	= dev;
 	exynos->clk	= clk;
 	exynos->clk	= clk;
 
 
 	clk_enable(exynos->clk);
 	clk_enable(exynos->clk);
@@ -147,26 +148,23 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
 	ret = platform_device_add_resources(dwc3, pdev->resource,
 	ret = platform_device_add_resources(dwc3, pdev->resource,
 			pdev->num_resources);
 			pdev->num_resources);
 	if (ret) {
 	if (ret) {
-		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-		goto err4;
+		dev_err(dev, "couldn't add resources to dwc3 device\n");
+		goto err2;
 	}
 	}
 
 
 	ret = platform_device_add(dwc3);
 	ret = platform_device_add(dwc3);
 	if (ret) {
 	if (ret) {
-		dev_err(&pdev->dev, "failed to register dwc3 device\n");
-		goto err4;
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto err2;
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
-err4:
+err2:
 	clk_disable(clk);
 	clk_disable(clk);
-	clk_put(clk);
-err3:
-	platform_device_put(dwc3);
 err1:
 err1:
-	kfree(exynos);
-err0:
+	platform_device_put(dwc3);
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -179,16 +177,13 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
 	platform_device_unregister(exynos->usb3_phy);
 	platform_device_unregister(exynos->usb3_phy);
 
 
 	clk_disable(exynos->clk);
 	clk_disable(exynos->clk);
-	clk_put(exynos->clk);
-
-	kfree(exynos);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static const struct of_device_id exynos_dwc3_match[] = {
 static const struct of_device_id exynos_dwc3_match[] = {
-	{ .compatible = "samsung,exynos-dwc3" },
+	{ .compatible = "samsung,exynos5250-dwusb3" },
 	{},
 	{},
 };
 };
 MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
 MODULE_DEVICE_TABLE(of, exynos_dwc3_match);

+ 93 - 59
drivers/usb/dwc3/dwc3-omap.c

@@ -43,10 +43,13 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/dwc3-omap.h>
 #include <linux/platform_data/dwc3-omap.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 
 
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/nop-usb-xceiv.h>
 #include <linux/usb/nop-usb-xceiv.h>
@@ -78,23 +81,6 @@
 
 
 /* SYSCONFIG REGISTER */
 /* SYSCONFIG REGISTER */
 #define USBOTGSS_SYSCONFIG_DMADISABLE		(1 << 16)
 #define USBOTGSS_SYSCONFIG_DMADISABLE		(1 << 16)
-#define USBOTGSS_SYSCONFIG_STANDBYMODE(x)	((x) << 4)
-
-#define USBOTGSS_STANDBYMODE_FORCE_STANDBY	0
-#define USBOTGSS_STANDBYMODE_NO_STANDBY		1
-#define USBOTGSS_STANDBYMODE_SMART_STANDBY	2
-#define USBOTGSS_STANDBYMODE_SMART_WAKEUP	3
-
-#define USBOTGSS_STANDBYMODE_MASK		(0x03 << 4)
-
-#define USBOTGSS_SYSCONFIG_IDLEMODE(x)		((x) << 2)
-
-#define USBOTGSS_IDLEMODE_FORCE_IDLE		0
-#define USBOTGSS_IDLEMODE_NO_IDLE		1
-#define USBOTGSS_IDLEMODE_SMART_IDLE		2
-#define USBOTGSS_IDLEMODE_SMART_WAKEUP		3
-
-#define USBOTGSS_IDLEMODE_MASK			(0x03 << 2)
 
 
 /* IRQ_EOI REGISTER */
 /* IRQ_EOI REGISTER */
 #define USBOTGSS_IRQ_EOI_LINE_NUMBER		(1 << 0)
 #define USBOTGSS_IRQ_EOI_LINE_NUMBER		(1 << 0)
@@ -133,7 +119,6 @@ struct dwc3_omap {
 	/* device lock */
 	/* device lock */
 	spinlock_t		lock;
 	spinlock_t		lock;
 
 
-	struct platform_device	*dwc3;
 	struct platform_device	*usb2_phy;
 	struct platform_device	*usb2_phy;
 	struct platform_device	*usb3_phy;
 	struct platform_device	*usb3_phy;
 	struct device		*dev;
 	struct device		*dev;
@@ -147,6 +132,8 @@ struct dwc3_omap {
 	u32			dma_status:1;
 	u32			dma_status:1;
 };
 };
 
 
+struct dwc3_omap		*_omap;
+
 static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
 static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
 {
 {
 	return readl(base + offset);
 	return readl(base + offset);
@@ -157,6 +144,57 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
 	writel(value, base + offset);
 	writel(value, base + offset);
 }
 }
 
 
+void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+{
+	u32			val;
+	struct dwc3_omap	*omap = _omap;
+
+	switch (status) {
+	case OMAP_DWC3_ID_GROUND:
+		dev_dbg(omap->dev, "ID GND\n");
+
+		val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+		val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_SESSEND);
+		val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
+		dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
+		break;
+
+	case OMAP_DWC3_VBUS_VALID:
+		dev_dbg(omap->dev, "VBUS Connect\n");
+
+		val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+		val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
+		val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
+		dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
+		break;
+
+	case OMAP_DWC3_ID_FLOAT:
+	case OMAP_DWC3_VBUS_OFF:
+		dev_dbg(omap->dev, "VBUS Disconnect\n");
+
+		val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+		val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
+				| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
+		val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
+				| USBOTGSS_UTMI_OTG_STATUS_IDDIG;
+		dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
+		break;
+
+	default:
+		dev_dbg(omap->dev, "ID float\n");
+	}
+
+	return;
+}
+EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
+
 static int dwc3_omap_register_phys(struct dwc3_omap *omap)
 static int dwc3_omap_register_phys(struct dwc3_omap *omap)
 {
 {
 	struct nop_usb_xceiv_platform_data pdata;
 	struct nop_usb_xceiv_platform_data pdata;
@@ -165,7 +203,7 @@ static int dwc3_omap_register_phys(struct dwc3_omap *omap)
 
 
 	memset(&pdata, 0x00, sizeof(pdata));
 	memset(&pdata, 0x00, sizeof(pdata));
 
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev)
 	if (!pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -176,7 +214,7 @@ static int dwc3_omap_register_phys(struct dwc3_omap *omap)
 	if (ret)
 	if (ret)
 		goto err1;
 		goto err1;
 
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev) {
 	if (!pdev) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err1;
 		goto err1;
@@ -262,12 +300,20 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
+static int dwc3_omap_remove_core(struct device *dev, void *c)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	platform_device_unregister(pdev);
+
+	return 0;
+}
+
 static int dwc3_omap_probe(struct platform_device *pdev)
 static int dwc3_omap_probe(struct platform_device *pdev)
 {
 {
 	struct dwc3_omap_data	*pdata = pdev->dev.platform_data;
 	struct dwc3_omap_data	*pdata = pdev->dev.platform_data;
 	struct device_node	*node = pdev->dev.of_node;
 	struct device_node	*node = pdev->dev.of_node;
 
 
-	struct platform_device	*dwc3;
 	struct dwc3_omap	*omap;
 	struct dwc3_omap	*omap;
 	struct resource		*res;
 	struct resource		*res;
 	struct device		*dev = &pdev->dev;
 	struct device		*dev = &pdev->dev;
@@ -314,30 +360,32 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
-	if (!dwc3) {
-		dev_err(dev, "couldn't allocate dwc3 device\n");
-		return -ENOMEM;
-	}
-
 	context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
 	context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
 	if (!context) {
 	if (!context) {
 		dev_err(dev, "couldn't allocate dwc3 context memory\n");
 		dev_err(dev, "couldn't allocate dwc3 context memory\n");
-		goto err2;
+		return -ENOMEM;
 	}
 	}
 
 
 	spin_lock_init(&omap->lock);
 	spin_lock_init(&omap->lock);
-	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
 
-	dwc3->dev.parent = dev;
-	dwc3->dev.dma_mask = dev->dma_mask;
-	dwc3->dev.dma_parms = dev->dma_parms;
 	omap->resource_size = resource_size(res);
 	omap->resource_size = resource_size(res);
 	omap->context	= context;
 	omap->context	= context;
 	omap->dev	= dev;
 	omap->dev	= dev;
 	omap->irq	= irq;
 	omap->irq	= irq;
 	omap->base	= base;
 	omap->base	= base;
-	omap->dwc3	= dwc3;
+
+	/*
+	 * REVISIT if we ever have two instances of the wrapper, we will be
+	 * in big trouble
+	 */
+	_omap	= omap;
+
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "get_sync failed with err %d\n", ret);
+		return ret;
+	}
 
 
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
 
@@ -368,21 +416,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
 	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
 
 
-	/* Set No-Idle and No-Standby */
-	reg &= ~(USBOTGSS_STANDBYMODE_MASK
-			| USBOTGSS_IDLEMODE_MASK);
-
-	reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
-		| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
-
-	dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
-
 	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
 	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
 			"dwc3-omap", omap);
 			"dwc3-omap", omap);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "failed to request IRQ #%d --> %d\n",
 		dev_err(dev, "failed to request IRQ #%d --> %d\n",
 				omap->irq, ret);
 				omap->irq, ret);
-		goto err2;
+		return ret;
 	}
 	}
 
 
 	/* enable all IRQs */
 	/* enable all IRQs */
@@ -401,33 +440,28 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 
 
 	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
 	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
 
 
-	ret = platform_device_add_resources(dwc3, pdev->resource,
-			pdev->num_resources);
-	if (ret) {
-		dev_err(dev, "couldn't add resources to dwc3 device\n");
-		goto err2;
-	}
-
-	ret = platform_device_add(dwc3);
-	if (ret) {
-		dev_err(dev, "failed to register dwc3 device\n");
-		goto err2;
+	if (node) {
+		ret = of_platform_populate(node, NULL, NULL, dev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"failed to add create dwc3 core\n");
+			return ret;
+		}
 	}
 	}
 
 
 	return 0;
 	return 0;
-
-err2:
-	platform_device_put(dwc3);
-	return ret;
 }
 }
 
 
 static int dwc3_omap_remove(struct platform_device *pdev)
 static int dwc3_omap_remove(struct platform_device *pdev)
 {
 {
 	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
 	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
 
 
-	platform_device_unregister(omap->dwc3);
 	platform_device_unregister(omap->usb2_phy);
 	platform_device_unregister(omap->usb2_phy);
 	platform_device_unregister(omap->usb3_phy);
 	platform_device_unregister(omap->usb3_phy);
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 179 - 113
drivers/usb/dwc3/gadget.c

@@ -241,21 +241,23 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		int status)
 		int status)
 {
 {
 	struct dwc3			*dwc = dep->dwc;
 	struct dwc3			*dwc = dep->dwc;
+	int				i;
 
 
 	if (req->queued) {
 	if (req->queued) {
-		if (req->request.num_mapped_sgs)
-			dep->busy_slot += req->request.num_mapped_sgs;
-		else
+		i = 0;
+		do {
 			dep->busy_slot++;
 			dep->busy_slot++;
-
-		/*
-		 * Skip LINK TRB. We can't use req->trb and check for
-		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
-		 * completed (not the LINK TRB).
-		 */
-		if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+			/*
+			 * Skip LINK TRB. We can't use req->trb and check for
+			 * DWC3_TRBCTL_LINK_TRB because it points the TRB we
+			 * just completed (not the LINK TRB).
+			 */
+			if (((dep->busy_slot & DWC3_TRB_MASK) ==
+				DWC3_TRB_NUM- 1) &&
 				usb_endpoint_xfer_isoc(dep->endpoint.desc))
 				usb_endpoint_xfer_isoc(dep->endpoint.desc))
-			dep->busy_slot++;
+				dep->busy_slot++;
+		} while(++i < req->request.num_mapped_sgs);
+		req->queued = false;
 	}
 	}
 	list_del(&req->list);
 	list_del(&req->list);
 	req->trb = NULL;
 	req->trb = NULL;
@@ -749,33 +751,32 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
  */
  */
 static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 		struct dwc3_request *req, dma_addr_t dma,
 		struct dwc3_request *req, dma_addr_t dma,
-		unsigned length, unsigned last, unsigned chain)
+		unsigned length, unsigned last, unsigned chain, unsigned node)
 {
 {
 	struct dwc3		*dwc = dep->dwc;
 	struct dwc3		*dwc = dep->dwc;
 	struct dwc3_trb		*trb;
 	struct dwc3_trb		*trb;
 
 
-	unsigned int		cur_slot;
-
 	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
 	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
 			dep->name, req, (unsigned long long) dma,
 			dep->name, req, (unsigned long long) dma,
 			length, last ? " last" : "",
 			length, last ? " last" : "",
 			chain ? " chain" : "");
 			chain ? " chain" : "");
 
 
-	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
-	cur_slot = dep->free_slot;
-	dep->free_slot++;
-
 	/* Skip the LINK-TRB on ISOC */
 	/* Skip the LINK-TRB on ISOC */
-	if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
 			usb_endpoint_xfer_isoc(dep->endpoint.desc))
 			usb_endpoint_xfer_isoc(dep->endpoint.desc))
-		return;
+		dep->free_slot++;
+
+	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 
 
 	if (!req->trb) {
 	if (!req->trb) {
 		dwc3_gadget_move_request_queued(req);
 		dwc3_gadget_move_request_queued(req);
 		req->trb = trb;
 		req->trb = trb;
 		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+		req->start_slot = dep->free_slot & DWC3_TRB_MASK;
 	}
 	}
 
 
+	dep->free_slot++;
+
 	trb->size = DWC3_TRB_SIZE_LENGTH(length);
 	trb->size = DWC3_TRB_SIZE_LENGTH(length);
 	trb->bpl = lower_32_bits(dma);
 	trb->bpl = lower_32_bits(dma);
 	trb->bph = upper_32_bits(dma);
 	trb->bph = upper_32_bits(dma);
@@ -786,9 +787,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 		break;
 		break;
 
 
 	case USB_ENDPOINT_XFER_ISOC:
 	case USB_ENDPOINT_XFER_ISOC:
-		trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+		if (!node)
+			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+		else
+			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
 
 
-		if (!req->request.no_interrupt)
+		if (!req->request.no_interrupt && !chain)
 			trb->ctrl |= DWC3_TRB_CTRL_IOC;
 			trb->ctrl |= DWC3_TRB_CTRL_IOC;
 		break;
 		break;
 
 
@@ -807,14 +811,13 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
 		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
 		trb->ctrl |= DWC3_TRB_CTRL_CSP;
 		trb->ctrl |= DWC3_TRB_CTRL_CSP;
-	} else {
-		if (chain)
-			trb->ctrl |= DWC3_TRB_CTRL_CHN;
-
-		if (last)
-			trb->ctrl |= DWC3_TRB_CTRL_LST;
+	} else if (last) {
+		trb->ctrl |= DWC3_TRB_CTRL_LST;
 	}
 	}
 
 
+	if (chain)
+		trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
 	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
 	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
 		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
 		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
 
 
@@ -885,6 +888,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
 		unsigned	length;
 		unsigned	length;
 		dma_addr_t	dma;
 		dma_addr_t	dma;
+		last_one = false;
 
 
 		if (req->request.num_mapped_sgs > 0) {
 		if (req->request.num_mapped_sgs > 0) {
 			struct usb_request *request = &req->request;
 			struct usb_request *request = &req->request;
@@ -900,7 +904,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 
 
 				if (i == (request->num_mapped_sgs - 1) ||
 				if (i == (request->num_mapped_sgs - 1) ||
 						sg_is_last(s)) {
 						sg_is_last(s)) {
-					last_one = true;
+					if (list_is_last(&req->list,
+							&dep->request_list))
+						last_one = true;
 					chain = false;
 					chain = false;
 				}
 				}
 
 
@@ -912,7 +918,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 					chain = false;
 					chain = false;
 
 
 				dwc3_prepare_one_trb(dep, req, dma, length,
 				dwc3_prepare_one_trb(dep, req, dma, length,
-						last_one, chain);
+						last_one, chain, i);
 
 
 				if (last_one)
 				if (last_one)
 					break;
 					break;
@@ -930,7 +936,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 				last_one = 1;
 				last_one = 1;
 
 
 			dwc3_prepare_one_trb(dep, req, dma, length,
 			dwc3_prepare_one_trb(dep, req, dma, length,
-					last_one, false);
+					last_one, false, 0);
 
 
 			if (last_one)
 			if (last_one)
 				break;
 				break;
@@ -977,13 +983,14 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 	}
 	}
 
 
 	memset(&params, 0, sizeof(params));
 	memset(&params, 0, sizeof(params));
-	params.param0 = upper_32_bits(req->trb_dma);
-	params.param1 = lower_32_bits(req->trb_dma);
 
 
-	if (start_new)
+	if (start_new) {
+		params.param0 = upper_32_bits(req->trb_dma);
+		params.param1 = lower_32_bits(req->trb_dma);
 		cmd = DWC3_DEPCMD_STARTTRANSFER;
 		cmd = DWC3_DEPCMD_STARTTRANSFER;
-	else
+	} else {
 		cmd = DWC3_DEPCMD_UPDATETRANSFER;
 		cmd = DWC3_DEPCMD_UPDATETRANSFER;
+	}
 
 
 	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
 	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
 	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
 	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
@@ -1082,8 +1089,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	 *
 	 *
 	 */
 	 */
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-		int	ret;
-
 		/*
 		/*
 		 * If xfernotready is already elapsed and it is a case
 		 * If xfernotready is already elapsed and it is a case
 		 * of isoc transfer, then issue END TRANSFER, so that
 		 * of isoc transfer, then issue END TRANSFER, so that
@@ -1091,7 +1096,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 		 * notion of current microframe.
 		 * notion of current microframe.
 		 */
 		 */
 		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
-			dwc3_stop_active_transfer(dwc, dep->number);
+			if (list_empty(&dep->req_queued)) {
+				dwc3_stop_active_transfer(dwc, dep->number);
+				dep->flags = DWC3_EP_ENABLED;
+			}
 			return 0;
 			return 0;
 		}
 		}
 
 
@@ -1099,6 +1107,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 		if (ret && ret != -EBUSY)
 		if (ret && ret != -EBUSY)
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
 					dep->name);
+		return ret;
 	}
 	}
 
 
 	/*
 	/*
@@ -1115,16 +1124,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 		if (ret && ret != -EBUSY)
 		if (ret && ret != -EBUSY)
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
 					dep->name);
-	}
-
-	/*
-	 * 3. Missed ISOC Handling. We need to start isoc transfer on the saved
-	 * uframe number.
-	 */
-	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-		(dep->flags & DWC3_EP_MISSED_ISOC)) {
-			__dwc3_gadget_start_isoc(dwc, dep, dep->current_uf);
-			dep->flags &= ~DWC3_EP_MISSED_ISOC;
+		return ret;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -1652,76 +1652,134 @@ static void dwc3_gadget_release(struct device *dev)
 }
 }
 
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
-static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
+		struct dwc3_request *req, struct dwc3_trb *trb,
 		const struct dwc3_event_depevt *event, int status)
 		const struct dwc3_event_depevt *event, int status)
 {
 {
-	struct dwc3_request	*req;
-	struct dwc3_trb		*trb;
 	unsigned int		count;
 	unsigned int		count;
 	unsigned int		s_pkt = 0;
 	unsigned int		s_pkt = 0;
 	unsigned int		trb_status;
 	unsigned int		trb_status;
 
 
+	if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
+		/*
+		 * We continue despite the error. There is not much we
+		 * can do. If we don't clean it up we loop forever. If
+		 * we skip the TRB then it gets overwritten after a
+		 * while since we use them in a ring buffer. A BUG()
+		 * would help. Lets hope that if this occurs, someone
+		 * fixes the root cause instead of looking away :)
+		 */
+		dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+				dep->name, trb);
+	count = trb->size & DWC3_TRB_SIZE_MASK;
+
+	if (dep->direction) {
+		if (count) {
+			trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+			if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
+				dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				/*
+				 * If missed isoc occurred and there is
+				 * no request queued then issue END
+				 * TRANSFER, so that core generates
+				 * next xfernotready and we will issue
+				 * a fresh START TRANSFER.
+				 * If there are still queued request
+				 * then wait, do not issue either END
+				 * or UPDATE TRANSFER, just attach next
+				 * request in request_list during
+				 * giveback.If any future queued request
+				 * is successfully transferred then we
+				 * will issue UPDATE TRANSFER for all
+				 * request in the request_list.
+				 */
+				dep->flags |= DWC3_EP_MISSED_ISOC;
+			} else {
+				dev_err(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				status = -ECONNRESET;
+			}
+		} else {
+			dep->flags &= ~DWC3_EP_MISSED_ISOC;
+		}
+	} else {
+		if (count && (event->status & DEPEVT_STATUS_SHORT))
+			s_pkt = 1;
+	}
+
+	/*
+	 * We assume here we will always receive the entire data block
+	 * which we should receive. Meaning, if we program RX to
+	 * receive 4K but we receive only 2K, we assume that's all we
+	 * should receive and we simply bounce the request back to the
+	 * gadget driver for further processing.
+	 */
+	req->request.actual += req->request.length - count;
+	if (s_pkt)
+		return 1;
+	if ((event->status & DEPEVT_STATUS_LST) &&
+			(trb->ctrl & (DWC3_TRB_CTRL_LST |
+				DWC3_TRB_CTRL_HWO)))
+		return 1;
+	if ((event->status & DEPEVT_STATUS_IOC) &&
+			(trb->ctrl & DWC3_TRB_CTRL_IOC))
+		return 1;
+	return 0;
+}
+
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event, int status)
+{
+	struct dwc3_request	*req;
+	struct dwc3_trb		*trb;
+	unsigned int		slot;
+	unsigned int		i;
+	int			ret;
+
 	do {
 	do {
 		req = next_request(&dep->req_queued);
 		req = next_request(&dep->req_queued);
 		if (!req) {
 		if (!req) {
 			WARN_ON_ONCE(1);
 			WARN_ON_ONCE(1);
 			return 1;
 			return 1;
 		}
 		}
+		i = 0;
+		do {
+			slot = req->start_slot + i;
+			if ((slot == DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->endpoint.desc))
+				slot++;
+			slot %= DWC3_TRB_NUM;
+			trb = &dep->trb_pool[slot];
 
 
-		trb = req->trb;
+			ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+					event, status);
+			if (ret)
+				break;
+		}while (++i < req->request.num_mapped_sgs);
 
 
-		if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
+		dwc3_gadget_giveback(dep, req, status);
+
+		if (ret)
+			break;
+	} while (1);
+
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+			list_empty(&dep->req_queued)) {
+		if (list_empty(&dep->request_list)) {
 			/*
 			/*
-			 * We continue despite the error. There is not much we
-			 * can do. If we don't clean it up we loop forever. If
-			 * we skip the TRB then it gets overwritten after a
-			 * while since we use them in a ring buffer. A BUG()
-			 * would help. Lets hope that if this occurs, someone
-			 * fixes the root cause instead of looking away :)
+			 * If there is no entry in request list then do
+			 * not issue END TRANSFER now. Just set PENDING
+			 * flag, so that END TRANSFER is issued when an
+			 * entry is added into request list.
 			 */
 			 */
-			dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
-					dep->name, req->trb);
-		count = trb->size & DWC3_TRB_SIZE_MASK;
-
-		if (dep->direction) {
-			if (count) {
-				trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
-				if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
-					dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
-							dep->name);
-					dep->current_uf = event->parameters &
-						~(dep->interval - 1);
-					dep->flags |= DWC3_EP_MISSED_ISOC;
-				} else {
-					dev_err(dwc->dev, "incomplete IN transfer %s\n",
-							dep->name);
-					status = -ECONNRESET;
-				}
-			}
+			dep->flags = DWC3_EP_PENDING_REQUEST;
 		} else {
 		} else {
-			if (count && (event->status & DEPEVT_STATUS_SHORT))
-				s_pkt = 1;
+			dwc3_stop_active_transfer(dwc, dep->number);
+			dep->flags = DWC3_EP_ENABLED;
 		}
 		}
-
-		/*
-		 * We assume here we will always receive the entire data block
-		 * which we should receive. Meaning, if we program RX to
-		 * receive 4K but we receive only 2K, we assume that's all we
-		 * should receive and we simply bounce the request back to the
-		 * gadget driver for further processing.
-		 */
-		req->request.actual += req->request.length - count;
-		dwc3_gadget_giveback(dep, req, status);
-		if (s_pkt)
-			break;
-		if ((event->status & DEPEVT_STATUS_LST) &&
-				(trb->ctrl & (DWC3_TRB_CTRL_LST |
-						DWC3_TRB_CTRL_HWO)))
-			break;
-		if ((event->status & DEPEVT_STATUS_IOC) &&
-				(trb->ctrl & DWC3_TRB_CTRL_IOC))
-			break;
-	} while (1);
+		return 1;
+	}
 
 
 	if ((event->status & DEPEVT_STATUS_IOC) &&
 	if ((event->status & DEPEVT_STATUS_IOC) &&
 			(trb->ctrl & DWC3_TRB_CTRL_IOC))
 			(trb->ctrl & DWC3_TRB_CTRL_IOC))
@@ -2157,6 +2215,26 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 		break;
 		break;
 	}
 	}
 
 
+	/* Enable USB2 LPM Capability */
+
+	if ((dwc->revision > DWC3_REVISION_194A)
+			&& (speed != DWC3_DCFG_SUPERSPEED)) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg |= DWC3_DCFG_LPM_CAP;
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+		/*
+		 * TODO: This should be configurable. For now using
+		 * maximum allowed HIRD threshold value of 0b1100
+		 */
+		reg |= DWC3_DCTL_HIRD_THRES(12);
+
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
+
 	/* Recent versions support automatic phy suspend and don't need this */
 	/* Recent versions support automatic phy suspend and don't need this */
 	if (dwc->revision < DWC3_REVISION_194A) {
 	if (dwc->revision < DWC3_REVISION_194A) {
 		/* Suspend unneeded PHY */
 		/* Suspend unneeded PHY */
@@ -2463,20 +2541,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 			DWC3_DEVTEN_DISCONNEVTEN);
 			DWC3_DEVTEN_DISCONNEVTEN);
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 
 
-	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
+	/* automatic phy suspend only on recent versions */
 	if (dwc->revision >= DWC3_REVISION_194A) {
 	if (dwc->revision >= DWC3_REVISION_194A) {
-		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-		reg |= DWC3_DCFG_LPM_CAP;
-		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
-		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
-
-		/* TODO: This should be configurable */
-		reg |= DWC3_DCTL_HIRD_THRES(28);
-
-		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
 		dwc3_gadget_usb2_phy_suspend(dwc, false);
 		dwc3_gadget_usb2_phy_suspend(dwc, false);
 		dwc3_gadget_usb3_phy_suspend(dwc, false);
 		dwc3_gadget_usb3_phy_suspend(dwc, false);
 	}
 	}

+ 1 - 1
drivers/usb/dwc3/host.c

@@ -44,7 +44,7 @@ int dwc3_host_init(struct dwc3 *dwc)
 	struct platform_device	*xhci;
 	struct platform_device	*xhci;
 	int			ret;
 	int			ret;
 
 
-	xhci = platform_device_alloc("xhci-hcd", -1);
+	xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
 	if (!xhci) {
 	if (!xhci) {
 		dev_err(dwc->dev, "couldn't allocate xHCI device\n");
 		dev_err(dwc->dev, "couldn't allocate xHCI device\n");
 		ret = -ENOMEM;
 		ret = -ENOMEM;

+ 23 - 1
drivers/usb/gadget/Kconfig

@@ -281,6 +281,7 @@ config USB_S3C_HSOTG
 config USB_IMX
 config USB_IMX
 	tristate "Freescale i.MX1 USB Peripheral Controller"
 	tristate "Freescale i.MX1 USB Peripheral Controller"
 	depends on ARCH_MXC
 	depends on ARCH_MXC
+	depends on BROKEN
 	help
 	help
 	   Freescale's i.MX1 includes an integrated full speed
 	   Freescale's i.MX1 includes an integrated full speed
 	   USB 1.1 device controller.
 	   USB 1.1 device controller.
@@ -319,6 +320,7 @@ config USB_S3C_HSUDC
 
 
 config USB_MV_UDC
 config USB_MV_UDC
 	tristate "Marvell USB2.0 Device Controller"
 	tristate "Marvell USB2.0 Device Controller"
+	depends on GENERIC_HARDIRQS
 	help
 	help
 	  Marvell Socs (including PXA and MMP series) include a high speed
 	  Marvell Socs (including PXA and MMP series) include a high speed
 	  USB2.0 OTG controller, which can be configured as high speed or
 	  USB2.0 OTG controller, which can be configured as high speed or
@@ -440,7 +442,7 @@ config USB_GOKU
 
 
 config USB_EG20T
 config USB_EG20T
 	tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
 	tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
-	depends on PCI
+	depends on PCI && GENERIC_HARDIRQS
 	help
 	help
 	  This is a USB device driver for EG20T PCH.
 	  This is a USB device driver for EG20T PCH.
 	  EG20T PCH is the platform controller hub that is used in Intel's
 	  EG20T PCH is the platform controller hub that is used in Intel's
@@ -500,6 +502,15 @@ config USB_LIBCOMPOSITE
 	tristate
 	tristate
 	depends on USB_GADGET
 	depends on USB_GADGET
 
 
+config USB_F_ACM
+	tristate
+
+config USB_F_SS_LB
+	tristate
+
+config USB_U_SERIAL
+	tristate
+
 choice
 choice
 	tristate "USB Gadget Drivers"
 	tristate "USB Gadget Drivers"
 	default USB_ETH
 	default USB_ETH
@@ -524,6 +535,7 @@ choice
 config USB_ZERO
 config USB_ZERO
 	tristate "Gadget Zero (DEVELOPMENT)"
 	tristate "Gadget Zero (DEVELOPMENT)"
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
+	select USB_F_SS_LB
 	help
 	help
 	  Gadget Zero is a two-configuration device.  It either sinks and
 	  Gadget Zero is a two-configuration device.  It either sinks and
 	  sources bulk data; or it loops back a configurable number of
 	  sources bulk data; or it loops back a configurable number of
@@ -750,6 +762,8 @@ config USB_GADGET_TARGET
 
 
 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)"
+	select USB_U_SERIAL
+	select USB_F_ACM
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
 	help
 	help
 	  The Serial Gadget talks to the Linux-USB generic serial driver.
 	  The Serial Gadget talks to the Linux-USB generic serial driver.
@@ -803,6 +817,8 @@ config USB_CDC_COMPOSITE
 	tristate "CDC Composite Device (Ethernet and ACM)"
 	tristate "CDC Composite Device (Ethernet and ACM)"
 	depends on NET
 	depends on NET
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
+	select USB_U_SERIAL
+	select USB_F_ACM
 	help
 	help
 	  This driver provides two functions in one configuration:
 	  This driver provides two functions in one configuration:
 	  a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
 	  a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
@@ -818,6 +834,7 @@ config USB_G_NOKIA
 	tristate "Nokia composite gadget"
 	tristate "Nokia composite gadget"
 	depends on PHONET
 	depends on PHONET
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
+	select USB_U_SERIAL
 	help
 	help
 	  The Nokia composite gadget provides support for acm, obex
 	  The Nokia composite gadget provides support for acm, obex
 	  and phonet in only one composite gadget driver.
 	  and phonet in only one composite gadget driver.
@@ -829,6 +846,8 @@ config USB_G_ACM_MS
 	tristate "CDC Composite Device (ACM and mass storage)"
 	tristate "CDC Composite Device (ACM and mass storage)"
 	depends on BLOCK
 	depends on BLOCK
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
+	select USB_U_SERIAL
+	select USB_F_ACM
 	help
 	help
 	  This driver provides two functions in one configuration:
 	  This driver provides two functions in one configuration:
 	  a mass storage, and a CDC ACM (serial port) link.
 	  a mass storage, and a CDC ACM (serial port) link.
@@ -841,6 +860,8 @@ config USB_G_MULTI
 	depends on BLOCK && NET
 	depends on BLOCK && NET
 	select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
 	select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
 	select USB_LIBCOMPOSITE
 	select USB_LIBCOMPOSITE
+	select USB_U_SERIAL
+	select USB_F_ACM
 	help
 	help
 	  The Multifunction Composite Gadget provides Ethernet (RNDIS
 	  The Multifunction Composite Gadget provides Ethernet (RNDIS
 	  and/or CDC Ethernet), mass storage and ACM serial link
 	  and/or CDC Ethernet), mass storage and ACM serial link
@@ -916,6 +937,7 @@ config USB_G_DBGP_PRINTK
 
 
 config USB_G_DBGP_SERIAL
 config USB_G_DBGP_SERIAL
 	depends on USB_G_DBGP
 	depends on USB_G_DBGP
+	select USB_U_SERIAL
 	bool "serial"
 	bool "serial"
 	help
 	help
 	  Userland can interact using /dev/ttyGSxxx.
 	  Userland can interact using /dev/ttyGSxxx.

+ 7 - 1
drivers/usb/gadget/Makefile

@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 obj-$(CONFIG_USB_GADGET)	+= udc-core.o
 obj-$(CONFIG_USB_GADGET)	+= udc-core.o
 obj-$(CONFIG_USB_LIBCOMPOSITE)	+= libcomposite.o
 obj-$(CONFIG_USB_LIBCOMPOSITE)	+= libcomposite.o
 libcomposite-y			:= usbstring.o config.o epautoconf.o
 libcomposite-y			:= usbstring.o config.o epautoconf.o
-libcomposite-y			+= composite.o
+libcomposite-y			+= composite.o functions.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_NET2272)	+= net2272.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
@@ -74,3 +74,9 @@ obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
 obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
 obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
+
+# USB Functions
+obj-$(CONFIG_USB_F_ACM)		+= f_acm.o
+f_ss_lb-y			:= f_loopback.o f_sourcesink.o
+obj-$(CONFIG_USB_F_SS_LB)	+= f_ss_lb.o
+obj-$(CONFIG_USB_U_SERIAL)	+= u_serial.o

+ 31 - 11
drivers/usb/gadget/acm_ms.c

@@ -40,9 +40,6 @@
  * the runtime footprint, and giving us at least some parts of what
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
  */
-
-#include "u_serial.c"
-#include "f_acm.c"
 #include "f_mass_storage.c"
 #include "f_mass_storage.c"
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -112,12 +109,15 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
 static struct fsg_common fsg_common;
 static struct fsg_common fsg_common;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
-
+static unsigned char tty_line;
+static struct usb_function *f_acm;
+static struct usb_function_instance *f_acm_inst;
 /*
 /*
  * We _always_ have both ACM and mass storage functions.
  * We _always_ have both ACM and mass storage functions.
  */
  */
 static int __init acm_ms_do_config(struct usb_configuration *c)
 static int __init acm_ms_do_config(struct usb_configuration *c)
 {
 {
+	struct f_serial_opts *opts;
 	int	status;
 	int	status;
 
 
 	if (gadget_is_otg(c->cdev->gadget)) {
 	if (gadget_is_otg(c->cdev->gadget)) {
@@ -125,16 +125,35 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
 		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 	}
 
 
+	f_acm_inst = usb_get_function_instance("acm");
+	if (IS_ERR(f_acm_inst))
+		return PTR_ERR(f_acm_inst);
+
+	opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
+	opts->port_num = tty_line;
+
+	f_acm = usb_get_function(f_acm_inst);
+	if (IS_ERR(f_acm)) {
+		status = PTR_ERR(f_acm);
+		goto err_func;
+	}
 
 
-	status = acm_bind_config(c, 0);
+	status = usb_add_function(c, f_acm);
 	if (status < 0)
 	if (status < 0)
-		return status;
+		goto err_conf;
 
 
 	status = fsg_bind_config(c->cdev, c, &fsg_common);
 	status = fsg_bind_config(c->cdev, c, &fsg_common);
 	if (status < 0)
 	if (status < 0)
-		return status;
+		goto err_fsg;
 
 
 	return 0;
 	return 0;
+err_fsg:
+	usb_remove_function(c, f_acm);
+err_conf:
+	usb_put_function(f_acm);
+err_func:
+	usb_put_function_instance(f_acm_inst);
+	return status;
 }
 }
 
 
 static struct usb_configuration acm_ms_config_driver = {
 static struct usb_configuration acm_ms_config_driver = {
@@ -153,7 +172,7 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
 	void			*retp;
 	void			*retp;
 
 
 	/* set up serial link layer */
 	/* set up serial link layer */
-	status = gserial_setup(cdev->gadget, 1);
+	status = gserial_alloc_line(&tty_line);
 	if (status < 0)
 	if (status < 0)
 		return status;
 		return status;
 
 
@@ -189,14 +208,15 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
 fail1:
 fail1:
 	fsg_common_put(&fsg_common);
 	fsg_common_put(&fsg_common);
 fail0:
 fail0:
-	gserial_cleanup();
+	gserial_free_line(tty_line);
 	return status;
 	return status;
 }
 }
 
 
 static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
 static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
 {
 {
-	gserial_cleanup();
-
+	usb_put_function(f_acm);
+	usb_put_function_instance(f_acm_inst);
+	gserial_free_line(tty_line);
 	return 0;
 	return 0;
 }
 }
 
 

+ 14 - 45
drivers/usb/gadget/amd5536udc.c

@@ -1400,15 +1400,16 @@ 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 *, struct usb_gadget_driver *));
-static int amd5536_stop(struct usb_gadget_driver *driver);
+static int amd5536_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int amd5536_udc_stop(struct usb_gadget *g,
+		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,
+	.udc_start	= amd5536_udc_start,
+	.udc_stop	= amd5536_udc_stop,
 };
 };
 
 
 /* Setups endpoint parameters, adds endpoints to linked list */
 /* Setups endpoint parameters, adds endpoints to linked list */
@@ -1913,41 +1914,22 @@ static int setup_ep0(struct udc *dev)
 }
 }
 
 
 /* Called by gadget driver to register itself */
 /* Called by gadget driver to register itself */
-static int amd5536_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int amd5536_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct udc		*dev = udc;
-	int			retval;
+	struct udc *dev = to_amd5536_udc(g);
 	u32 tmp;
 	u32 tmp;
 
 
-	if (!driver || !bind || !driver->setup
-			|| driver->max_speed < USB_SPEED_HIGH)
-		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
-
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 	dev->gadget.dev.driver = &driver->driver;
 
 
-	retval = bind(&dev->gadget, driver);
-
 	/* Some gadget drivers use both ep0 directions.
 	/* Some gadget drivers use both ep0 directions.
 	 * NOTE: to gadget driver, ep0 is just one endpoint...
 	 * NOTE: to gadget driver, ep0 is just one endpoint...
 	 */
 	 */
 	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
 	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
 		dev->ep[UDC_EP0IN_IX].ep.driver_data;
 		dev->ep[UDC_EP0IN_IX].ep.driver_data;
 
 
-	if (retval) {
-		DBG(dev, "binding to %s returning %d\n",
-				driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
-
 	/* get ready for ep0 traffic */
 	/* get ready for ep0 traffic */
 	setup_ep0(dev);
 	setup_ep0(dev);
 
 
@@ -1969,14 +1951,9 @@ __acquires(dev->lock)
 {
 {
 	int tmp;
 	int tmp;
 
 
-	if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
-		spin_unlock(&dev->lock);
-		driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-	}
-
 	/* empty queues and init hardware */
 	/* empty queues and init hardware */
 	udc_basic_init(dev);
 	udc_basic_init(dev);
+
 	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
 	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
 		empty_req_queue(&dev->ep[tmp]);
 		empty_req_queue(&dev->ep[tmp]);
 
 
@@ -1984,23 +1961,18 @@ __acquires(dev->lock)
 }
 }
 
 
 /* Called by gadget driver to unregister itself */
 /* Called by gadget driver to unregister itself */
-static int amd5536_stop(struct usb_gadget_driver *driver)
+static int amd5536_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct udc	*dev = udc;
-	unsigned long	flags;
+	struct udc *dev = to_amd5536_udc(g);
+	unsigned long flags;
 	u32 tmp;
 	u32 tmp;
 
 
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver || !driver->unbind)
-		return -EINVAL;
-
 	spin_lock_irqsave(&dev->lock, flags);
 	spin_lock_irqsave(&dev->lock, flags);
 	udc_mask_unused_interrupts(dev);
 	udc_mask_unused_interrupts(dev);
 	shutdown(dev, driver);
 	shutdown(dev, driver);
 	spin_unlock_irqrestore(&dev->lock, flags);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 	dev->driver = NULL;
 
 
@@ -2009,9 +1981,6 @@ static int amd5536_stop(struct usb_gadget_driver *driver)
 	tmp |= AMD_BIT(UDC_DEVCTL_SD);
 	tmp |= AMD_BIT(UDC_DEVCTL_SD);
 	writel(tmp, &dev->regs->ctl);
 	writel(tmp, &dev->regs->ctl);
 
 
-
-	DBG(dev, "%s: unregistered\n", driver->driver.name);
-
 	return 0;
 	return 0;
 }
 }
 
 

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

@@ -563,6 +563,8 @@ struct udc {
 	u16				cur_alt;
 	u16				cur_alt;
 };
 };
 
 
+#define to_amd5536_udc(g)	(container_of((g), struct udc, gadget))
+
 /* setup request data */
 /* setup request data */
 union udc_setup_data {
 union udc_setup_data {
 	u32			data[2];
 	u32			data[2];

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

@@ -1621,8 +1621,7 @@ static void at91_vbus_timer(unsigned long data)
 	 * bus such as i2c or spi which may sleep, so schedule some work
 	 * bus such as i2c or spi which may sleep, so schedule some work
 	 * to read the vbus gpio
 	 * to read the vbus gpio
 	 */
 	 */
-	if (!work_pending(&udc->vbus_timer_work))
-		schedule_work(&udc->vbus_timer_work);
+	schedule_work(&udc->vbus_timer_work);
 }
 }
 
 
 static int at91_start(struct usb_gadget *gadget,
 static int at91_start(struct usb_gadget *gadget,
@@ -1739,7 +1738,7 @@ static int at91udc_probe(struct platform_device *pdev)
 
 
 	/* rm9200 needs manual D+ pullup; off by default */
 	/* rm9200 needs manual D+ pullup; off by default */
 	if (cpu_is_at91rm9200()) {
 	if (cpu_is_at91rm9200()) {
-		if (gpio_is_valid(udc->board.pullup_pin)) {
+		if (!gpio_is_valid(udc->board.pullup_pin)) {
 			DBG("no D+ pullup?\n");
 			DBG("no D+ pullup?\n");
 			retval = -ENODEV;
 			retval = -ENODEV;
 			goto fail0;
 			goto fail0;

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

@@ -42,9 +42,6 @@ USB_GADGET_COMPOSITE_OPTIONS();
  * the runtime footprint, and giving us at least some parts of what
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
  */
-
-#include "u_serial.c"
-#include "f_acm.c"
 #include "f_ecm.c"
 #include "f_ecm.c"
 #include "u_ether.c"
 #include "u_ether.c"
 
 
@@ -108,12 +105,16 @@ static struct usb_gadget_strings *dev_strings[] = {
 static u8 hostaddr[ETH_ALEN];
 static u8 hostaddr[ETH_ALEN];
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
+static struct usb_function *f_acm;
+static struct usb_function_instance *fi_serial;
 
 
+static unsigned char tty_line;
 /*
 /*
  * We _always_ have both CDC ECM and CDC ACM functions.
  * We _always_ have both CDC ECM and CDC ACM functions.
  */
  */
 static int __init cdc_do_config(struct usb_configuration *c)
 static int __init cdc_do_config(struct usb_configuration *c)
 {
 {
+	struct f_serial_opts *opts;
 	int	status;
 	int	status;
 
 
 	if (gadget_is_otg(c->cdev->gadget)) {
 	if (gadget_is_otg(c->cdev->gadget)) {
@@ -125,11 +126,26 @@ static int __init cdc_do_config(struct usb_configuration *c)
 	if (status < 0)
 	if (status < 0)
 		return status;
 		return status;
 
 
-	status = acm_bind_config(c, 0);
-	if (status < 0)
-		return status;
+	fi_serial = usb_get_function_instance("acm");
+	if (IS_ERR(fi_serial))
+		return PTR_ERR(fi_serial);
 
 
+	opts = container_of(fi_serial, struct f_serial_opts, func_inst);
+	opts->port_num = tty_line;
+
+	f_acm = usb_get_function(fi_serial);
+	if (IS_ERR(f_acm))
+		goto err_func_acm;
+
+	status = usb_add_function(c, f_acm);
+	if (status)
+		goto err_conf;
 	return 0;
 	return 0;
+err_conf:
+	usb_put_function(f_acm);
+err_func_acm:
+	usb_put_function_instance(fi_serial);
+	return status;
 }
 }
 
 
 static struct usb_configuration cdc_config_driver = {
 static struct usb_configuration cdc_config_driver = {
@@ -158,7 +174,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
 		return status;
 		return status;
 
 
 	/* set up serial link layer */
 	/* set up serial link layer */
-	status = gserial_setup(cdev->gadget, 1);
+	status = gserial_alloc_line(&tty_line);
 	if (status < 0)
 	if (status < 0)
 		goto fail0;
 		goto fail0;
 
 
@@ -184,7 +200,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
 	return 0;
 	return 0;
 
 
 fail1:
 fail1:
-	gserial_cleanup();
+	gserial_free_line(tty_line);
 fail0:
 fail0:
 	gether_cleanup();
 	gether_cleanup();
 	return status;
 	return status;
@@ -192,7 +208,9 @@ fail0:
 
 
 static int __exit cdc_unbind(struct usb_composite_dev *cdev)
 static int __exit cdc_unbind(struct usb_composite_dev *cdev)
 {
 {
-	gserial_cleanup();
+	usb_put_function(f_acm);
+	usb_put_function_instance(fi_serial);
+	gserial_free_line(tty_line);
 	gether_cleanup();
 	gether_cleanup();
 	return 0;
 	return 0;
 }
 }

+ 268 - 58
drivers/usb/gadget/composite.c

@@ -28,6 +28,12 @@
  * with the relevant device-wide data.
  * with the relevant device-wide data.
  */
  */
 
 
+static struct usb_gadget_strings **get_containers_gs(
+		struct usb_gadget_string_container *uc)
+{
+	return (struct usb_gadget_strings **)uc->stash;
+}
+
 /**
 /**
  * next_ep_desc() - advance to the next EP descriptor
  * next_ep_desc() - advance to the next EP descriptor
  * @t: currect pointer within descriptor array
  * @t: currect pointer within descriptor array
@@ -215,6 +221,18 @@ done:
 }
 }
 EXPORT_SYMBOL_GPL(usb_add_function);
 EXPORT_SYMBOL_GPL(usb_add_function);
 
 
+void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
+{
+	if (f->disable)
+		f->disable(f);
+
+	bitmap_zero(f->endpoints, 32);
+	list_del(&f->list);
+	if (f->unbind)
+		f->unbind(c, f);
+}
+EXPORT_SYMBOL_GPL(usb_remove_function);
+
 /**
 /**
  * usb_function_deactivate - prevent function and gadget enumeration
  * usb_function_deactivate - prevent function and gadget enumeration
  * @function: the function that isn't yet ready to respond
  * @function: the function that isn't yet ready to respond
@@ -320,6 +338,25 @@ int usb_interface_id(struct usb_configuration *config,
 }
 }
 EXPORT_SYMBOL_GPL(usb_interface_id);
 EXPORT_SYMBOL_GPL(usb_interface_id);
 
 
+static u8 encode_bMaxPower(enum usb_device_speed speed,
+		struct usb_configuration *c)
+{
+	unsigned val;
+
+	if (c->MaxPower)
+		val = c->MaxPower;
+	else
+		val = CONFIG_USB_GADGET_VBUS_DRAW;
+	if (!val)
+		return 0;
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		return DIV_ROUND_UP(val, 8);
+	default:
+		return DIV_ROUND_UP(val, 2);
+	};
+}
+
 static int config_buf(struct usb_configuration *config,
 static int config_buf(struct usb_configuration *config,
 		enum usb_device_speed speed, void *buf, u8 type)
 		enum usb_device_speed speed, void *buf, u8 type)
 {
 {
@@ -339,7 +376,7 @@ static int config_buf(struct usb_configuration *config,
 	c->bConfigurationValue = config->bConfigurationValue;
 	c->bConfigurationValue = config->bConfigurationValue;
 	c->iConfiguration = config->iConfiguration;
 	c->iConfiguration = config->iConfiguration;
 	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
 	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
-	c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+	c->bMaxPower = encode_bMaxPower(speed, config);
 
 
 	/* There may be e.g. OTG descriptors */
 	/* There may be e.g. OTG descriptors */
 	if (config->descriptors) {
 	if (config->descriptors) {
@@ -656,7 +693,7 @@ static int set_config(struct usb_composite_dev *cdev,
 	}
 	}
 
 
 	/* when we return, be sure our power usage is valid */
 	/* when we return, be sure our power usage is valid */
-	power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+	power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
 done:
 done:
 	usb_gadget_vbus_draw(gadget, power);
 	usb_gadget_vbus_draw(gadget, power);
 	if (result >= 0 && cdev->delayed_status)
 	if (result >= 0 && cdev->delayed_status)
@@ -664,6 +701,31 @@ done:
 	return result;
 	return result;
 }
 }
 
 
+int usb_add_config_only(struct usb_composite_dev *cdev,
+		struct usb_configuration *config)
+{
+	struct usb_configuration *c;
+
+	if (!config->bConfigurationValue)
+		return -EINVAL;
+
+	/* Prevent duplicate configuration identifiers */
+	list_for_each_entry(c, &cdev->configs, list) {
+		if (c->bConfigurationValue == config->bConfigurationValue)
+			return -EBUSY;
+	}
+
+	config->cdev = cdev;
+	list_add_tail(&config->list, &cdev->configs);
+
+	INIT_LIST_HEAD(&config->functions);
+	config->next_interface_id = 0;
+	memset(config->interface, 0, sizeof(config->interface));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_add_config_only);
+
 /**
 /**
  * usb_add_config() - add a configuration to a device.
  * usb_add_config() - add a configuration to a device.
  * @cdev: wraps the USB gadget
  * @cdev: wraps the USB gadget
@@ -684,30 +746,18 @@ int usb_add_config(struct usb_composite_dev *cdev,
 		int (*bind)(struct usb_configuration *))
 		int (*bind)(struct usb_configuration *))
 {
 {
 	int				status = -EINVAL;
 	int				status = -EINVAL;
-	struct usb_configuration	*c;
+
+	if (!bind)
+		goto done;
 
 
 	DBG(cdev, "adding config #%u '%s'/%p\n",
 	DBG(cdev, "adding config #%u '%s'/%p\n",
 			config->bConfigurationValue,
 			config->bConfigurationValue,
 			config->label, config);
 			config->label, config);
 
 
-	if (!config->bConfigurationValue || !bind)
+	status = usb_add_config_only(cdev, config);
+	if (status)
 		goto done;
 		goto done;
 
 
-	/* Prevent duplicate configuration identifiers */
-	list_for_each_entry(c, &cdev->configs, list) {
-		if (c->bConfigurationValue == config->bConfigurationValue) {
-			status = -EBUSY;
-			goto done;
-		}
-	}
-
-	config->cdev = cdev;
-	list_add_tail(&config->list, &cdev->configs);
-
-	INIT_LIST_HEAD(&config->functions);
-	config->next_interface_id = 0;
-	memset(config->interface, 0, sizeof(config->interface));
-
 	status = bind(config);
 	status = bind(config);
 	if (status < 0) {
 	if (status < 0) {
 		while (!list_empty(&config->functions)) {
 		while (!list_empty(&config->functions)) {
@@ -860,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
 		void *buf, u16 language, int id)
 		void *buf, u16 language, int id)
 {
 {
 	struct usb_composite_driver	*composite = cdev->driver;
 	struct usb_composite_driver	*composite = cdev->driver;
+	struct usb_gadget_string_container *uc;
 	struct usb_configuration	*c;
 	struct usb_configuration	*c;
 	struct usb_function		*f;
 	struct usb_function		*f;
 	int				len;
 	int				len;
@@ -892,6 +943,12 @@ static int get_string(struct usb_composite_dev *cdev,
 					collect_langs(sp, s->wData);
 					collect_langs(sp, s->wData);
 			}
 			}
 		}
 		}
+		list_for_each_entry(uc, &cdev->gstrings, list) {
+			struct usb_gadget_strings **sp;
+
+			sp = get_containers_gs(uc);
+			collect_langs(sp, s->wData);
+		}
 
 
 		for (len = 0; len <= 126 && s->wData[len]; len++)
 		for (len = 0; len <= 126 && s->wData[len]; len++)
 			continue;
 			continue;
@@ -902,6 +959,15 @@ static int get_string(struct usb_composite_dev *cdev,
 		return s->bLength;
 		return s->bLength;
 	}
 	}
 
 
+	list_for_each_entry(uc, &cdev->gstrings, list) {
+		struct usb_gadget_strings **sp;
+
+		sp = get_containers_gs(uc);
+		len = lookup_string(sp, buf, language, id);
+		if (len > 0)
+			return len;
+	}
+
 	/* String IDs are device-scoped, so we look up each string
 	/* String IDs are device-scoped, so we look up each string
 	 * table we're told about.  These lookups are infrequent;
 	 * table we're told about.  These lookups are infrequent;
 	 * simpler-is-better here.
 	 * simpler-is-better here.
@@ -987,6 +1053,119 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
 }
 }
 EXPORT_SYMBOL_GPL(usb_string_ids_tab);
 EXPORT_SYMBOL_GPL(usb_string_ids_tab);
 
 
+static struct usb_gadget_string_container *copy_gadget_strings(
+		struct usb_gadget_strings **sp, unsigned n_gstrings,
+		unsigned n_strings)
+{
+	struct usb_gadget_string_container *uc;
+	struct usb_gadget_strings **gs_array;
+	struct usb_gadget_strings *gs;
+	struct usb_string *s;
+	unsigned mem;
+	unsigned n_gs;
+	unsigned n_s;
+	void *stash;
+
+	mem = sizeof(*uc);
+	mem += sizeof(void *) * (n_gstrings + 1);
+	mem += sizeof(struct usb_gadget_strings) * n_gstrings;
+	mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings);
+	uc = kmalloc(mem, GFP_KERNEL);
+	if (!uc)
+		return ERR_PTR(-ENOMEM);
+	gs_array = get_containers_gs(uc);
+	stash = uc->stash;
+	stash += sizeof(void *) * (n_gstrings + 1);
+	for (n_gs = 0; n_gs < n_gstrings; n_gs++) {
+		struct usb_string *org_s;
+
+		gs_array[n_gs] = stash;
+		gs = gs_array[n_gs];
+		stash += sizeof(struct usb_gadget_strings);
+		gs->language = sp[n_gs]->language;
+		gs->strings = stash;
+		org_s = sp[n_gs]->strings;
+
+		for (n_s = 0; n_s < n_strings; n_s++) {
+			s = stash;
+			stash += sizeof(struct usb_string);
+			if (org_s->s)
+				s->s = org_s->s;
+			else
+				s->s = "";
+			org_s++;
+		}
+		s = stash;
+		s->s = NULL;
+		stash += sizeof(struct usb_string);
+
+	}
+	gs_array[n_gs] = NULL;
+	return uc;
+}
+
+/**
+ * usb_gstrings_attach() - attach gadget strings to a cdev and assign ids
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * and attached.
+ * @sp: an array of usb_gadget_strings to attach.
+ * @n_strings: number of entries in each usb_strings array (sp[]->strings)
+ *
+ * This function will create a deep copy of usb_gadget_strings and usb_string
+ * and attach it to the cdev. The actual string (usb_string.s) will not be
+ * copied but only a referenced will be made. The struct usb_gadget_strings
+ * array may contain multiple languges and should be NULL terminated.
+ * The ->language pointer of each struct usb_gadget_strings has to contain the
+ * same amount of entries.
+ * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
+ * usb_string entry of es-ES containts the translation of the first usb_string
+ * entry of en-US. Therefore both entries become the same id assign.
+ */
+struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
+		struct usb_gadget_strings **sp, unsigned n_strings)
+{
+	struct usb_gadget_string_container *uc;
+	struct usb_gadget_strings **n_gs;
+	unsigned n_gstrings = 0;
+	unsigned i;
+	int ret;
+
+	for (i = 0; sp[i]; i++)
+		n_gstrings++;
+
+	if (!n_gstrings)
+		return ERR_PTR(-EINVAL);
+
+	uc = copy_gadget_strings(sp, n_gstrings, n_strings);
+	if (IS_ERR(uc))
+		return ERR_PTR(PTR_ERR(uc));
+
+	n_gs = get_containers_gs(uc);
+	ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
+	if (ret)
+		goto err;
+
+	for (i = 1; i < n_gstrings; i++) {
+		struct usb_string *m_s;
+		struct usb_string *s;
+		unsigned n;
+
+		m_s = n_gs[0]->strings;
+		s = n_gs[i]->strings;
+		for (n = 0; n < n_strings; n++) {
+			s->id = m_s->id;
+			s++;
+			m_s++;
+		}
+	}
+	list_add_tail(&uc->list, &cdev->gstrings);
+	return n_gs[0]->strings;
+err:
+	kfree(uc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_gstrings_attach);
+
 /**
 /**
  * usb_string_ids_n() - allocate unused string IDs in batch
  * usb_string_ids_n() - allocate unused string IDs in batch
  * @c: the device whose string descriptor IDs are being allocated
  * @c: the device whose string descriptor IDs are being allocated
@@ -1033,7 +1212,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
  * housekeeping for the gadget function we're implementing.  Most of
  * housekeeping for the gadget function we're implementing.  Most of
  * the work is in config and function specific setup.
  * the work is in config and function specific setup.
  */
  */
-static int
+int
 composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 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);
@@ -1300,7 +1479,7 @@ done:
 	return value;
 	return value;
 }
 }
 
 
-static void composite_disconnect(struct usb_gadget *gadget)
+void composite_disconnect(struct usb_gadget *gadget)
 {
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	unsigned long			flags;
 	unsigned long			flags;
@@ -1330,8 +1509,7 @@ static ssize_t composite_show_suspended(struct device *dev,
 
 
 static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
 static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
 
 
-static void
-composite_unbind(struct usb_gadget *gadget)
+static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 
 
@@ -1348,19 +1526,21 @@ composite_unbind(struct usb_gadget *gadget)
 				struct usb_configuration, list);
 				struct usb_configuration, list);
 		remove_config(cdev, c);
 		remove_config(cdev, c);
 	}
 	}
-	if (cdev->driver->unbind)
+	if (cdev->driver->unbind && unbind_driver)
 		cdev->driver->unbind(cdev);
 		cdev->driver->unbind(cdev);
 
 
-	if (cdev->req) {
-		kfree(cdev->req->buf);
-		usb_ep_free_request(gadget->ep0, cdev->req);
-	}
-	device_remove_file(&gadget->dev, &dev_attr_suspended);
+	composite_dev_cleanup(cdev);
+
 	kfree(cdev->def_manufacturer);
 	kfree(cdev->def_manufacturer);
 	kfree(cdev);
 	kfree(cdev);
 	set_gadget_data(gadget, NULL);
 	set_gadget_data(gadget, NULL);
 }
 }
 
 
+static void composite_unbind(struct usb_gadget *gadget)
+{
+	__composite_unbind(gadget, true);
+}
+
 static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
 static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
 		const struct usb_device_descriptor *old)
 		const struct usb_device_descriptor *old)
 {
 {
@@ -1399,34 +1579,25 @@ static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
 		new->iProduct = iProduct;
 		new->iProduct = iProduct;
 }
 }
 
 
-static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
-{
-	return container_of(gdrv, struct usb_composite_driver, gadget_driver);
-}
-
-static int composite_bind(struct usb_gadget *gadget,
-		struct usb_gadget_driver *gdriver)
+int composite_dev_prepare(struct usb_composite_driver *composite,
+		struct usb_composite_dev *cdev)
 {
 {
-	struct usb_composite_dev	*cdev;
-	struct usb_composite_driver	*composite = to_cdriver(gdriver);
-	int				status = -ENOMEM;
-
-	cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
-	if (!cdev)
-		return status;
-
-	spin_lock_init(&cdev->lock);
-	cdev->gadget = gadget;
-	set_gadget_data(gadget, cdev);
-	INIT_LIST_HEAD(&cdev->configs);
+	struct usb_gadget *gadget = cdev->gadget;
+	int ret = -ENOMEM;
 
 
 	/* preallocate control response and buffer */
 	/* preallocate control response and buffer */
 	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!cdev->req)
 	if (!cdev->req)
-		goto fail;
+		return -ENOMEM;
+
 	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
 	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
 	if (!cdev->req->buf)
 	if (!cdev->req->buf)
 		goto fail;
 		goto fail;
+
+	ret = device_create_file(&gadget->dev, &dev_attr_suspended);
+	if (ret)
+		goto fail_dev;
+
 	cdev->req->complete = composite_setup_complete;
 	cdev->req->complete = composite_setup_complete;
 	gadget->ep0->driver_data = cdev;
 	gadget->ep0->driver_data = cdev;
 
 
@@ -1444,7 +1615,51 @@ static int composite_bind(struct usb_gadget *gadget,
 	 * we force endpoints to start unassigned; few controller
 	 * we force endpoints to start unassigned; few controller
 	 * drivers will zero ep->driver_data.
 	 * drivers will zero ep->driver_data.
 	 */
 	 */
-	usb_ep_autoconfig_reset(cdev->gadget);
+	usb_ep_autoconfig_reset(gadget);
+	return 0;
+fail_dev:
+	kfree(cdev->req->buf);
+fail:
+	usb_ep_free_request(gadget->ep0, cdev->req);
+	cdev->req = NULL;
+	return ret;
+}
+
+void composite_dev_cleanup(struct usb_composite_dev *cdev)
+{
+	struct usb_gadget_string_container *uc, *tmp;
+
+	list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
+		list_del(&uc->list);
+		kfree(uc);
+	}
+	if (cdev->req) {
+		kfree(cdev->req->buf);
+		usb_ep_free_request(cdev->gadget->ep0, cdev->req);
+	}
+	device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
+}
+
+static int composite_bind(struct usb_gadget *gadget,
+		struct usb_gadget_driver *gdriver)
+{
+	struct usb_composite_dev	*cdev;
+	struct usb_composite_driver	*composite = to_cdriver(gdriver);
+	int				status = -ENOMEM;
+
+	cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
+	if (!cdev)
+		return status;
+
+	spin_lock_init(&cdev->lock);
+	cdev->gadget = gadget;
+	set_gadget_data(gadget, cdev);
+	INIT_LIST_HEAD(&cdev->configs);
+	INIT_LIST_HEAD(&cdev->gstrings);
+
+	status = composite_dev_prepare(composite, cdev);
+	if (status)
+		goto fail;
 
 
 	/* composite gadget needs to assign strings for whole device (like
 	/* composite gadget needs to assign strings for whole device (like
 	 * serial number), register function drivers, potentially update
 	 * serial number), register function drivers, potentially update
@@ -1460,16 +1675,11 @@ static int composite_bind(struct usb_gadget *gadget,
 	if (composite->needs_serial && !cdev->desc.iSerialNumber)
 	if (composite->needs_serial && !cdev->desc.iSerialNumber)
 		WARNING(cdev, "userspace failed to provide iSerialNumber\n");
 		WARNING(cdev, "userspace failed to provide iSerialNumber\n");
 
 
-	/* finish up */
-	status = device_create_file(&gadget->dev, &dev_attr_suspended);
-	if (status)
-		goto fail;
-
 	INFO(cdev, "%s ready\n", composite->name);
 	INFO(cdev, "%s ready\n", composite->name);
 	return 0;
 	return 0;
 
 
 fail:
 fail:
-	composite_unbind(gadget);
+	__composite_unbind(gadget, false);
 	return status;
 	return status;
 }
 }
 
 
@@ -1518,10 +1728,10 @@ composite_resume(struct usb_gadget *gadget)
 				f->resume(f);
 				f->resume(f);
 		}
 		}
 
 
-		maxpower = cdev->config->bMaxPower;
+		maxpower = cdev->config->MaxPower;
 
 
 		usb_gadget_vbus_draw(gadget, maxpower ?
 		usb_gadget_vbus_draw(gadget, maxpower ?
-			(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
+			maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
 	}
 	}
 
 
 	cdev->suspended = 0;
 	cdev->suspended = 0;

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

@@ -13,9 +13,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
 
 
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-#include "u_serial.c"
-#endif
+#include "u_serial.h"
 
 
 #define DRIVER_VENDOR_ID	0x0525 /* NetChip */
 #define DRIVER_VENDOR_ID	0x0525 /* NetChip */
 #define DRIVER_PRODUCT_ID	0xc0de /* undefined */
 #define DRIVER_PRODUCT_ID	0xc0de /* undefined */
@@ -233,6 +231,10 @@ static void dbgp_unbind(struct usb_gadget *gadget)
 	gadget->ep0->driver_data = NULL;
 	gadget->ep0->driver_data = NULL;
 }
 }
 
 
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+static unsigned char tty_line;
+#endif
+
 static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 {
 {
 	int stp;
 	int stp;
@@ -270,7 +272,7 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 	dbgp.serial->in->desc = &i_desc;
 	dbgp.serial->in->desc = &i_desc;
 	dbgp.serial->out->desc = &o_desc;
 	dbgp.serial->out->desc = &o_desc;
 
 
-	if (gserial_setup(gadget, 1) < 0) {
+	if (gserial_alloc_line(&tty_line)) {
 		stp = 3;
 		stp = 3;
 		goto fail_3;
 		goto fail_3;
 	}
 	}
@@ -379,7 +381,7 @@ static int dbgp_setup(struct usb_gadget *gadget,
 #ifdef CONFIG_USB_G_DBGP_PRINTK
 #ifdef CONFIG_USB_G_DBGP_PRINTK
 		err = dbgp_enable_ep();
 		err = dbgp_enable_ep();
 #else
 #else
-		err = gserial_connect(dbgp.serial, 0);
+		err = gserial_connect(dbgp.serial, tty_line);
 #endif
 #endif
 		if (err < 0)
 		if (err < 0)
 			goto fail;
 			goto fail;
@@ -422,7 +424,7 @@ static void __exit dbgp_exit(void)
 {
 {
 	usb_gadget_unregister_driver(&dbgp_driver);
 	usb_gadget_unregister_driver(&dbgp_driver);
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 #ifdef CONFIG_USB_G_DBGP_SERIAL
-	gserial_cleanup();
+	gserial_free_line(tty_line);
 #endif
 #endif
 }
 }
 
 

+ 104 - 49
drivers/usb/gadget/f_acm.c

@@ -16,7 +16,9 @@
 
 
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/device.h>
+#include <linux/err.h>
 
 
 #include "u_serial.h"
 #include "u_serial.h"
 #include "gadget_chips.h"
 #include "gadget_chips.h"
@@ -283,7 +285,6 @@ static struct usb_string acm_string_defs[] = {
 	[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
 	[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
 	[ACM_DATA_IDX].s = "CDC ACM Data",
 	[ACM_DATA_IDX].s = "CDC ACM Data",
 	[ACM_IAD_IDX ].s = "CDC Serial",
 	[ACM_IAD_IDX ].s = "CDC Serial",
-	{  /* ZEROES END LIST */ },
 };
 };
 
 
 static struct usb_gadget_strings acm_string_table = {
 static struct usb_gadget_strings acm_string_table = {
@@ -605,9 +606,23 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_acm		*acm = func_to_acm(f);
 	struct f_acm		*acm = func_to_acm(f);
+	struct usb_string	*us;
 	int			status;
 	int			status;
 	struct usb_ep		*ep;
 	struct usb_ep		*ep;
 
 
+	/* REVISIT might want instance-specific strings to help
+	 * distinguish instances ...
+	 */
+
+	/* maybe allocate device-global string IDs, and patch descriptors */
+	us = usb_gstrings_attach(cdev, acm_strings,
+			ARRAY_SIZE(acm_string_defs));
+	if (IS_ERR(us))
+		return PTR_ERR(us);
+	acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id;
+	acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
+	acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;
+
 	/* allocate instance-specific interface IDs, and patch descriptors */
 	/* allocate instance-specific interface IDs, and patch descriptors */
 	status = usb_interface_id(c, f);
 	status = usb_interface_id(c, f);
 	if (status < 0)
 	if (status < 0)
@@ -700,24 +715,42 @@ fail:
 	return status;
 	return status;
 }
 }
 
 
+static struct f_acm *acm_alloc_basic_func(void)
+{
+	struct f_acm	*acm;
+
+	acm = kzalloc(sizeof(*acm), GFP_KERNEL);
+	if (!acm)
+		return NULL;
+
+	spin_lock_init(&acm->lock);
+
+	acm->port.connect = acm_connect;
+	acm->port.disconnect = acm_disconnect;
+	acm->port.send_break = acm_send_break;
+
+	acm->port.func.name = "acm";
+	/* descriptors are per-instance copies */
+	acm->port.func.bind = acm_bind;
+	acm->port.func.set_alt = acm_set_alt;
+	acm->port.func.setup = acm_setup;
+	acm->port.func.disable = acm_disable;
+
+	return acm;
+}
+
+#ifdef USB_FACM_INCLUDED
 static void
 static void
-acm_unbind(struct usb_configuration *c, struct usb_function *f)
+acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 {
 	struct f_acm		*acm = func_to_acm(f);
 	struct f_acm		*acm = func_to_acm(f);
 
 
-	acm_string_defs[0].id = 0;
 	usb_free_all_descriptors(f);
 	usb_free_all_descriptors(f);
-	gs_free_req(acm->notify, acm->notify_req);
+	if (acm->notify_req)
+		gs_free_req(acm->notify, acm->notify_req);
 	kfree(acm);
 	kfree(acm);
 }
 }
 
 
-/* Some controllers can't support CDC ACM ... */
-static inline bool can_support_cdc(struct usb_configuration *c)
-{
-	/* everything else is *probably* fine ... */
-	return true;
-}
-
 /**
 /**
  * acm_bind_config - add a CDC ACM function to a configuration
  * acm_bind_config - add a CDC ACM function to a configuration
  * @c: the configuration to support the CDC ACM instance
  * @c: the configuration to support the CDC ACM instance
@@ -726,58 +759,80 @@ static inline bool can_support_cdc(struct usb_configuration *c)
  *
  *
  * Returns zero on success, else negative errno.
  * Returns zero on success, else negative errno.
  *
  *
- * Caller must have called @gserial_setup() with enough ports to
- * handle all the ones it binds.  Caller is also responsible
- * for calling @gserial_cleanup() before module unload.
  */
  */
 int acm_bind_config(struct usb_configuration *c, u8 port_num)
 int acm_bind_config(struct usb_configuration *c, u8 port_num)
 {
 {
 	struct f_acm	*acm;
 	struct f_acm	*acm;
 	int		status;
 	int		status;
 
 
-	if (!can_support_cdc(c))
-		return -EINVAL;
-
-	/* REVISIT might want instance-specific strings to help
-	 * distinguish instances ...
-	 */
-
-	/* maybe allocate device-global string IDs, and patch descriptors */
-	if (acm_string_defs[0].id == 0) {
-		status = usb_string_ids_tab(c->cdev, acm_string_defs);
-		if (status < 0)
-			return status;
-		acm_control_interface_desc.iInterface =
-			acm_string_defs[ACM_CTRL_IDX].id;
-		acm_data_interface_desc.iInterface =
-			acm_string_defs[ACM_DATA_IDX].id;
-		acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id;
-	}
-
 	/* allocate and initialize one new instance */
 	/* allocate and initialize one new instance */
-	acm = kzalloc(sizeof *acm, GFP_KERNEL);
+	acm = acm_alloc_basic_func();
 	if (!acm)
 	if (!acm)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	spin_lock_init(&acm->lock);
-
 	acm->port_num = port_num;
 	acm->port_num = port_num;
-
-	acm->port.connect = acm_connect;
-	acm->port.disconnect = acm_disconnect;
-	acm->port.send_break = acm_send_break;
-
-	acm->port.func.name = "acm";
-	acm->port.func.strings = acm_strings;
-	/* descriptors are per-instance copies */
-	acm->port.func.bind = acm_bind;
-	acm->port.func.unbind = acm_unbind;
-	acm->port.func.set_alt = acm_set_alt;
-	acm->port.func.setup = acm_setup;
-	acm->port.func.disable = acm_disable;
+	acm->port.func.unbind = acm_old_unbind;
 
 
 	status = usb_add_function(c, &acm->port.func);
 	status = usb_add_function(c, &acm->port.func);
 	if (status)
 	if (status)
 		kfree(acm);
 		kfree(acm);
 	return status;
 	return status;
 }
 }
+
+#else
+
+static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_acm		*acm = func_to_acm(f);
+
+	acm_string_defs[0].id = 0;
+	usb_free_all_descriptors(f);
+	if (acm->notify_req)
+		gs_free_req(acm->notify, acm->notify_req);
+}
+
+static void acm_free_func(struct usb_function *f)
+{
+	struct f_acm		*acm = func_to_acm(f);
+
+	kfree(acm);
+}
+
+static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
+{
+	struct f_serial_opts *opts;
+	struct f_acm *acm;
+
+	acm = acm_alloc_basic_func();
+	if (!acm)
+		return ERR_PTR(-ENOMEM);
+
+	opts = container_of(fi, struct f_serial_opts, func_inst);
+	acm->port_num = opts->port_num;
+	acm->port.func.unbind = acm_unbind;
+	acm->port.func.free_func = acm_free_func;
+
+	return &acm->port.func;
+}
+
+static void acm_free_instance(struct usb_function_instance *fi)
+{
+	struct f_serial_opts *opts;
+
+	opts = container_of(fi, struct f_serial_opts, func_inst);
+	kfree(opts);
+}
+
+static struct usb_function_instance *acm_alloc_instance(void)
+{
+	struct f_serial_opts *opts;
+
+	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	if (!opts)
+		return ERR_PTR(-ENOMEM);
+	opts->func_inst.free_func_inst = acm_free_instance;
+	return &opts->func_inst;
+}
+DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
+MODULE_LICENSE("GPL");
+#endif

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

@@ -1103,8 +1103,8 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
 		return 0;
 		return 0;
 
 
 	for (;;) {
 	for (;;) {
-		char *end, *eq, *comma;
 		unsigned long value;
 		unsigned long value;
+		char *eq, *comma;
 
 
 		/* Option limit */
 		/* Option limit */
 		comma = strchr(opts, ',');
 		comma = strchr(opts, ',');
@@ -1120,8 +1120,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
 		*eq = 0;
 		*eq = 0;
 
 
 		/* Parse value */
 		/* Parse value */
-		value = simple_strtoul(eq + 1, &end, 0);
-		if (unlikely(*end != ',' && *end != 0)) {
+		if (kstrtoul(eq + 1, 0, &value)) {
 			pr_err("%s: invalid value: %s\n", opts, eq + 1);
 			pr_err("%s: invalid value: %s\n", opts, eq + 1);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}

+ 54 - 49
drivers/usb/gadget/f_loopback.c

@@ -15,10 +15,11 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/usb/composite.h>
 
 
 #include "g_zero.h"
 #include "g_zero.h"
-#include "gadget_chips.h"
-
 
 
 /*
 /*
  * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
  * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
@@ -44,9 +45,8 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f)
 	return container_of(f, struct f_loopback, function);
 	return container_of(f, struct f_loopback, function);
 }
 }
 
 
-static unsigned qlen = 32;
-module_param(qlen, uint, 0);
-MODULE_PARM_DESC(qlenn, "depth of loopback queue");
+static unsigned qlen;
+static unsigned buflen;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -171,8 +171,7 @@ static struct usb_gadget_strings *loopback_strings[] = {
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int __init
-loopback_bind(struct usb_configuration *c, struct usb_function *f)
+static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
 {
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_loopback	*loop = func_to_loop(f);
 	struct f_loopback	*loop = func_to_loop(f);
@@ -185,6 +184,12 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
 		return id;
 		return id;
 	loopback_intf.bInterfaceNumber = id;
 	loopback_intf.bInterfaceNumber = id;
 
 
+	id = usb_string_id(cdev);
+	if (id < 0)
+		return id;
+	strings_loopback[0].id = id;
+	loopback_intf.iInterface = id;
+
 	/* allocate endpoints */
 	/* allocate endpoints */
 
 
 	loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
 	loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
@@ -223,8 +228,7 @@ autoconf_fail:
 	return 0;
 	return 0;
 }
 }
 
 
-static void
-loopback_unbind(struct usb_configuration *c, struct usb_function *f)
+static void lb_free_func(struct usb_function *f)
 {
 {
 	usb_free_all_descriptors(f);
 	usb_free_all_descriptors(f);
 	kfree(func_to_loop(f));
 	kfree(func_to_loop(f));
@@ -366,63 +370,64 @@ static void loopback_disable(struct usb_function *f)
 	disable_loopback(loop);
 	disable_loopback(loop);
 }
 }
 
 
-/*-------------------------------------------------------------------------*/
-
-static int __init loopback_bind_config(struct usb_configuration *c)
+static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
 {
 {
 	struct f_loopback	*loop;
 	struct f_loopback	*loop;
-	int			status;
+	struct f_lb_opts	*lb_opts;
 
 
 	loop = kzalloc(sizeof *loop, GFP_KERNEL);
 	loop = kzalloc(sizeof *loop, GFP_KERNEL);
 	if (!loop)
 	if (!loop)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
+
+	lb_opts = container_of(fi, struct f_lb_opts, func_inst);
+	buflen = lb_opts->bulk_buflen;
+	qlen = lb_opts->qlen;
+	if (!qlen)
+		qlen = 32;
 
 
 	loop->function.name = "loopback";
 	loop->function.name = "loopback";
 	loop->function.bind = loopback_bind;
 	loop->function.bind = loopback_bind;
-	loop->function.unbind = loopback_unbind;
 	loop->function.set_alt = loopback_set_alt;
 	loop->function.set_alt = loopback_set_alt;
 	loop->function.disable = loopback_disable;
 	loop->function.disable = loopback_disable;
+	loop->function.strings = loopback_strings;
 
 
-	status = usb_add_function(c, &loop->function);
-	if (status)
-		kfree(loop);
-	return status;
-}
+	loop->function.free_func = lb_free_func;
 
 
-static struct usb_configuration loopback_driver = {
-	.label		= "loopback",
-	.strings	= loopback_strings,
-	.bConfigurationValue = 2,
-	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,
-	/* .iConfiguration = DYNAMIC */
-};
+	return &loop->function;
+}
 
 
-/**
- * loopback_add - add a loopback testing configuration to a device
- * @cdev: the device to support the loopback configuration
- */
-int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
+static void lb_free_instance(struct usb_function_instance *fi)
 {
 {
-	int id;
+	struct f_lb_opts *lb_opts;
 
 
-	/* allocate string ID(s) */
-	id = usb_string_id(cdev);
-	if (id < 0)
-		return id;
-	strings_loopback[0].id = id;
+	lb_opts = container_of(fi, struct f_lb_opts, func_inst);
+	kfree(lb_opts);
+}
 
 
-	loopback_intf.iInterface = id;
-	loopback_driver.iConfiguration = id;
+static struct usb_function_instance *loopback_alloc_instance(void)
+{
+	struct f_lb_opts *lb_opts;
 
 
-	/* support autoresume for remote wakeup testing */
-	if (autoresume)
-		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
+	if (!lb_opts)
+		return ERR_PTR(-ENOMEM);
+	lb_opts->func_inst.free_func_inst = lb_free_instance;
+	return  &lb_opts->func_inst;
+}
+DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 
 
-	/* support OTG systems */
-	if (gadget_is_otg(cdev->gadget)) {
-		loopback_driver.descriptors = otg_desc;
-		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	}
+int __init lb_modinit(void)
+{
+	int ret;
 
 
-	return usb_add_config(cdev, &loopback_driver, loopback_bind_config);
+	ret = usb_function_register(&Loopbackusb_func);
+	if (ret)
+		return ret;
+	return ret;
 }
 }
+void __exit lb_modexit(void)
+{
+	usb_function_unregister(&Loopbackusb_func);
+}
+
+MODULE_LICENSE("GPL");

+ 5 - 32
drivers/usb/gadget/f_mass_storage.c

@@ -246,20 +246,6 @@ struct fsg_operations {
 	 * set).
 	 * set).
 	 */
 	 */
 	int (*thread_exits)(struct fsg_common *common);
 	int (*thread_exits)(struct fsg_common *common);
-
-	/*
-	 * Called prior to ejection.  Negative return means error,
-	 * zero means to continue with ejection, positive means not to
-	 * eject.
-	 */
-	int (*pre_eject)(struct fsg_common *common,
-			 struct fsg_lun *lun, int num);
-	/*
-	 * Called after ejection.  Negative return means error, zero
-	 * or positive is just a success.
-	 */
-	int (*post_eject)(struct fsg_common *common,
-			  struct fsg_lun *lun, int num);
 };
 };
 
 
 /* Data shared by all the FSG instances. */
 /* Data shared by all the FSG instances. */
@@ -1374,26 +1360,13 @@ static int do_start_stop(struct fsg_common *common)
 	if (!loej)
 	if (!loej)
 		return 0;
 		return 0;
 
 
-	/* Simulate an unload/eject */
-	if (common->ops && common->ops->pre_eject) {
-		int r = common->ops->pre_eject(common, curlun,
-					       curlun - common->luns);
-		if (unlikely(r < 0))
-			return r;
-		else if (r)
-			return 0;
-	}
-
 	up_read(&common->filesem);
 	up_read(&common->filesem);
 	down_write(&common->filesem);
 	down_write(&common->filesem);
 	fsg_lun_close(curlun);
 	fsg_lun_close(curlun);
 	up_write(&common->filesem);
 	up_write(&common->filesem);
 	down_read(&common->filesem);
 	down_read(&common->filesem);
 
 
-	return common->ops && common->ops->post_eject
-		? min(0, common->ops->post_eject(common, curlun,
-						 curlun - common->luns))
-		: 0;
+	return 0;
 }
 }
 
 
 static int do_prevent_allow(struct fsg_common *common)
 static int do_prevent_allow(struct fsg_common *common)
@@ -1718,7 +1691,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 			 int needs_medium, const char *name)
 			 int needs_medium, const char *name)
 {
 {
 	int			i;
 	int			i;
-	int			lun = common->cmnd[1] >> 5;
+	unsigned int		lun = common->cmnd[1] >> 5;
 	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
 	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
 	char			hdlen[20];
 	char			hdlen[20];
 	struct fsg_lun		*curlun;
 	struct fsg_lun		*curlun;
@@ -1784,7 +1757,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 
 
 	/* Check that the LUN values are consistent */
 	/* Check that the LUN values are consistent */
 	if (common->lun != lun)
 	if (common->lun != lun)
-		DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
+		DBG(common, "using LUN %u from CBW, not LUN %u from CDB\n",
 		    common->lun, lun);
 		    common->lun, lun);
 
 
 	/* Check the LUN */
 	/* Check the LUN */
@@ -1804,7 +1777,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 		 */
 		 */
 		if (common->cmnd[0] != INQUIRY &&
 		if (common->cmnd[0] != INQUIRY &&
 		    common->cmnd[0] != REQUEST_SENSE) {
 		    common->cmnd[0] != REQUEST_SENSE) {
-			DBG(common, "unsupported LUN %d\n", common->lun);
+			DBG(common, "unsupported LUN %u\n", common->lun);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 	}
 	}
@@ -2196,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 	if (common->data_size == 0)
 	if (common->data_size == 0)
 		common->data_dir = DATA_DIR_NONE;
 		common->data_dir = DATA_DIR_NONE;
 	common->lun = cbw->Lun;
 	common->lun = cbw->Lun;
-	if (common->lun >= 0 && common->lun < common->nluns)
+	if (common->lun < common->nluns)
 		common->curlun = &common->luns[common->lun];
 		common->curlun = &common->luns[common->lun];
 	else
 	else
 		common->curlun = NULL;
 		common->curlun = NULL;

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

@@ -56,8 +56,9 @@ struct f_ncm {
 	u8				notify_state;
 	u8				notify_state;
 	bool				is_open;
 	bool				is_open;
 
 
-	struct ndp_parser_opts		*parser_opts;
+	const struct ndp_parser_opts	*parser_opts;
 	bool				is_crc;
 	bool				is_crc;
+	u32				ndp_sign;
 
 
 	/*
 	/*
 	 * for notification, it is accessed from both
 	 * for notification, it is accessed from both
@@ -390,8 +391,8 @@ struct ndp_parser_opts {
 		.next_fp_index = 2,				\
 		.next_fp_index = 2,				\
 	}
 	}
 
 
-static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
+static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
 
 
 static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
 static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
 {
 {
@@ -732,8 +733,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 		default:
 		default:
 			goto invalid;
 			goto invalid;
 		}
 		}
-		ncm->parser_opts->ndp_sign &= ~NCM_NDP_HDR_CRC_MASK;
-		ncm->parser_opts->ndp_sign |= ndp_hdr_crc;
+		ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc;
 		value = 0;
 		value = 0;
 		break;
 		break;
 	}
 	}
@@ -875,7 +875,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
 	int		ndp_align;
 	int		ndp_align;
 	int		ndp_pad;
 	int		ndp_pad;
 	unsigned	max_size = ncm->port.fixed_in_len;
 	unsigned	max_size = ncm->port.fixed_in_len;
-	struct ndp_parser_opts *opts = ncm->parser_opts;
+	const struct ndp_parser_opts *opts = ncm->parser_opts;
 	unsigned	crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
 	unsigned	crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
 
 
 	div = le16_to_cpu(ntb_parameters.wNdpInDivisor);
 	div = le16_to_cpu(ntb_parameters.wNdpInDivisor);
@@ -921,7 +921,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
 	tmp = (void *)tmp + ndp_pad;
 	tmp = (void *)tmp + ndp_pad;
 
 
 	/* NDP */
 	/* NDP */
-	put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */
+	put_unaligned_le32(ncm->ndp_sign, tmp); /* dwSignature */
 	tmp += 2;
 	tmp += 2;
 	/* wLength */
 	/* wLength */
 	put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++);
 	put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++);
@@ -965,7 +965,7 @@ static int ncm_unwrap_ntb(struct gether *port,
 	struct sk_buff	*skb2;
 	struct sk_buff	*skb2;
 	int		ret = -EINVAL;
 	int		ret = -EINVAL;
 	unsigned	max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
 	unsigned	max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
-	struct ndp_parser_opts *opts = ncm->parser_opts;
+	const struct ndp_parser_opts *opts = ncm->parser_opts;
 	unsigned	crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
 	unsigned	crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
 	int		dgram_counter;
 	int		dgram_counter;
 
 
@@ -1002,7 +1002,7 @@ static int ncm_unwrap_ntb(struct gether *port,
 
 
 	/* walk through NDP */
 	/* walk through NDP */
 	tmp = ((void *)skb->data) + index;
 	tmp = ((void *)skb->data) + index;
-	if (get_unaligned_le32(tmp) != opts->ndp_sign) {
+	if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
 		INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
 		INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
 		goto err;
 		goto err;
 	}
 	}

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

@@ -406,10 +406,6 @@ static inline bool can_support_obex(struct usb_configuration *c)
  * Context: single threaded during gadget setup
  * Context: single threaded during gadget setup
  *
  *
  * Returns zero on success, else negative errno.
  * Returns zero on success, else negative errno.
- *
- * Caller must have called @gserial_setup() with enough ports to
- * handle all the ones it binds.  Caller is also responsible
- * for calling @gserial_cleanup() before module unload.
  */
  */
 int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
 int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
 {
 {

+ 0 - 4
drivers/usb/gadget/f_serial.c

@@ -260,10 +260,6 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
  * Context: single threaded during gadget setup
  * Context: single threaded during gadget setup
  *
  *
  * Returns zero on success, else negative errno.
  * Returns zero on success, else negative errno.
- *
- * Caller must have called @gserial_setup() with enough ports to
- * handle all the ones it binds.  Caller is also responsible
- * for calling @gserial_cleanup() before module unload.
  */
  */
 int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
 int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
 {
 {

+ 125 - 75
drivers/usb/gadget/f_sourcesink.c

@@ -16,11 +16,12 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/usb/composite.h>
+#include <linux/err.h>
 
 
 #include "g_zero.h"
 #include "g_zero.h"
 #include "gadget_chips.h"
 #include "gadget_chips.h"
 
 
-
 /*
 /*
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
  * controller drivers.
  * controller drivers.
@@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
 }
 }
 
 
 static unsigned pattern;
 static unsigned pattern;
-module_param(pattern, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
-
-static unsigned isoc_interval = 4;
-module_param(isoc_interval, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_interval, "1 - 16");
-
-static unsigned isoc_maxpacket = 1024;
-module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
+static unsigned isoc_interval;
+static unsigned isoc_maxpacket;
 static unsigned isoc_mult;
 static unsigned isoc_mult;
-module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
-
 static unsigned isoc_maxburst;
 static unsigned isoc_maxburst;
-module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
+static unsigned buflen;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -313,7 +301,57 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int __init
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
+{
+	struct usb_request      *req;
+
+	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (req) {
+		if (len)
+			req->length = len;
+		else
+			req->length = buflen;
+		req->buf = kmalloc(req->length, GFP_ATOMIC);
+		if (!req->buf) {
+			usb_ep_free_request(ep, req);
+			req = NULL;
+		}
+	}
+	return req;
+}
+
+void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+	kfree(req->buf);
+	usb_ep_free_request(ep, req);
+}
+
+static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
+{
+	int			value;
+
+	if (ep->driver_data) {
+		value = usb_ep_disable(ep);
+		if (value < 0)
+			DBG(cdev, "disable %s --> %d\n",
+					ep->name, value);
+		ep->driver_data = NULL;
+	}
+}
+
+void disable_endpoints(struct usb_composite_dev *cdev,
+		struct usb_ep *in, struct usb_ep *out,
+		struct usb_ep *iso_in, struct usb_ep *iso_out)
+{
+	disable_ep(cdev, in);
+	disable_ep(cdev, out);
+	if (iso_in)
+		disable_ep(cdev, iso_in);
+	if (iso_out)
+		disable_ep(cdev, iso_out);
+}
+
+static int
 sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 {
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
@@ -450,7 +488,7 @@ no_iso:
 }
 }
 
 
 static void
 static void
-sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
+sourcesink_free_func(struct usb_function *f)
 {
 {
 	usb_free_all_descriptors(f);
 	usb_free_all_descriptors(f);
 	kfree(func_to_ss(f));
 	kfree(func_to_ss(f));
@@ -531,8 +569,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 			check_read_data(ss, req);
 			check_read_data(ss, req);
 			if (pattern != 2)
 			if (pattern != 2)
 				memset(req->buf, 0x55, req->length);
 				memset(req->buf, 0x55, req->length);
-		} else
-			reinit_write_data(ep, req);
+		}
 		break;
 		break;
 
 
 	/* this endpoint is normally active while we're configured */
 	/* this endpoint is normally active while we're configured */
@@ -758,31 +795,10 @@ static void sourcesink_disable(struct usb_function *f)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int __init sourcesink_bind_config(struct usb_configuration *c)
-{
-	struct f_sourcesink	*ss;
-	int			status;
-
-	ss = kzalloc(sizeof *ss, GFP_KERNEL);
-	if (!ss)
-		return -ENOMEM;
-
-	ss->function.name = "source/sink";
-	ss->function.bind = sourcesink_bind;
-	ss->function.unbind = sourcesink_unbind;
-	ss->function.set_alt = sourcesink_set_alt;
-	ss->function.get_alt = sourcesink_get_alt;
-	ss->function.disable = sourcesink_disable;
-
-	status = usb_add_function(c, &ss->function);
-	if (status)
-		kfree(ss);
-	return status;
-}
-
-static int sourcesink_setup(struct usb_configuration *c,
+static int sourcesink_setup(struct usb_function *f,
 		const struct usb_ctrlrequest *ctrl)
 		const struct usb_ctrlrequest *ctrl)
 {
 {
+	struct usb_configuration        *c = f->config;
 	struct usb_request	*req = c->cdev->req;
 	struct usb_request	*req = c->cdev->req;
 	int			value = -EOPNOTSUPP;
 	int			value = -EOPNOTSUPP;
 	u16			w_index = le16_to_cpu(ctrl->wIndex);
 	u16			w_index = le16_to_cpu(ctrl->wIndex);
@@ -851,42 +867,76 @@ unknown:
 	return value;
 	return value;
 }
 }
 
 
-static struct usb_configuration sourcesink_driver = {
-	.label			= "source/sink",
-	.strings		= sourcesink_strings,
-	.setup			= sourcesink_setup,
-	.bConfigurationValue	= 3,
-	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
-	/* .iConfiguration	= DYNAMIC */
-};
+static struct usb_function *source_sink_alloc_func(
+		struct usb_function_instance *fi)
+{
+	struct f_sourcesink     *ss;
+	struct f_ss_opts	*ss_opts;
 
 
-/**
- * sourcesink_add - add a source/sink testing configuration to a device
- * @cdev: the device to support the configuration
- */
-int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
+	ss = kzalloc(sizeof(*ss), GFP_KERNEL);
+	if (!ss)
+		return NULL;
+
+	ss_opts =  container_of(fi, struct f_ss_opts, func_inst);
+	pattern = ss_opts->pattern;
+	isoc_interval = ss_opts->isoc_interval;
+	isoc_maxpacket = ss_opts->isoc_maxpacket;
+	isoc_mult = ss_opts->isoc_mult;
+	isoc_maxburst = ss_opts->isoc_maxburst;
+	buflen = ss_opts->bulk_buflen;
+
+	ss->function.name = "source/sink";
+	ss->function.bind = sourcesink_bind;
+	ss->function.set_alt = sourcesink_set_alt;
+	ss->function.get_alt = sourcesink_get_alt;
+	ss->function.disable = sourcesink_disable;
+	ss->function.setup = sourcesink_setup;
+	ss->function.strings = sourcesink_strings;
+
+	ss->function.free_func = sourcesink_free_func;
+
+	return &ss->function;
+}
+
+static void acm_free_instance(struct usb_function_instance *fi)
 {
 {
-	int id;
+	struct f_ss_opts *ss_opts;
 
 
-	/* allocate string ID(s) */
-	id = usb_string_id(cdev);
-	if (id < 0)
-		return id;
-	strings_sourcesink[0].id = id;
+	ss_opts = container_of(fi, struct f_ss_opts, func_inst);
+	kfree(ss_opts);
+}
 
 
-	source_sink_intf_alt0.iInterface = id;
-	source_sink_intf_alt1.iInterface = id;
-	sourcesink_driver.iConfiguration = id;
+static struct usb_function_instance *source_sink_alloc_inst(void)
+{
+	struct f_ss_opts *ss_opts;
 
 
-	/* support autoresume for remote wakeup testing */
-	if (autoresume)
-		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);
+	if (!ss_opts)
+		return ERR_PTR(-ENOMEM);
+	ss_opts->func_inst.free_func_inst = acm_free_instance;
+	return &ss_opts->func_inst;
+}
+DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,
+		source_sink_alloc_func);
 
 
-	/* support OTG systems */
-	if (gadget_is_otg(cdev->gadget)) {
-		sourcesink_driver.descriptors = otg_desc;
-		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	}
+static int __init sslb_modinit(void)
+{
+	int ret;
 
 
-	return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);
+	ret = usb_function_register(&SourceSinkusb_func);
+	if (ret)
+		return ret;
+	ret = lb_modinit();
+	if (ret)
+		usb_function_unregister(&SourceSinkusb_func);
+	return ret;
+}
+static void __exit sslb_modexit(void)
+{
+	usb_function_unregister(&SourceSinkusb_func);
+	lb_modexit();
 }
 }
+module_init(sslb_modinit);
+module_exit(sslb_modexit);
+
+MODULE_LICENSE("GPL");

+ 2 - 7
drivers/usb/gadget/f_uac2.c

@@ -260,19 +260,14 @@ static int
 uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 {
 	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
 	struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
-	struct audio_dev *agdev = uac2_to_agdev(uac2);
 	struct uac2_rtd_params *prm;
 	struct uac2_rtd_params *prm;
 	unsigned long flags;
 	unsigned long flags;
-	struct usb_ep *ep;
 	int err = 0;
 	int err = 0;
 
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ep = agdev->in_ep;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		prm = &uac2->p_prm;
 		prm = &uac2->p_prm;
-	} else {
-		ep = agdev->out_ep;
+	else
 		prm = &uac2->c_prm;
 		prm = &uac2->c_prm;
-	}
 
 
 	spin_lock_irqsave(&prm->lock, flags);
 	spin_lock_irqsave(&prm->lock, flags);
 
 

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

@@ -16,6 +16,7 @@
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <linux/string.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/video.h>
 #include <linux/usb/video.h>
@@ -419,7 +420,7 @@ uvc_register_video(struct uvc_device *uvc)
 	video->parent = &cdev->gadget->dev;
 	video->parent = &cdev->gadget->dev;
 	video->fops = &uvc_v4l2_fops;
 	video->fops = &uvc_v4l2_fops;
 	video->release = video_device_release;
 	video->release = video_device_release;
-	strncpy(video->name, cdev->gadget->name, sizeof(video->name));
+	strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
 
 
 	uvc->vdev = video;
 	uvc->vdev = video;
 	video_set_drvdata(video, uvc);
 	video_set_drvdata(video, uvc);

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

@@ -1894,7 +1894,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver);
 		struct usb_gadget_driver *driver);
 
 
 /* defined in usb_gadget.h */
 /* defined in usb_gadget.h */
-static struct usb_gadget_ops qe_gadget_ops = {
+static const struct usb_gadget_ops qe_gadget_ops = {
 	.get_frame = qe_get_frame,
 	.get_frame = qe_get_frame,
 	.udc_start = fsl_qe_start,
 	.udc_start = fsl_qe_start,
 	.udc_stop = fsl_qe_stop,
 	.udc_stop = fsl_qe_stop,

+ 12 - 48
drivers/usb/gadget/fsl_udc_core.c

@@ -1255,19 +1255,20 @@ 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 *, struct usb_gadget_driver *));
-static int fsl_stop(struct usb_gadget_driver *driver);
+static int fsl_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int fsl_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
 /* defined in gadget.h */
 /* defined in gadget.h */
-static struct usb_gadget_ops fsl_gadget_ops = {
+static const struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.get_frame = fsl_get_frame,
 	.wakeup = fsl_wakeup,
 	.wakeup = fsl_wakeup,
 /*	.set_selfpowered = fsl_set_selfpowered,	*/ /* Always selfpowered */
 /*	.set_selfpowered = fsl_set_selfpowered,	*/ /* Always selfpowered */
 	.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,
+	.udc_start = fsl_udc_start,
+	.udc_stop = fsl_udc_stop,
 };
 };
 
 
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
@@ -1951,22 +1952,12 @@ 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
 *----------------------------------------------------------------*/
 *----------------------------------------------------------------*/
-static int fsl_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int fsl_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	int retval = -ENODEV;
+	int retval = 0;
 	unsigned long flags = 0;
 	unsigned long flags = 0;
 
 
-	if (!udc_controller)
-		return -ENODEV;
-
-	if (!driver || driver->max_speed < USB_SPEED_FULL
-			|| !bind || !driver->disconnect || !driver->setup)
-		return -EINVAL;
-
-	if (udc_controller->driver)
-		return -EBUSY;
-
 	/* lock is needed but whether should use this lock or another */
 	/* lock is needed but whether should use this lock or another */
 	spin_lock_irqsave(&udc_controller->lock, flags);
 	spin_lock_irqsave(&udc_controller->lock, flags);
 
 
@@ -1976,15 +1967,6 @@ static int fsl_start(struct usb_gadget_driver *driver,
 	udc_controller->gadget.dev.driver = &driver->driver;
 	udc_controller->gadget.dev.driver = &driver->driver;
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 
 
-	/* bind udc driver to gadget driver */
-	retval = bind(&udc_controller->gadget, driver);
-	if (retval) {
-		VDBG("bind to %s --> %d", driver->driver.name, retval);
-		udc_controller->gadget.dev.driver = NULL;
-		udc_controller->driver = NULL;
-		goto out;
-	}
-
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 		/* Suspend the controller until OTG enable it */
 		/* Suspend the controller until OTG enable it */
 		udc_controller->stopped = 1;
 		udc_controller->stopped = 1;
@@ -2010,28 +1992,17 @@ static int fsl_start(struct usb_gadget_driver *driver,
 		udc_controller->ep0_state = WAIT_FOR_SETUP;
 		udc_controller->ep0_state = WAIT_FOR_SETUP;
 		udc_controller->ep0_dir = 0;
 		udc_controller->ep0_dir = 0;
 	}
 	}
-	printk(KERN_INFO "%s: bind to driver %s\n",
-			udc_controller->gadget.name, driver->driver.name);
 
 
-out:
-	if (retval)
-		printk(KERN_WARNING "gadget driver register failed %d\n",
-		       retval);
 	return retval;
 	return retval;
 }
 }
 
 
 /* Disconnect from gadget driver */
 /* Disconnect from gadget driver */
-static int fsl_stop(struct usb_gadget_driver *driver)
+static int fsl_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
 	struct fsl_ep *loop_ep;
 	struct fsl_ep *loop_ep;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!udc_controller)
-		return -ENODEV;
-
-	if (!driver || driver != udc_controller->driver || !driver->unbind)
-		return -EINVAL;
-
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 
 
@@ -2052,16 +2023,9 @@ static int fsl_stop(struct usb_gadget_driver *driver)
 		nuke(loop_ep, -ESHUTDOWN);
 		nuke(loop_ep, -ESHUTDOWN);
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 
 
-	/* report disconnect; the controller is already quiesced */
-	driver->disconnect(&udc_controller->gadget);
-
-	/* unbind gadget and unhook driver. */
-	driver->unbind(&udc_controller->gadget);
 	udc_controller->gadget.dev.driver = NULL;
 	udc_controller->gadget.dev.driver = NULL;
 	udc_controller->driver = NULL;
 	udc_controller->driver = NULL;
 
 
-	printk(KERN_WARNING "unregistered gadget driver '%s'\n",
-	       driver->driver.name);
 	return 0;
 	return 0;
 }
 }
 
 

+ 116 - 0
drivers/usb/gadget/functions.c

@@ -0,0 +1,116 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <linux/usb/composite.h>
+
+static LIST_HEAD(func_list);
+static DEFINE_MUTEX(func_lock);
+
+static struct usb_function_instance *try_get_usb_function_instance(const char *name)
+{
+	struct usb_function_driver *fd;
+	struct usb_function_instance *fi;
+
+	fi = ERR_PTR(-ENOENT);
+	mutex_lock(&func_lock);
+	list_for_each_entry(fd, &func_list, list) {
+
+		if (strcmp(name, fd->name))
+			continue;
+
+		if (!try_module_get(fd->mod)) {
+			fi = ERR_PTR(-EBUSY);
+			break;
+		}
+		fi = fd->alloc_inst();
+		if (IS_ERR(fi))
+			module_put(fd->mod);
+		else
+			fi->fd = fd;
+		break;
+	}
+	mutex_unlock(&func_lock);
+	return fi;
+}
+
+struct usb_function_instance *usb_get_function_instance(const char *name)
+{
+	struct usb_function_instance *fi;
+	int ret;
+
+	fi = try_get_usb_function_instance(name);
+	if (!IS_ERR(fi))
+		return fi;
+	ret = PTR_ERR(fi);
+	if (ret != -ENOENT)
+		return fi;
+	ret = request_module("usbfunc:%s", name);
+	if (ret < 0)
+		return ERR_PTR(ret);
+	return try_get_usb_function_instance(name);
+}
+EXPORT_SYMBOL_GPL(usb_get_function_instance);
+
+struct usb_function *usb_get_function(struct usb_function_instance *fi)
+{
+	struct usb_function *f;
+
+	f = fi->fd->alloc_func(fi);
+	if (IS_ERR(f))
+		return f;
+	f->fi = fi;
+	return f;
+}
+EXPORT_SYMBOL_GPL(usb_get_function);
+
+void usb_put_function_instance(struct usb_function_instance *fi)
+{
+	struct module *mod;
+
+	if (!fi)
+		return;
+
+	mod = fi->fd->mod;
+	fi->free_func_inst(fi);
+	module_put(mod);
+}
+EXPORT_SYMBOL_GPL(usb_put_function_instance);
+
+void usb_put_function(struct usb_function *f)
+{
+	if (!f)
+		return;
+
+	f->free_func(f);
+}
+EXPORT_SYMBOL_GPL(usb_put_function);
+
+int usb_function_register(struct usb_function_driver *newf)
+{
+	struct usb_function_driver *fd;
+	int ret;
+
+	ret = -EEXIST;
+
+	mutex_lock(&func_lock);
+	list_for_each_entry(fd, &func_list, list) {
+		if (!strcmp(fd->name, newf->name))
+			goto out;
+	}
+	ret = 0;
+	list_add_tail(&newf->list, &func_list);
+out:
+	mutex_unlock(&func_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_function_register);
+
+void usb_function_unregister(struct usb_function_driver *fd)
+{
+	mutex_lock(&func_lock);
+	list_del(&fd->list);
+	mutex_unlock(&func_lock);
+}
+EXPORT_SYMBOL_GPL(usb_function_unregister);

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

@@ -1308,65 +1308,28 @@ static void init_controller(struct fusb300 *fusb300)
 	iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
 	iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
 }
 }
 /*------------------------------------------------------------------------*/
 /*------------------------------------------------------------------------*/
-static struct fusb300 *the_controller;
-
-static int fusb300_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int fusb300_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct fusb300 *fusb300 = the_controller;
-	int retval;
-
-	if (!driver
-			|| driver->max_speed < USB_SPEED_FULL
-			|| !bind
-			|| !driver->setup)
-		return -EINVAL;
-
-	if (!fusb300)
-		return -ENODEV;
-
-	if (fusb300->driver)
-		return -EBUSY;
+	struct fusb300 *fusb300 = to_fusb300(g);
 
 
 	/* hook up the driver */
 	/* hook up the driver */
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	fusb300->driver = driver;
 	fusb300->driver = driver;
 	fusb300->gadget.dev.driver = &driver->driver;
 	fusb300->gadget.dev.driver = &driver->driver;
 
 
-	retval = device_add(&fusb300->gadget.dev);
-	if (retval) {
-		pr_err("device_add error (%d)\n", retval);
-		goto error;
-	}
-
-	retval = bind(&fusb300->gadget, driver);
-	if (retval) {
-		pr_err("bind to driver error (%d)\n", retval);
-		device_del(&fusb300->gadget.dev);
-		goto error;
-	}
-
 	return 0;
 	return 0;
-
-error:
-	fusb300->driver = NULL;
-	fusb300->gadget.dev.driver = NULL;
-
-	return retval;
 }
 }
 
 
-static int fusb300_udc_stop(struct usb_gadget_driver *driver)
+static int fusb300_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct fusb300 *fusb300 = the_controller;
-
-	if (driver != fusb300->driver || !driver->unbind)
-		return -EINVAL;
+	struct fusb300 *fusb300 = to_fusb300(g);
 
 
 	driver->unbind(&fusb300->gadget);
 	driver->unbind(&fusb300->gadget);
 	fusb300->gadget.dev.driver = NULL;
 	fusb300->gadget.dev.driver = NULL;
 
 
 	init_controller(fusb300);
 	init_controller(fusb300);
-	device_del(&fusb300->gadget.dev);
 	fusb300->driver = NULL;
 	fusb300->driver = NULL;
 
 
 	return 0;
 	return 0;
@@ -1378,10 +1341,10 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct usb_gadget_ops fusb300_gadget_ops = {
+static const struct usb_gadget_ops fusb300_gadget_ops = {
 	.pullup		= fusb300_udc_pullup,
 	.pullup		= fusb300_udc_pullup,
-	.start		= fusb300_udc_start,
-	.stop		= fusb300_udc_stop,
+	.udc_start	= fusb300_udc_start,
+	.udc_stop	= fusb300_udc_stop,
 };
 };
 
 
 static int __exit fusb300_remove(struct platform_device *pdev)
 static int __exit fusb300_remove(struct platform_device *pdev)
@@ -1505,8 +1468,6 @@ static int __init fusb300_probe(struct platform_device *pdev)
 	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
 	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
 	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
 	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
 
 
-	the_controller = fusb300;
-
 	fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
 	fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
 				GFP_KERNEL);
 				GFP_KERNEL);
 	if (fusb300->ep0_req == NULL)
 	if (fusb300->ep0_req == NULL)
@@ -1517,9 +1478,19 @@ static int __init fusb300_probe(struct platform_device *pdev)
 	if (ret)
 	if (ret)
 		goto err_add_udc;
 		goto err_add_udc;
 
 
+	ret = device_add(&fusb300->gadget.dev);
+	if (ret) {
+		pr_err("device_add error (%d)\n", ret);
+		goto err_add_device;
+	}
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 
 
 	return 0;
 	return 0;
+
+err_add_device:
+	usb_del_gadget_udc(&fusb300->gadget);
+
 err_add_udc:
 err_add_udc:
 	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
 	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
 
 

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

@@ -673,4 +673,6 @@ struct fusb300 {
 	u8			reenum;		/* if re-enumeration */
 	u8			reenum;		/* if re-enumeration */
 };
 };
 
 
+#define to_fusb300(g)		(container_of((g), struct fusb300, gadget))
+
 #endif
 #endif

+ 27 - 8
drivers/usb/gadget/g_zero.h

@@ -6,11 +6,34 @@
 #ifndef __G_ZERO_H
 #ifndef __G_ZERO_H
 #define __G_ZERO_H
 #define __G_ZERO_H
 
 
-#include <linux/usb/composite.h>
+struct usb_zero_options {
+	unsigned pattern;
+	unsigned isoc_interval;
+	unsigned isoc_maxpacket;
+	unsigned isoc_mult;
+	unsigned isoc_maxburst;
+	unsigned bulk_buflen;
+	unsigned qlen;
+};
 
 
-/* global state */
-extern unsigned buflen;
-extern const struct usb_descriptor_header *otg_desc[];
+struct f_ss_opts {
+	struct usb_function_instance func_inst;
+	unsigned pattern;
+	unsigned isoc_interval;
+	unsigned isoc_maxpacket;
+	unsigned isoc_mult;
+	unsigned isoc_maxburst;
+	unsigned bulk_buflen;
+};
+
+struct f_lb_opts {
+	struct usb_function_instance func_inst;
+	unsigned bulk_buflen;
+	unsigned qlen;
+};
+
+void lb_modexit(void);
+int lb_modinit(void);
 
 
 /* common utilities */
 /* common utilities */
 struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
 struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
@@ -19,8 +42,4 @@ void disable_endpoints(struct usb_composite_dev *cdev,
 		struct usb_ep *in, struct usb_ep *out,
 		struct usb_ep *in, struct usb_ep *out,
 		struct usb_ep *iso_in, struct usb_ep *iso_out);
 		struct usb_ep *iso_in, struct usb_ep *iso_out);
 
 
-/* configuration-specific linkup */
-int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
-int loopback_add(struct usb_composite_dev *cdev, bool autoresume);
-
 #endif /* __G_ZERO_H */
 #endif /* __G_ZERO_H */

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

@@ -125,7 +125,7 @@ static struct usb_configuration midi_config = {
 	.bConfigurationValue = 1,
 	.bConfigurationValue = 1,
 	/* .iConfiguration = DYNAMIC */
 	/* .iConfiguration = DYNAMIC */
 	.bmAttributes	= USB_CONFIG_ATT_ONE,
 	.bmAttributes	= USB_CONFIG_ATT_ONE,
-	.bMaxPower	= CONFIG_USB_GADGET_VBUS_DRAW / 2,
+	.MaxPower	= CONFIG_USB_GADGET_VBUS_DRAW,
 };
 };
 
 
 static int __init midi_bind_config(struct usb_configuration *c)
 static int __init midi_bind_config(struct usb_configuration *c)

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

@@ -993,14 +993,15 @@ 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 *, struct usb_gadget_driver *));
-static int goku_stop(struct usb_gadget_driver *driver);
+static int goku_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int goku_udc_stop(struct usb_gadget *g,
+		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,
+	.udc_start	= goku_udc_start,
+	.udc_stop	= goku_udc_stop,
 	// no remote wakeup
 	// no remote wakeup
 	// not selfpowered
 	// not selfpowered
 };
 };
@@ -1339,50 +1340,28 @@ static void udc_enable(struct goku_udc *dev)
  * - one function driver, initted second
  * - one function driver, initted second
  */
  */
 
 
-static struct goku_udc	*the_controller;
-
 /* when a driver is successfully registered, it will receive
 /* when a driver is successfully registered, it will receive
  * control requests including set_configuration(), which enables
  * control requests including set_configuration(), which enables
  * non-control requests.  then usb traffic follows until a
  * non-control requests.  then usb traffic follows until a
  * 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.
  */
  */
-static int goku_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int goku_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct goku_udc	*dev = the_controller;
-	int			retval;
-
-	if (!driver
-			|| driver->max_speed < USB_SPEED_FULL
-			|| !bind
-			|| !driver->disconnect
-			|| !driver->setup)
-		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
+	struct goku_udc	*dev = to_goku_udc(g);
 
 
 	/* hook up the driver */
 	/* hook up the driver */
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 	dev->gadget.dev.driver = &driver->driver;
-	retval = bind(&dev->gadget, driver);
-	if (retval) {
-		DBG(dev, "bind to driver %s --> error %d\n",
-				driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
 
 
-	/* then enable host detection and ep0; and we're ready
+	/*
+	 * then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
 	 * for set_configuration as well as eventual disconnect.
 	 */
 	 */
 	udc_enable(dev);
 	udc_enable(dev);
 
 
-	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1400,35 +1379,23 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
 	udc_reset (dev);
 	udc_reset (dev);
 	for (i = 0; i < 4; i++)
 	for (i = 0; i < 4; i++)
 		nuke(&dev->ep [i], -ESHUTDOWN);
 		nuke(&dev->ep [i], -ESHUTDOWN);
-	if (driver) {
-		spin_unlock(&dev->lock);
-		driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-	}
 
 
 	if (dev->driver)
 	if (dev->driver)
 		udc_enable(dev);
 		udc_enable(dev);
 }
 }
 
 
-static int goku_stop(struct usb_gadget_driver *driver)
+static int goku_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct goku_udc	*dev = the_controller;
+	struct goku_udc	*dev = to_goku_udc(g);
 	unsigned long	flags;
 	unsigned long	flags;
 
 
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver || !driver->unbind)
-		return -EINVAL;
-
 	spin_lock_irqsave(&dev->lock, flags);
 	spin_lock_irqsave(&dev->lock, flags);
 	dev->driver = NULL;
 	dev->driver = NULL;
 	stop_activity(dev, driver);
 	stop_activity(dev, driver);
 	spin_unlock_irqrestore(&dev->lock, flags);
 	spin_unlock_irqrestore(&dev->lock, flags);
-
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->gadget.dev.driver = NULL;
 
 
-	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1754,7 +1721,6 @@ static void goku_remove(struct pci_dev *pdev)
 
 
 	pci_set_drvdata(pdev, NULL);
 	pci_set_drvdata(pdev, NULL);
 	dev->regs = NULL;
 	dev->regs = NULL;
-	the_controller = NULL;
 
 
 	INFO(dev, "unbind\n");
 	INFO(dev, "unbind\n");
 }
 }
@@ -1770,13 +1736,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	void __iomem		*base = NULL;
 	void __iomem		*base = NULL;
 	int			retval;
 	int			retval;
 
 
-	/* if you want to support more than one controller in a system,
-	 * usb_gadget_driver_{register,unregister}() must change.
-	 */
-	if (the_controller) {
-		pr_warning("ignoring %s\n", pci_name(pdev));
-		return -EBUSY;
-	}
 	if (!pdev->irq) {
 	if (!pdev->irq) {
 		printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
 		printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
 		retval = -ENODEV;
 		retval = -ENODEV;
@@ -1851,7 +1810,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
 	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
 #endif
 #endif
 
 
-	the_controller = dev;
 	retval = device_register(&dev->gadget.dev);
 	retval = device_register(&dev->gadget.dev);
 	if (retval) {
 	if (retval) {
 		put_device(&dev->gadget.dev);
 		put_device(&dev->gadget.dev);

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

@@ -261,6 +261,7 @@ struct goku_udc {
 	/* statistics... */
 	/* statistics... */
 	unsigned long			irqs;
 	unsigned long			irqs;
 };
 };
+#define to_goku_udc(g)		(container_of((g), struct goku_udc, gadget))
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 

+ 20 - 52
drivers/usb/gadget/m66592-udc.c

@@ -1463,42 +1463,16 @@ static struct usb_ep_ops m66592_ep_ops = {
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
-static struct m66592 *the_controller;
-
-static int m66592_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int m66592_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct m66592 *m66592 = the_controller;
-	int retval;
-
-	if (!driver
-			|| driver->max_speed < USB_SPEED_HIGH
-			|| !bind
-			|| !driver->setup)
-		return -EINVAL;
-	if (!m66592)
-		return -ENODEV;
-	if (m66592->driver)
-		return -EBUSY;
+	struct m66592 *m66592 = to_m66592(g);
 
 
 	/* hook up the driver */
 	/* hook up the driver */
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	m66592->driver = driver;
 	m66592->driver = driver;
 	m66592->gadget.dev.driver = &driver->driver;
 	m66592->gadget.dev.driver = &driver->driver;
 
 
-	retval = device_add(&m66592->gadget.dev);
-	if (retval) {
-		pr_err("device_add error (%d)\n", retval);
-		goto error;
-	}
-
-	retval = bind(&m66592->gadget, driver);
-	if (retval) {
-		pr_err("bind to driver error (%d)\n", retval);
-		device_del(&m66592->gadget.dev);
-		goto error;
-	}
-
 	m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 	m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 	if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
 	if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
 		m66592_start_xclock(m66592);
 		m66592_start_xclock(m66592);
@@ -1510,26 +1484,12 @@ static int m66592_start(struct usb_gadget_driver *driver,
 	}
 	}
 
 
 	return 0;
 	return 0;
-
-error:
-	m66592->driver = NULL;
-	m66592->gadget.dev.driver = NULL;
-
-	return retval;
 }
 }
 
 
-static int m66592_stop(struct usb_gadget_driver *driver)
+static int m66592_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct m66592 *m66592 = the_controller;
-	unsigned long flags;
-
-	if (driver != m66592->driver || !driver->unbind)
-		return -EINVAL;
-
-	spin_lock_irqsave(&m66592->lock, flags);
-	if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
-		m66592_usb_disconnect(m66592);
-	spin_unlock_irqrestore(&m66592->lock, flags);
+	struct m66592 *m66592 = to_m66592(g);
 
 
 	m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 
 
@@ -1539,8 +1499,8 @@ static int m66592_stop(struct usb_gadget_driver *driver)
 	init_controller(m66592);
 	init_controller(m66592);
 	disable_controller(m66592);
 	disable_controller(m66592);
 
 
-	device_del(&m66592->gadget.dev);
 	m66592->driver = NULL;
 	m66592->driver = NULL;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1566,10 +1526,10 @@ static int m66592_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct usb_gadget_ops m66592_gadget_ops = {
+static const struct usb_gadget_ops m66592_gadget_ops = {
 	.get_frame		= m66592_get_frame,
 	.get_frame		= m66592_get_frame,
-	.start			= m66592_start,
-	.stop			= m66592_stop,
+	.udc_start		= m66592_udc_start,
+	.udc_stop		= m66592_udc_stop,
 	.pullup			= m66592_pullup,
 	.pullup			= m66592_pullup,
 };
 };
 
 
@@ -1578,6 +1538,7 @@ 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);
 	usb_del_gadget_udc(&m66592->gadget);
+	device_del(&m66592->gadget.dev);
 
 
 	del_timer_sync(&m66592->timer);
 	del_timer_sync(&m66592->timer);
 	iounmap(m66592->reg);
 	iounmap(m66592->reg);
@@ -1706,8 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev)
 	m66592->pipenum2ep[0] = &m66592->ep[0];
 	m66592->pipenum2ep[0] = &m66592->ep[0];
 	m66592->epaddr2ep[0] = &m66592->ep[0];
 	m66592->epaddr2ep[0] = &m66592->ep[0];
 
 
-	the_controller = m66592;
-
 	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
 	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
 	if (m66592->ep0_req == NULL)
 	if (m66592->ep0_req == NULL)
 		goto clean_up3;
 		goto clean_up3;
@@ -1715,6 +1674,12 @@ static int __init m66592_probe(struct platform_device *pdev)
 
 
 	init_controller(m66592);
 	init_controller(m66592);
 
 
+	ret = device_add(&m66592->gadget.dev);
+	if (ret) {
+		pr_err("device_add error (%d)\n", ret);
+		goto err_device_add;
+	}
+
 	ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
 	ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
 	if (ret)
 	if (ret)
 		goto err_add_udc;
 		goto err_add_udc;
@@ -1723,6 +1688,9 @@ static int __init m66592_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
 err_add_udc:
 err_add_udc:
+	device_del(&m66592->gadget.dev);
+
+err_device_add:
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 
 
 clean_up3:
 clean_up3:

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

@@ -492,6 +492,7 @@ struct m66592 {
 	int isochronous;
 	int isochronous;
 	int num_dma;
 	int num_dma;
 };
 };
+#define to_m66592(g)	(container_of((g), struct m66592, gadget))
 
 
 #define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
 #define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
 #define m66592_to_gadget(m66592) (&m66592->gadget)
 #define m66592_to_gadget(m66592) (&m66592->gadget)

+ 56 - 15
drivers/usb/gadget/multi.c

@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 
 
+#include "u_serial.h"
 #if defined USB_ETH_RNDIS
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
 #endif
 #endif
@@ -42,9 +43,6 @@ MODULE_LICENSE("GPL");
  */
  */
 #include "f_mass_storage.c"
 #include "f_mass_storage.c"
 
 
-#include "u_serial.c"
-#include "f_acm.c"
-
 #include "f_ecm.c"
 #include "f_ecm.c"
 #include "f_subset.c"
 #include "f_subset.c"
 #ifdef USB_ETH_RNDIS
 #ifdef USB_ETH_RNDIS
@@ -137,10 +135,13 @@ static struct fsg_common fsg_common;
 
 
 static u8 hostaddr[ETH_ALEN];
 static u8 hostaddr[ETH_ALEN];
 
 
+static unsigned char tty_line;
+static struct usb_function_instance *fi_acm;
 
 
 /********** RNDIS **********/
 /********** RNDIS **********/
 
 
 #ifdef USB_ETH_RNDIS
 #ifdef USB_ETH_RNDIS
+static struct usb_function *f_acm_rndis;
 
 
 static __init int rndis_do_config(struct usb_configuration *c)
 static __init int rndis_do_config(struct usb_configuration *c)
 {
 {
@@ -155,15 +156,25 @@ static __init int rndis_do_config(struct usb_configuration *c)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	ret = acm_bind_config(c, 0);
-	if (ret < 0)
-		return ret;
+	f_acm_rndis = usb_get_function(fi_acm);
+	if (IS_ERR(f_acm_rndis))
+		goto err_func_acm;
+
+	ret = usb_add_function(c, f_acm_rndis);
+	if (ret)
+		goto err_conf;
 
 
 	ret = fsg_bind_config(c->cdev, c, &fsg_common);
 	ret = fsg_bind_config(c->cdev, c, &fsg_common);
 	if (ret < 0)
 	if (ret < 0)
-		return ret;
+		goto err_fsg;
 
 
 	return 0;
 	return 0;
+err_fsg:
+	usb_remove_function(c, f_acm_rndis);
+err_conf:
+	usb_put_function(f_acm_rndis);
+err_func_acm:
+	return ret;
 }
 }
 
 
 static int rndis_config_register(struct usb_composite_dev *cdev)
 static int rndis_config_register(struct usb_composite_dev *cdev)
@@ -192,6 +203,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
 /********** CDC ECM **********/
 /********** CDC ECM **********/
 
 
 #ifdef CONFIG_USB_G_MULTI_CDC
 #ifdef CONFIG_USB_G_MULTI_CDC
+static struct usb_function *f_acm_multi;
 
 
 static __init int cdc_do_config(struct usb_configuration *c)
 static __init int cdc_do_config(struct usb_configuration *c)
 {
 {
@@ -206,15 +218,26 @@ static __init int cdc_do_config(struct usb_configuration *c)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	ret = acm_bind_config(c, 0);
-	if (ret < 0)
-		return ret;
+	/* implicit port_num is zero */
+	f_acm_multi = usb_get_function(fi_acm);
+	if (IS_ERR(f_acm_multi))
+		goto err_func_acm;
+
+	ret = usb_add_function(c, f_acm_multi);
+	if (ret)
+		goto err_conf;
 
 
 	ret = fsg_bind_config(c->cdev, c, &fsg_common);
 	ret = fsg_bind_config(c->cdev, c, &fsg_common);
 	if (ret < 0)
 	if (ret < 0)
-		return ret;
+		goto err_fsg;
 
 
 	return 0;
 	return 0;
+err_fsg:
+	usb_remove_function(c, f_acm_multi);
+err_conf:
+	usb_put_function(f_acm_multi);
+err_func_acm:
+	return ret;
 }
 }
 
 
 static int cdc_config_register(struct usb_composite_dev *cdev)
 static int cdc_config_register(struct usb_composite_dev *cdev)
@@ -243,10 +266,10 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
 
 
 /****************************** Gadget Bind ******************************/
 /****************************** Gadget Bind ******************************/
 
 
-
 static int __ref multi_bind(struct usb_composite_dev *cdev)
 static int __ref multi_bind(struct usb_composite_dev *cdev)
 {
 {
 	struct usb_gadget *gadget = cdev->gadget;
 	struct usb_gadget *gadget = cdev->gadget;
+	struct f_serial_opts *opts;
 	int status;
 	int status;
 
 
 	if (!can_support_ecm(cdev->gadget)) {
 	if (!can_support_ecm(cdev->gadget)) {
@@ -261,10 +284,19 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
 		return status;
 		return status;
 
 
 	/* set up serial link layer */
 	/* set up serial link layer */
-	status = gserial_setup(cdev->gadget, 1);
+	status = gserial_alloc_line(&tty_line);
 	if (status < 0)
 	if (status < 0)
 		goto fail0;
 		goto fail0;
 
 
+	fi_acm = usb_get_function_instance("acm");
+	if (IS_ERR(fi_acm)) {
+		status = PTR_ERR(fi_acm);
+		goto fail0dot5;
+	}
+
+	opts = container_of(fi_acm, struct f_serial_opts, func_inst);
+	opts->port_num = tty_line;
+
 	/* set up mass storage function */
 	/* set up mass storage function */
 	{
 	{
 		void *retp;
 		void *retp;
@@ -301,7 +333,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
 fail2:
 fail2:
 	fsg_common_put(&fsg_common);
 	fsg_common_put(&fsg_common);
 fail1:
 fail1:
-	gserial_cleanup();
+	usb_put_function_instance(fi_acm);
+fail0dot5:
+	gserial_free_line(tty_line);
 fail0:
 fail0:
 	gether_cleanup();
 	gether_cleanup();
 	return status;
 	return status;
@@ -309,7 +343,14 @@ fail0:
 
 
 static int __exit multi_unbind(struct usb_composite_dev *cdev)
 static int __exit multi_unbind(struct usb_composite_dev *cdev)
 {
 {
-	gserial_cleanup();
+#ifdef CONFIG_USB_G_MULTI_CDC
+	usb_put_function(f_acm_multi);
+#endif
+#ifdef USB_ETH_RNDIS
+	usb_put_function(f_acm_rndis);
+#endif
+	usb_put_function_instance(fi_acm);
+	gserial_free_line(tty_line);
 	gether_cleanup();
 	gether_cleanup();
 	return 0;
 	return 0;
 }
 }

+ 99 - 147
drivers/usb/gadget/mv_udc_core.c

@@ -61,9 +61,6 @@ static DECLARE_COMPLETION(release_done);
 static const char driver_name[] = "mv_udc";
 static const char driver_name[] = "mv_udc";
 static const char driver_desc[] = DRIVER_DESC;
 static const char driver_desc[] = DRIVER_DESC;
 
 
-/* controller device global variable */
-static struct mv_udc	*the_controller;
-
 static void nuke(struct mv_ep *ep, int status);
 static void nuke(struct mv_ep *ep, int status);
 static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
 static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
 
 
@@ -1268,9 +1265,8 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
 	return retval;
 	return retval;
 }
 }
 
 
-static int mv_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
-static int mv_udc_stop(struct usb_gadget_driver *driver);
+static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *);
+static int mv_udc_stop(struct usb_gadget *, struct usb_gadget_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 = {
 
 
@@ -1285,8 +1281,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,
+	.udc_start	= mv_udc_start,
+	.udc_stop	= mv_udc_stop,
 };
 };
 
 
 static int eps_init(struct mv_udc *udc)
 static int eps_init(struct mv_udc *udc)
@@ -1373,15 +1369,14 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
 	}
 	}
 }
 }
 
 
-static int mv_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int mv_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
 	int retval = 0;
 	int retval = 0;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!udc)
-		return -ENODEV;
+	udc = container_of(gadget, struct mv_udc, gadget);
 
 
 	if (udc->driver)
 	if (udc->driver)
 		return -EBUSY;
 		return -EBUSY;
@@ -1399,26 +1394,14 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
 
 
 	spin_unlock_irqrestore(&udc->lock, flags);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 
-	retval = bind(&udc->gadget, driver);
-	if (retval) {
-		dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
-				driver->driver.name, retval);
-		udc->driver = NULL;
-		udc->gadget.dev.driver = NULL;
-		return retval;
-	}
-
-	if (!IS_ERR_OR_NULL(udc->transceiver)) {
+	if (udc->transceiver) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 		retval = otg_set_peripheral(udc->transceiver->otg,
 					&udc->gadget);
 					&udc->gadget);
 		if (retval) {
 		if (retval) {
 			dev_err(&udc->dev->dev,
 			dev_err(&udc->dev->dev,
 				"unable to register peripheral to otg\n");
 				"unable to register peripheral to otg\n");
-			if (driver->unbind) {
-				driver->unbind(&udc->gadget);
-				udc->gadget.dev.driver = NULL;
-				udc->driver = NULL;
-			}
+			udc->driver = NULL;
+			udc->gadget.dev.driver = NULL;
 			return retval;
 			return retval;
 		}
 		}
 	}
 	}
@@ -1433,13 +1416,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
 	return 0;
 	return 0;
 }
 }
 
 
-static int mv_udc_stop(struct usb_gadget_driver *driver)
+static int mv_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!udc)
-		return -ENODEV;
+	udc = container_of(gadget, struct mv_udc, gadget);
 
 
 	spin_lock_irqsave(&udc->lock, flags);
 	spin_lock_irqsave(&udc->lock, flags);
 
 
@@ -1454,7 +1437,6 @@ static int mv_udc_stop(struct usb_gadget_driver *driver)
 	spin_unlock_irqrestore(&udc->lock, flags);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 
 	/* unbind gadget driver */
 	/* unbind gadget driver */
-	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
 	udc->driver = NULL;
 
 
@@ -1472,10 +1454,13 @@ static void mv_set_ptc(struct mv_udc *udc, u32 mode)
 
 
 static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
 static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_ep *mvep = container_of(ep, struct mv_ep, ep);
 	struct mv_req *req = container_of(_req, struct mv_req, req);
 	struct mv_req *req = container_of(_req, struct mv_req, req);
+	struct mv_udc *udc;
 	unsigned long flags;
 	unsigned long flags;
 
 
+	udc = mvep->udc;
+
 	dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
 	dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
 
 
 	spin_lock_irqsave(&udc->lock, flags);
 	spin_lock_irqsave(&udc->lock, flags);
@@ -2123,15 +2108,18 @@ static void mv_udc_vbus_work(struct work_struct *work)
 /* release device structure */
 /* release device structure */
 static void gadget_release(struct device *_dev)
 static void gadget_release(struct device *_dev)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
+
+	udc = dev_get_drvdata(_dev);
 
 
 	complete(udc->done);
 	complete(udc->done);
 }
 }
 
 
-static int mv_udc_remove(struct platform_device *dev)
+static int mv_udc_remove(struct platform_device *pdev)
 {
 {
-	struct mv_udc *udc = the_controller;
-	int clk_i;
+	struct mv_udc *udc;
+
+	udc = platform_get_drvdata(pdev);
 
 
 	usb_del_gadget_udc(&udc->gadget);
 	usb_del_gadget_udc(&udc->gadget);
 
 
@@ -2140,57 +2128,27 @@ static int mv_udc_remove(struct platform_device *dev)
 		destroy_workqueue(udc->qwork);
 		destroy_workqueue(udc->qwork);
 	}
 	}
 
 
-	/*
-	 * If we have transceiver inited,
-	 * then vbus irq will not be requested in udc driver.
-	 */
-	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
-		free_irq(udc->pdata->vbus->irq, &dev->dev);
-
 	/* free memory allocated in probe */
 	/* free memory allocated in probe */
 	if (udc->dtd_pool)
 	if (udc->dtd_pool)
 		dma_pool_destroy(udc->dtd_pool);
 		dma_pool_destroy(udc->dtd_pool);
 
 
 	if (udc->ep_dqh)
 	if (udc->ep_dqh)
-		dma_free_coherent(&dev->dev, udc->ep_dqh_size,
+		dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
 			udc->ep_dqh, udc->ep_dqh_dma);
 			udc->ep_dqh, udc->ep_dqh_dma);
 
 
-	kfree(udc->eps);
-
-	if (udc->irq)
-		free_irq(udc->irq, &dev->dev);
-
 	mv_udc_disable(udc);
 	mv_udc_disable(udc);
 
 
-	if (udc->cap_regs)
-		iounmap(udc->cap_regs);
-
-	if (udc->phy_regs)
-		iounmap(udc->phy_regs);
-
-	if (udc->status_req) {
-		kfree(udc->status_req->req.buf);
-		kfree(udc->status_req);
-	}
-
-	for (clk_i = 0; clk_i <= udc->clknum; clk_i++)
-		clk_put(udc->clk[clk_i]);
-
 	device_unregister(&udc->gadget.dev);
 	device_unregister(&udc->gadget.dev);
 
 
 	/* free dev, wait for the release() finished */
 	/* free dev, wait for the release() finished */
 	wait_for_completion(udc->done);
 	wait_for_completion(udc->done);
-	kfree(udc);
-
-	the_controller = NULL;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int mv_udc_probe(struct platform_device *dev)
+static int mv_udc_probe(struct platform_device *pdev)
 {
 {
-	struct mv_usb_platform_data *pdata = dev->dev.platform_data;
+	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
 	struct mv_udc *udc;
 	struct mv_udc *udc;
 	int retval = 0;
 	int retval = 0;
 	int clk_i = 0;
 	int clk_i = 0;
@@ -2198,71 +2156,73 @@ static int mv_udc_probe(struct platform_device *dev)
 	size_t size;
 	size_t size;
 
 
 	if (pdata == NULL) {
 	if (pdata == NULL) {
-		dev_err(&dev->dev, "missing platform_data\n");
+		dev_err(&pdev->dev, "missing platform_data\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
 	size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
 	size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
-	udc = kzalloc(size, GFP_KERNEL);
+	udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (udc == NULL) {
 	if (udc == NULL) {
-		dev_err(&dev->dev, "failed to allocate memory for udc\n");
+		dev_err(&pdev->dev, "failed to allocate memory for udc\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	the_controller = udc;
 	udc->done = &release_done;
 	udc->done = &release_done;
-	udc->pdata = dev->dev.platform_data;
+	udc->pdata = pdev->dev.platform_data;
 	spin_lock_init(&udc->lock);
 	spin_lock_init(&udc->lock);
 
 
-	udc->dev = dev;
+	udc->dev = pdev;
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (pdata->mode == MV_USB_MODE_OTG)
-		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (pdata->mode == MV_USB_MODE_OTG) {
+		udc->transceiver = devm_usb_get_phy(&pdev->dev,
+					USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(udc->transceiver)) {
+			udc->transceiver = NULL;
+			return -ENODEV;
+		}
+	}
 #endif
 #endif
 
 
 	udc->clknum = pdata->clknum;
 	udc->clknum = pdata->clknum;
 	for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
 	for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
-		udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
+		udc->clk[clk_i] = devm_clk_get(&pdev->dev,
+					pdata->clkname[clk_i]);
 		if (IS_ERR(udc->clk[clk_i])) {
 		if (IS_ERR(udc->clk[clk_i])) {
 			retval = PTR_ERR(udc->clk[clk_i]);
 			retval = PTR_ERR(udc->clk[clk_i]);
-			goto err_put_clk;
+			return retval;
 		}
 		}
 	}
 	}
 
 
 	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
 	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
 	if (r == NULL) {
 	if (r == NULL) {
-		dev_err(&dev->dev, "no I/O memory resource defined\n");
-		retval = -ENODEV;
-		goto err_put_clk;
+		dev_err(&pdev->dev, "no I/O memory resource defined\n");
+		return -ENODEV;
 	}
 	}
 
 
 	udc->cap_regs = (struct mv_cap_regs __iomem *)
 	udc->cap_regs = (struct mv_cap_regs __iomem *)
-		ioremap(r->start, resource_size(r));
+		devm_ioremap(&pdev->dev, r->start, resource_size(r));
 	if (udc->cap_regs == NULL) {
 	if (udc->cap_regs == NULL) {
-		dev_err(&dev->dev, "failed to map I/O memory\n");
-		retval = -EBUSY;
-		goto err_put_clk;
+		dev_err(&pdev->dev, "failed to map I/O memory\n");
+		return -EBUSY;
 	}
 	}
 
 
 	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
 	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
 	if (r == NULL) {
 	if (r == NULL) {
-		dev_err(&dev->dev, "no phy I/O memory resource defined\n");
-		retval = -ENODEV;
-		goto err_iounmap_capreg;
+		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+		return -ENODEV;
 	}
 	}
 
 
 	udc->phy_regs = ioremap(r->start, resource_size(r));
 	udc->phy_regs = ioremap(r->start, resource_size(r));
 	if (udc->phy_regs == NULL) {
 	if (udc->phy_regs == NULL) {
-		dev_err(&dev->dev, "failed to map phy I/O memory\n");
-		retval = -EBUSY;
-		goto err_iounmap_capreg;
+		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+		return -EBUSY;
 	}
 	}
 
 
 	/* we will acces controller register, so enable the clk */
 	/* we will acces controller register, so enable the clk */
 	retval = mv_udc_enable_internal(udc);
 	retval = mv_udc_enable_internal(udc);
 	if (retval)
 	if (retval)
-		goto err_iounmap_phyreg;
+		return retval;
 
 
 	udc->op_regs =
 	udc->op_regs =
 		(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
 		(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
@@ -2279,11 +2239,11 @@ static int mv_udc_probe(struct platform_device *dev)
 
 
 	size = udc->max_eps * sizeof(struct mv_dqh) *2;
 	size = udc->max_eps * sizeof(struct mv_dqh) *2;
 	size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
 	size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
-	udc->ep_dqh = dma_alloc_coherent(&dev->dev, size,
+	udc->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
 					&udc->ep_dqh_dma, GFP_KERNEL);
 					&udc->ep_dqh_dma, GFP_KERNEL);
 
 
 	if (udc->ep_dqh == NULL) {
 	if (udc->ep_dqh == NULL) {
-		dev_err(&dev->dev, "allocate dQH memory failed\n");
+		dev_err(&pdev->dev, "allocate dQH memory failed\n");
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto err_disable_clock;
 		goto err_disable_clock;
 	}
 	}
@@ -2291,7 +2251,7 @@ static int mv_udc_probe(struct platform_device *dev)
 
 
 	/* create dTD dma_pool resource */
 	/* create dTD dma_pool resource */
 	udc->dtd_pool = dma_pool_create("mv_dtd",
 	udc->dtd_pool = dma_pool_create("mv_dtd",
-			&dev->dev,
+			&pdev->dev,
 			sizeof(struct mv_dtd),
 			sizeof(struct mv_dtd),
 			DTD_ALIGNMENT,
 			DTD_ALIGNMENT,
 			DMA_BOUNDARY);
 			DMA_BOUNDARY);
@@ -2302,19 +2262,20 @@ static int mv_udc_probe(struct platform_device *dev)
 	}
 	}
 
 
 	size = udc->max_eps * sizeof(struct mv_ep) *2;
 	size = udc->max_eps * sizeof(struct mv_ep) *2;
-	udc->eps = kzalloc(size, GFP_KERNEL);
+	udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (udc->eps == NULL) {
 	if (udc->eps == NULL) {
-		dev_err(&dev->dev, "allocate ep memory failed\n");
+		dev_err(&pdev->dev, "allocate ep memory failed\n");
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto err_destroy_dma;
 		goto err_destroy_dma;
 	}
 	}
 
 
 	/* initialize ep0 status request structure */
 	/* initialize ep0 status request structure */
-	udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL);
+	udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req),
+					GFP_KERNEL);
 	if (!udc->status_req) {
 	if (!udc->status_req) {
-		dev_err(&dev->dev, "allocate status_req memory failed\n");
+		dev_err(&pdev->dev, "allocate status_req memory failed\n");
 		retval = -ENOMEM;
 		retval = -ENOMEM;
-		goto err_free_eps;
+		goto err_destroy_dma;
 	}
 	}
 	INIT_LIST_HEAD(&udc->status_req->queue);
 	INIT_LIST_HEAD(&udc->status_req->queue);
 
 
@@ -2329,17 +2290,17 @@ static int mv_udc_probe(struct platform_device *dev)
 
 
 	r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
 	r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
 	if (r == NULL) {
 	if (r == NULL) {
-		dev_err(&dev->dev, "no IRQ resource defined\n");
+		dev_err(&pdev->dev, "no IRQ resource defined\n");
 		retval = -ENODEV;
 		retval = -ENODEV;
-		goto err_free_status_req;
+		goto err_destroy_dma;
 	}
 	}
 	udc->irq = r->start;
 	udc->irq = r->start;
-	if (request_irq(udc->irq, mv_udc_irq,
+	if (devm_request_irq(&pdev->dev, udc->irq, mv_udc_irq,
 		IRQF_SHARED, driver_name, udc)) {
 		IRQF_SHARED, driver_name, udc)) {
-		dev_err(&dev->dev, "Request irq %d for UDC failed\n",
+		dev_err(&pdev->dev, "Request irq %d for UDC failed\n",
 			udc->irq);
 			udc->irq);
 		retval = -ENODEV;
 		retval = -ENODEV;
-		goto err_free_status_req;
+		goto err_destroy_dma;
 	}
 	}
 
 
 	/* initialize gadget structure */
 	/* initialize gadget structure */
@@ -2351,26 +2312,27 @@ static int mv_udc_probe(struct platform_device *dev)
 
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	/* the "gadget" abstracts/virtualizes the controller */
 	dev_set_name(&udc->gadget.dev, "gadget");
 	dev_set_name(&udc->gadget.dev, "gadget");
-	udc->gadget.dev.parent = &dev->dev;
-	udc->gadget.dev.dma_mask = dev->dev.dma_mask;
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
 	udc->gadget.dev.release = gadget_release;
 	udc->gadget.dev.release = gadget_release;
 	udc->gadget.name = driver_name;		/* gadget name */
 	udc->gadget.name = driver_name;		/* gadget name */
 
 
 	retval = device_register(&udc->gadget.dev);
 	retval = device_register(&udc->gadget.dev);
 	if (retval)
 	if (retval)
-		goto err_free_irq;
+		goto err_destroy_dma;
 
 
 	eps_init(udc);
 	eps_init(udc);
 
 
 	/* VBUS detect: we can disable/enable clock on demand.*/
 	/* VBUS detect: we can disable/enable clock on demand.*/
-	if (!IS_ERR_OR_NULL(udc->transceiver))
+	if (udc->transceiver)
 		udc->clock_gating = 1;
 		udc->clock_gating = 1;
 	else if (pdata->vbus) {
 	else if (pdata->vbus) {
 		udc->clock_gating = 1;
 		udc->clock_gating = 1;
-		retval = request_threaded_irq(pdata->vbus->irq, NULL,
+		retval = devm_request_threaded_irq(&pdev->dev,
+				pdata->vbus->irq, NULL,
 				mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
 				mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
 		if (retval) {
 		if (retval) {
-			dev_info(&dev->dev,
+			dev_info(&pdev->dev,
 				"Can not request irq for VBUS, "
 				"Can not request irq for VBUS, "
 				"disable clock gating\n");
 				"disable clock gating\n");
 			udc->clock_gating = 0;
 			udc->clock_gating = 0;
@@ -2378,7 +2340,7 @@ static int mv_udc_probe(struct platform_device *dev)
 
 
 		udc->qwork = create_singlethread_workqueue("mv_udc_queue");
 		udc->qwork = create_singlethread_workqueue("mv_udc_queue");
 		if (!udc->qwork) {
 		if (!udc->qwork) {
-			dev_err(&dev->dev, "cannot create workqueue\n");
+			dev_err(&pdev->dev, "cannot create workqueue\n");
 			retval = -ENOMEM;
 			retval = -ENOMEM;
 			goto err_unregister;
 			goto err_unregister;
 		}
 		}
@@ -2396,53 +2358,40 @@ static int mv_udc_probe(struct platform_device *dev)
 	else
 	else
 		udc->vbus_active = 1;
 		udc->vbus_active = 1;
 
 
-	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
+	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (retval)
 	if (retval)
-		goto err_unregister;
+		goto err_create_workqueue;
 
 
-	dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n",
+	platform_set_drvdata(pdev, udc);
+	dev_info(&pdev->dev, "successful probe UDC device %s clock gating.\n",
 		udc->clock_gating ? "with" : "without");
 		udc->clock_gating ? "with" : "without");
 
 
 	return 0;
 	return 0;
 
 
+err_create_workqueue:
+	destroy_workqueue(udc->qwork);
 err_unregister:
 err_unregister:
-	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
-		free_irq(pdata->vbus->irq, &dev->dev);
 	device_unregister(&udc->gadget.dev);
 	device_unregister(&udc->gadget.dev);
-err_free_irq:
-	free_irq(udc->irq, &dev->dev);
-err_free_status_req:
-	kfree(udc->status_req->req.buf);
-	kfree(udc->status_req);
-err_free_eps:
-	kfree(udc->eps);
 err_destroy_dma:
 err_destroy_dma:
 	dma_pool_destroy(udc->dtd_pool);
 	dma_pool_destroy(udc->dtd_pool);
 err_free_dma:
 err_free_dma:
-	dma_free_coherent(&dev->dev, udc->ep_dqh_size,
+	dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
 			udc->ep_dqh, udc->ep_dqh_dma);
 			udc->ep_dqh, udc->ep_dqh_dma);
 err_disable_clock:
 err_disable_clock:
 	mv_udc_disable_internal(udc);
 	mv_udc_disable_internal(udc);
-err_iounmap_phyreg:
-	iounmap(udc->phy_regs);
-err_iounmap_capreg:
-	iounmap(udc->cap_regs);
-err_put_clk:
-	for (clk_i--; clk_i >= 0; clk_i--)
-		clk_put(udc->clk[clk_i]);
-	the_controller = NULL;
-	kfree(udc);
+
 	return retval;
 	return retval;
 }
 }
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
-static int mv_udc_suspend(struct device *_dev)
+static int mv_udc_suspend(struct device *dev)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
+
+	udc = dev_get_drvdata(dev);
 
 
 	/* if OTG is enabled, the following will be done in OTG driver*/
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (!IS_ERR_OR_NULL(udc->transceiver))
+	if (udc->transceiver)
 		return 0;
 		return 0;
 
 
 	if (udc->pdata->vbus && udc->pdata->vbus->poll)
 	if (udc->pdata->vbus && udc->pdata->vbus->poll)
@@ -2469,13 +2418,15 @@ static int mv_udc_suspend(struct device *_dev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int mv_udc_resume(struct device *_dev)
+static int mv_udc_resume(struct device *dev)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
 	int retval;
 	int retval;
 
 
+	udc = dev_get_drvdata(dev);
+
 	/* if OTG is enabled, the following will be done in OTG driver*/
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (!IS_ERR_OR_NULL(udc->transceiver))
+	if (udc->transceiver)
 		return 0;
 		return 0;
 
 
 	if (!udc->clock_gating) {
 	if (!udc->clock_gating) {
@@ -2499,11 +2450,12 @@ static const struct dev_pm_ops mv_udc_pm_ops = {
 };
 };
 #endif
 #endif
 
 
-static void mv_udc_shutdown(struct platform_device *dev)
+static void mv_udc_shutdown(struct platform_device *pdev)
 {
 {
-	struct mv_udc *udc = the_controller;
+	struct mv_udc *udc;
 	u32 mode;
 	u32 mode;
 
 
+	udc = platform_get_drvdata(pdev);
 	/* reset controller mode to IDLE */
 	/* reset controller mode to IDLE */
 	mv_udc_enable(udc);
 	mv_udc_enable(udc);
 	mode = readl(&udc->op_regs->usbmode);
 	mode = readl(&udc->op_regs->usbmode);
@@ -2514,7 +2466,7 @@ static void mv_udc_shutdown(struct platform_device *dev)
 
 
 static struct platform_driver udc_driver = {
 static struct platform_driver udc_driver = {
 	.probe		= mv_udc_probe,
 	.probe		= mv_udc_probe,
-	.remove		= __exit_p(mv_udc_remove),
+	.remove		= mv_udc_remove,
 	.shutdown	= mv_udc_shutdown,
 	.shutdown	= mv_udc_shutdown,
 	.driver		= {
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,

+ 15 - 0
drivers/usb/gadget/net2280.c

@@ -116,6 +116,10 @@ static bool enable_suspend = 0;
 /* "modprobe net2280 enable_suspend=1" etc */
 /* "modprobe net2280 enable_suspend=1" etc */
 module_param (enable_suspend, bool, S_IRUGO);
 module_param (enable_suspend, bool, S_IRUGO);
 
 
+/* force full-speed operation */
+static bool full_speed;
+module_param(full_speed, bool, 0444);
+MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
 
 
 #define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 #define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 
 
@@ -1899,6 +1903,10 @@ static int net2280_start(struct usb_gadget *_gadget,
 	retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
 	retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
 	if (retval) goto err_func;
 	if (retval) goto err_func;
 
 
+	/* Enable force-full-speed testing mode, if desired */
+	if (full_speed)
+		writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag);
+
 	/* ... then enable host detection and ep0; and we're ready
 	/* ... then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
 	 * for set_configuration as well as eventual disconnect.
 	 */
 	 */
@@ -1957,6 +1965,10 @@ static int net2280_stop(struct usb_gadget *_gadget,
 	dev->driver = NULL;
 	dev->driver = NULL;
 
 
 	net2280_led_active (dev, 0);
 	net2280_led_active (dev, 0);
+
+	/* Disable full-speed test mode */
+	writel(0, &dev->usb->xcvrdiag);
+
 	device_remove_file (&dev->pdev->dev, &dev_attr_function);
 	device_remove_file (&dev->pdev->dev, &dev_attr_function);
 	device_remove_file (&dev->pdev->dev, &dev_attr_queues);
 	device_remove_file (&dev->pdev->dev, &dev_attr_queues);
 
 
@@ -2841,6 +2853,9 @@ static void net2280_shutdown (struct pci_dev *pdev)
 
 
 	/* disable the pullup so the host will think we're gone */
 	/* disable the pullup so the host will think we're gone */
 	writel (0, &dev->usb->usbctl);
 	writel (0, &dev->usb->usbctl);
+
+	/* Disable full-speed test mode */
+	writel(0, &dev->usb->xcvrdiag);
 }
 }
 
 
 
 

+ 31 - 12
drivers/usb/gadget/nokia.c

@@ -37,7 +37,7 @@
  * the runtime footprint, and giving us at least some parts of what
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
  */
-#include "u_serial.c"
+#define USB_FACM_INCLUDED
 #include "f_acm.c"
 #include "f_acm.c"
 #include "f_ecm.c"
 #include "f_ecm.c"
 #include "f_obex.c"
 #include "f_obex.c"
@@ -101,6 +101,15 @@ MODULE_LICENSE("GPL");
 
 
 static u8 hostaddr[ETH_ALEN];
 static u8 hostaddr[ETH_ALEN];
 
 
+enum {
+	TTY_PORT_OBEX0,
+	TTY_PORT_OBEX1,
+	TTY_PORT_ACM,
+	TTY_PORTS_MAX,
+};
+
+static unsigned char tty_lines[TTY_PORTS_MAX];
+
 static int __init nokia_bind_config(struct usb_configuration *c)
 static int __init nokia_bind_config(struct usb_configuration *c)
 {
 {
 	int status = 0;
 	int status = 0;
@@ -109,15 +118,15 @@ static int __init nokia_bind_config(struct usb_configuration *c)
 	if (status)
 	if (status)
 		printk(KERN_DEBUG "could not bind phonet config\n");
 		printk(KERN_DEBUG "could not bind phonet config\n");
 
 
-	status = obex_bind_config(c, 0);
+	status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX0]);
 	if (status)
 	if (status)
 		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
 		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
 
 
-	status = obex_bind_config(c, 1);
+	status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX1]);
 	if (status)
 	if (status)
 		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
 		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
 
 
-	status = acm_bind_config(c, 2);
+	status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
 	if (status)
 	if (status)
 		printk(KERN_DEBUG "could not bind acm config\n");
 		printk(KERN_DEBUG "could not bind acm config\n");
 
 
@@ -133,7 +142,7 @@ static struct usb_configuration nokia_config_500ma_driver = {
 	.bConfigurationValue = 1,
 	.bConfigurationValue = 1,
 	/* .iConfiguration = DYNAMIC */
 	/* .iConfiguration = DYNAMIC */
 	.bmAttributes	= USB_CONFIG_ATT_ONE,
 	.bmAttributes	= USB_CONFIG_ATT_ONE,
-	.bMaxPower	= 250, /* 500mA */
+	.MaxPower	= 500,
 };
 };
 
 
 static struct usb_configuration nokia_config_100ma_driver = {
 static struct usb_configuration nokia_config_100ma_driver = {
@@ -141,21 +150,24 @@ static struct usb_configuration nokia_config_100ma_driver = {
 	.bConfigurationValue = 2,
 	.bConfigurationValue = 2,
 	/* .iConfiguration = DYNAMIC */
 	/* .iConfiguration = DYNAMIC */
 	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower	= 50, /* 100 mA */
+	.MaxPower	= 100,
 };
 };
 
 
 static int __init nokia_bind(struct usb_composite_dev *cdev)
 static int __init nokia_bind(struct usb_composite_dev *cdev)
 {
 {
 	struct usb_gadget	*gadget = cdev->gadget;
 	struct usb_gadget	*gadget = cdev->gadget;
 	int			status;
 	int			status;
+	int			cur_line;
 
 
 	status = gphonet_setup(cdev->gadget);
 	status = gphonet_setup(cdev->gadget);
 	if (status < 0)
 	if (status < 0)
 		goto err_phonet;
 		goto err_phonet;
 
 
-	status = gserial_setup(cdev->gadget, 3);
-	if (status < 0)
-		goto err_serial;
+	for (cur_line = 0; cur_line < TTY_PORTS_MAX; cur_line++) {
+		status = gserial_alloc_line(&tty_lines[cur_line]);
+		if (status)
+			goto err_ether;
+	}
 
 
 	status = gether_setup(cdev->gadget, hostaddr);
 	status = gether_setup(cdev->gadget, hostaddr);
 	if (status < 0)
 	if (status < 0)
@@ -192,8 +204,10 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
 err_usb:
 err_usb:
 	gether_cleanup();
 	gether_cleanup();
 err_ether:
 err_ether:
-	gserial_cleanup();
-err_serial:
+	cur_line--;
+	while (cur_line >= 0)
+		gserial_free_line(tty_lines[cur_line--]);
+
 	gphonet_cleanup();
 	gphonet_cleanup();
 err_phonet:
 err_phonet:
 	return status;
 	return status;
@@ -201,8 +215,13 @@ err_phonet:
 
 
 static int __exit nokia_unbind(struct usb_composite_dev *cdev)
 static int __exit nokia_unbind(struct usb_composite_dev *cdev)
 {
 {
+	int i;
+
 	gphonet_cleanup();
 	gphonet_cleanup();
-	gserial_cleanup();
+
+	for (i = 0; i < TTY_PORTS_MAX; i++)
+		gserial_free_line(tty_lines[i]);
+
 	gether_cleanup();
 	gether_cleanup();
 
 
 	return 0;
 	return 0;

+ 13 - 38
drivers/usb/gadget/omap_udc.c

@@ -1309,19 +1309,20 @@ 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 *, struct usb_gadget_driver *));
-static int omap_udc_stop(struct usb_gadget_driver *driver);
+static int omap_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
 
 
-static struct usb_gadget_ops omap_gadget_ops = {
+static const struct usb_gadget_ops omap_gadget_ops = {
 	.get_frame		= omap_get_frame,
 	.get_frame		= omap_get_frame,
 	.wakeup			= omap_wakeup,
 	.wakeup			= omap_wakeup,
 	.set_selfpowered	= omap_set_selfpowered,
 	.set_selfpowered	= omap_set_selfpowered,
 	.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,
+	.udc_start		= omap_udc_start,
+	.udc_stop		= omap_udc_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -2041,28 +2042,15 @@ static inline int machine_without_vbus_sense(void)
 		|| cpu_is_omap7xx();
 		|| cpu_is_omap7xx();
 }
 }
 
 
-static int omap_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int omap_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
 	int		status = -ENODEV;
 	int		status = -ENODEV;
 	struct omap_ep	*ep;
 	struct omap_ep	*ep;
 	unsigned long	flags;
 	unsigned long	flags;
 
 
-	/* basic sanity tests */
-	if (!udc)
-		return -ENODEV;
-	if (!driver
-			/* FIXME if otg, check:  driver->is_otg */
-			|| driver->max_speed < USB_SPEED_FULL
-			|| !bind || !driver->setup)
-		return -EINVAL;
 
 
 	spin_lock_irqsave(&udc->lock, flags);
 	spin_lock_irqsave(&udc->lock, flags);
-	if (udc->driver) {
-		spin_unlock_irqrestore(&udc->lock, flags);
-		return -EBUSY;
-	}
-
 	/* reset state */
 	/* reset state */
 	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
 	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
 		ep->irqs = 0;
 		ep->irqs = 0;
@@ -2084,15 +2072,6 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 	if (udc->dc_clk != NULL)
 	if (udc->dc_clk != NULL)
 		omap_udc_enable_clock(1);
 		omap_udc_enable_clock(1);
 
 
-	status = bind(&udc->gadget, driver);
-	if (status) {
-		DBG("bind to %s --> %d\n", driver->driver.name, status);
-		udc->gadget.dev.driver = NULL;
-		udc->driver = NULL;
-		goto done;
-	}
-	DBG("bound to driver %s\n", driver->driver.name);
-
 	omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
 	omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
 
 
 	/* connect to bus through transceiver */
 	/* connect to bus through transceiver */
@@ -2124,19 +2103,16 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 done:
 done:
 	if (udc->dc_clk != NULL)
 	if (udc->dc_clk != NULL)
 		omap_udc_enable_clock(0);
 		omap_udc_enable_clock(0);
+
 	return status;
 	return status;
 }
 }
 
 
-static int omap_udc_stop(struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
 	unsigned long	flags;
 	unsigned long	flags;
 	int		status = -ENODEV;
 	int		status = -ENODEV;
 
 
-	if (!udc)
-		return -ENODEV;
-	if (!driver || driver != udc->driver || !driver->unbind)
-		return -EINVAL;
-
 	if (udc->dc_clk != NULL)
 	if (udc->dc_clk != NULL)
 		omap_udc_enable_clock(1);
 		omap_udc_enable_clock(1);
 
 
@@ -2152,13 +2128,12 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
 	udc_quiesce(udc);
 	udc_quiesce(udc);
 	spin_unlock_irqrestore(&udc->lock, flags);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 
-	driver->unbind(&udc->gadget);
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
 	udc->driver = NULL;
 
 
 	if (udc->dc_clk != NULL)
 	if (udc->dc_clk != NULL)
 		omap_udc_enable_clock(0);
 		omap_udc_enable_clock(0);
-	DBG("unregistered driver '%s'\n", driver->driver.name);
+
 	return status;
 	return status;
 }
 }
 
 

+ 14 - 53
drivers/usb/gadget/pch_udc.c

@@ -375,6 +375,7 @@ struct pch_udc_dev {
 	struct pch_udc_cfg_data		cfg_data;
 	struct pch_udc_cfg_data		cfg_data;
 	struct pch_vbus_gpio_data	vbus_gpio;
 	struct pch_vbus_gpio_data	vbus_gpio;
 };
 };
+#define to_pch_udc(g)	(container_of((g), struct pch_udc_dev, gadget))
 
 
 #define PCH_UDC_PCI_BAR			1
 #define PCH_UDC_PCI_BAR			1
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC	0x8808
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC	0x8808
@@ -384,7 +385,6 @@ struct pch_udc_dev {
 
 
 static const char	ep0_string[] = "ep0in";
 static const char	ep0_string[] = "ep0in";
 static DEFINE_SPINLOCK(udc_stall_spinlock);	/* stall spin lock */
 static DEFINE_SPINLOCK(udc_stall_spinlock);	/* stall spin lock */
-struct pch_udc_dev *pch_udc;		/* pointer to device object */
 static bool speed_fs;
 static bool speed_fs;
 module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
 module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
 MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
 MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
@@ -1235,9 +1235,10 @@ 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 *, struct usb_gadget_driver *));
-static int pch_udc_stop(struct usb_gadget_driver *driver);
+static int pch_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int pch_udc_stop(struct usb_gadget *g,
+		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,
@@ -1245,8 +1246,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,
+	.udc_start = pch_udc_start,
+	.udc_stop = pch_udc_stop,
 };
 };
 
 
 /**
 /**
@@ -2981,40 +2982,15 @@ static int init_dma_pools(struct pch_udc_dev *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int pch_udc_start(struct usb_gadget_driver *driver,
-	int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int pch_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pch_udc_dev	*dev = pch_udc;
-	int			retval;
-
-	if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind ||
-	    !driver->setup || !driver->unbind || !driver->disconnect) {
-		dev_err(&dev->pdev->dev,
-			"%s: invalid driver parameter\n", __func__);
-		return -EINVAL;
-	}
+	struct pch_udc_dev	*dev = to_pch_udc(g);
 
 
-	if (!dev)
-		return -ENODEV;
-
-	if (dev->driver) {
-		dev_err(&dev->pdev->dev, "%s: already bound\n", __func__);
-		return -EBUSY;
-	}
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 	dev->gadget.dev.driver = &driver->driver;
 
 
-	/* Invoke the bind routine of the gadget driver */
-	retval = bind(&dev->gadget, driver);
-
-	if (retval) {
-		dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n",
-		       __func__, driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
 	/* get ready for ep0 traffic */
 	/* get ready for ep0 traffic */
 	pch_udc_setup_ep0(dev);
 	pch_udc_setup_ep0(dev);
 
 
@@ -3026,30 +3002,21 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
 	return 0;
 	return 0;
 }
 }
 
 
-static int pch_udc_stop(struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pch_udc_dev	*dev = pch_udc;
-
-	if (!dev)
-		return -ENODEV;
-
-	if (!driver || (driver != dev->driver)) {
-		dev_err(&dev->pdev->dev,
-			"%s: invalid driver parameter\n", __func__);
-		return -EINVAL;
-	}
+	struct pch_udc_dev	*dev = to_pch_udc(g);
 
 
 	pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 	pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 
 
 	/* Assures that there are no pending requests with this driver */
 	/* Assures that there are no pending requests with this driver */
-	driver->disconnect(&dev->gadget);
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 	dev->driver = NULL;
 	dev->connected = 0;
 	dev->connected = 0;
 
 
 	/* set SD */
 	/* set SD */
 	pch_udc_set_disconnect(dev);
 	pch_udc_set_disconnect(dev);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3164,11 +3131,6 @@ static int pch_udc_probe(struct pci_dev *pdev,
 	int			retval;
 	int			retval;
 	struct pch_udc_dev	*dev;
 	struct pch_udc_dev	*dev;
 
 
-	/* one udc only */
-	if (pch_udc) {
-		pr_err("%s: already probed\n", __func__);
-		return -EBUSY;
-	}
 	/* init */
 	/* init */
 	dev = kzalloc(sizeof *dev, GFP_KERNEL);
 	dev = kzalloc(sizeof *dev, GFP_KERNEL);
 	if (!dev) {
 	if (!dev) {
@@ -3207,7 +3169,6 @@ static int pch_udc_probe(struct pci_dev *pdev,
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto finished;
 		goto finished;
 	}
 	}
-	pch_udc = dev;
 	/* initialize the hardware */
 	/* initialize the hardware */
 	if (pch_udc_pcd_init(dev)) {
 	if (pch_udc_pcd_init(dev)) {
 		retval = -ENODEV;
 		retval = -ENODEV;

+ 14 - 48
drivers/usb/gadget/pxa25x_udc.c

@@ -996,9 +996,10 @@ 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 *, struct usb_gadget_driver *));
-static int pxa25x_stop(struct usb_gadget_driver *driver);
+static int pxa25x_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int pxa25x_udc_stop(struct usb_gadget *g,
+		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,
@@ -1006,8 +1007,8 @@ static const struct usb_gadget_ops pxa25x_udc_ops = {
 	.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,
+	.udc_start	= pxa25x_udc_start,
+	.udc_stop	= pxa25x_udc_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1254,23 +1255,12 @@ 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.
  */
  */
-static int pxa25x_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int pxa25x_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pxa25x_udc	*dev = the_controller;
+	struct pxa25x_udc	*dev = to_pxa25x(g);
 	int			retval;
 	int			retval;
 
 
-	if (!driver
-			|| driver->max_speed < USB_SPEED_FULL
-			|| !bind
-			|| !driver->disconnect
-			|| !driver->setup)
-		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
-
 	/* first hook up the driver ... */
 	/* first hook up the driver ... */
 	dev->driver = driver;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 	dev->gadget.dev.driver = &driver->driver;
@@ -1278,34 +1268,20 @@ static int pxa25x_start(struct usb_gadget_driver *driver,
 
 
 	retval = device_add (&dev->gadget.dev);
 	retval = device_add (&dev->gadget.dev);
 	if (retval) {
 	if (retval) {
-fail:
 		dev->driver = NULL;
 		dev->driver = NULL;
 		dev->gadget.dev.driver = NULL;
 		dev->gadget.dev.driver = NULL;
 		return retval;
 		return retval;
 	}
 	}
-	retval = bind(&dev->gadget, driver);
-	if (retval) {
-		DMSG("bind to driver %s --> error %d\n",
-				driver->driver.name, retval);
-		device_del (&dev->gadget.dev);
-		goto fail;
-	}
 
 
 	/* ... then enable host detection and ep0; and we're ready
 	/* ... then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
 	 * for set_configuration as well as eventual disconnect.
 	 */
 	 */
-	DMSG("registered gadget driver '%s'\n", driver->driver.name);
-
 	/* connect to bus through transceiver */
 	/* connect to bus through transceiver */
 	if (!IS_ERR_OR_NULL(dev->transceiver)) {
 	if (!IS_ERR_OR_NULL(dev->transceiver)) {
 		retval = otg_set_peripheral(dev->transceiver->otg,
 		retval = otg_set_peripheral(dev->transceiver->otg,
 						&dev->gadget);
 						&dev->gadget);
-		if (retval) {
-			DMSG("can't bind to transceiver\n");
-			if (driver->unbind)
-				driver->unbind(&dev->gadget);
+		if (retval)
 			goto bind_fail;
 			goto bind_fail;
-		}
 	}
 	}
 
 
 	pullup(dev);
 	pullup(dev);
@@ -1334,22 +1310,14 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
 	}
 	}
 	del_timer_sync(&dev->timer);
 	del_timer_sync(&dev->timer);
 
 
-	/* report disconnect; the driver is already quiesced */
-	if (driver)
-		driver->disconnect(&dev->gadget);
-
 	/* re-init driver-visible data structures */
 	/* re-init driver-visible data structures */
 	udc_reinit(dev);
 	udc_reinit(dev);
 }
 }
 
 
-static int pxa25x_stop(struct usb_gadget_driver *driver)
+static int pxa25x_udc_stop(struct usb_gadget*g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pxa25x_udc	*dev = the_controller;
-
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver || !driver->unbind)
-		return -EINVAL;
+	struct pxa25x_udc	*dev = to_pxa25x(g);
 
 
 	local_irq_disable();
 	local_irq_disable();
 	dev->pullup = 0;
 	dev->pullup = 0;
@@ -1360,14 +1328,12 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
 	if (!IS_ERR_OR_NULL(dev->transceiver))
 	if (!IS_ERR_OR_NULL(dev->transceiver))
 		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 
 
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 	dev->driver = NULL;
 
 
 	device_del (&dev->gadget.dev);
 	device_del (&dev->gadget.dev);
-
-	DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
 	dump_state(dev);
 	dump_state(dev);
+
 	return 0;
 	return 0;
 }
 }
 
 

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

@@ -126,6 +126,7 @@ struct pxa25x_udc {
 	struct dentry				*debugfs_udc;
 	struct dentry				*debugfs_udc;
 #endif
 #endif
 };
 };
+#define to_pxa25x(g)	(container_of((g), struct pxa25x_udc, gadget))
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 

+ 15 - 46
drivers/usb/gadget/pxa27x_udc.c

@@ -1671,9 +1671,10 @@ 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 *, struct usb_gadget_driver *));
-static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
+static int pxa27x_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int pxa27x_udc_stop(struct usb_gadget *g,
+		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,
@@ -1681,8 +1682,8 @@ static const struct usb_gadget_ops pxa_udc_ops = {
 	.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,
+	.udc_start	= pxa27x_udc_start,
+	.udc_stop	= pxa27x_udc_stop,
 };
 };
 
 
 /**
 /**
@@ -1802,20 +1803,12 @@ 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
  */
  */
-static int pxa27x_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int pxa27x_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pxa_udc *udc = the_controller;
+	struct pxa_udc *udc = to_pxa(g);
 	int retval;
 	int retval;
 
 
-	if (!driver || driver->max_speed < USB_SPEED_FULL || !bind
-			|| !driver->disconnect || !driver->setup)
-		return -EINVAL;
-	if (!udc)
-		return -ENODEV;
-	if (udc->driver)
-		return -EBUSY;
-
 	/* first hook up the driver ... */
 	/* first hook up the driver ... */
 	udc->driver = driver;
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	udc->gadget.dev.driver = &driver->driver;
@@ -1824,23 +1817,14 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
 	retval = device_add(&udc->gadget.dev);
 	retval = device_add(&udc->gadget.dev);
 	if (retval) {
 	if (retval) {
 		dev_err(udc->dev, "device_add error %d\n", retval);
 		dev_err(udc->dev, "device_add error %d\n", retval);
-		goto add_fail;
+		goto fail;
 	}
 	}
-	retval = bind(&udc->gadget, driver);
-	if (retval) {
-		dev_err(udc->dev, "bind to driver %s --> error %d\n",
-			driver->driver.name, retval);
-		goto bind_fail;
-	}
-	dev_dbg(udc->dev, "registered gadget driver '%s'\n",
-		driver->driver.name);
-
 	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 		retval = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 						&udc->gadget);
 		if (retval) {
 		if (retval) {
 			dev_err(udc->dev, "can't bind to transceiver\n");
 			dev_err(udc->dev, "can't bind to transceiver\n");
-			goto transceiver_fail;
+			goto fail;
 		}
 		}
 	}
 	}
 
 
@@ -1848,12 +1832,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
 		udc_enable(udc);
 		udc_enable(udc);
 	return 0;
 	return 0;
 
 
-transceiver_fail:
-	if (driver->unbind)
-		driver->unbind(&udc->gadget);
-bind_fail:
-	device_del(&udc->gadget.dev);
-add_fail:
+fail:
 	udc->driver = NULL;
 	udc->driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	return retval;
 	return retval;
@@ -1878,9 +1857,6 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
 
 
 	for (i = 0; i < NR_USB_ENDPOINTS; i++)
 	for (i = 0; i < NR_USB_ENDPOINTS; i++)
 		pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
 		pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
-
-	if (driver)
-		driver->disconnect(&udc->gadget);
 }
 }
 
 
 /**
 /**
@@ -1889,25 +1865,18 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
  *
  *
  * Returns 0 if no error, -ENODEV, -EINVAL otherwise
  * Returns 0 if no error, -ENODEV, -EINVAL otherwise
  */
  */
-static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
+static int pxa27x_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct pxa_udc *udc = the_controller;
-
-	if (!udc)
-		return -ENODEV;
-	if (!driver || driver != udc->driver || !driver->unbind)
-		return -EINVAL;
+	struct pxa_udc *udc = to_pxa(g);
 
 
 	stop_activity(udc, driver);
 	stop_activity(udc, driver);
 	udc_disable(udc);
 	udc_disable(udc);
 	dplus_pullup(udc, 0);
 	dplus_pullup(udc, 0);
 
 
-	driver->unbind(&udc->gadget);
 	udc->driver = NULL;
 	udc->driver = NULL;
 
 
 	device_del(&udc->gadget.dev);
 	device_del(&udc->gadget.dev);
-	dev_info(udc->dev, "unregistered gadget driver '%s'\n",
-		 driver->driver.name);
 
 
 	if (!IS_ERR_OR_NULL(udc->transceiver))
 	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return otg_set_peripheral(udc->transceiver->otg, NULL);
 		return otg_set_peripheral(udc->transceiver->otg, NULL);

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

@@ -473,6 +473,7 @@ struct pxa_udc {
 	struct dentry				*debugfs_eps;
 	struct dentry				*debugfs_eps;
 #endif
 #endif
 };
 };
+#define to_pxa(g)	(container_of((g), struct pxa_udc, gadget))
 
 
 static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
 static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
 {
 {

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

@@ -1812,7 +1812,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct usb_gadget_ops r8a66597_gadget_ops = {
+static const struct usb_gadget_ops r8a66597_gadget_ops = {
 	.get_frame		= r8a66597_get_frame,
 	.get_frame		= r8a66597_get_frame,
 	.udc_start		= r8a66597_start,
 	.udc_start		= r8a66597_start,
 	.udc_stop		= r8a66597_stop,
 	.udc_stop		= r8a66597_stop,

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

@@ -32,6 +32,7 @@
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/phy.h>
 #include <linux/platform_data/s3c-hsotg.h>
 #include <linux/platform_data/s3c-hsotg.h>
 
 
 #include <mach/map.h>
 #include <mach/map.h>
@@ -133,7 +134,9 @@ struct s3c_hsotg_ep {
  * struct s3c_hsotg - driver state.
  * struct s3c_hsotg - driver state.
  * @dev: The parent device supplied to the probe function
  * @dev: The parent device supplied to the probe function
  * @driver: USB gadget driver
  * @driver: USB gadget driver
- * @plat: The platform specific configuration data.
+ * @phy: The otg phy transceiver structure for phy control.
+ * @plat: The platform specific configuration data. This can be removed once
+ * all SoCs support usb transceiver.
  * @regs: The memory area mapped for accessing registers.
  * @regs: The memory area mapped for accessing registers.
  * @irq: The IRQ number we are using
  * @irq: The IRQ number we are using
  * @supplies: Definition of USB power supplies
  * @supplies: Definition of USB power supplies
@@ -153,6 +156,7 @@ struct s3c_hsotg_ep {
 struct s3c_hsotg {
 struct s3c_hsotg {
 	struct device		 *dev;
 	struct device		 *dev;
 	struct usb_gadget_driver *driver;
 	struct usb_gadget_driver *driver;
+	struct usb_phy		*phy;
 	struct s3c_hsotg_plat	 *plat;
 	struct s3c_hsotg_plat	 *plat;
 
 
 	spinlock_t              lock;
 	spinlock_t              lock;
@@ -2854,7 +2858,10 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
 
 	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
 	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
-	if (hsotg->plat->phy_init)
+
+	if (hsotg->phy)
+		usb_phy_init(hsotg->phy);
+	else if (hsotg->plat->phy_init)
 		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 }
 }
 
 
@@ -2869,7 +2876,9 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
 {
 {
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
 
-	if (hsotg->plat->phy_exit)
+	if (hsotg->phy)
+		usb_phy_shutdown(hsotg->phy);
+	else if (hsotg->plat->phy_exit)
 		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
 		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
 }
 }
 
 
@@ -3055,7 +3064,7 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
+static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.udc_start		= s3c_hsotg_udc_start,
 	.udc_start		= s3c_hsotg_udc_start,
 	.udc_stop		= s3c_hsotg_udc_stop,
 	.udc_stop		= s3c_hsotg_udc_stop,
@@ -3492,6 +3501,7 @@ static void s3c_hsotg_release(struct device *dev)
 static int s3c_hsotg_probe(struct platform_device *pdev)
 static int s3c_hsotg_probe(struct platform_device *pdev)
 {
 {
 	struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
 	struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+	struct usb_phy *phy;
 	struct device *dev = &pdev->dev;
 	struct device *dev = &pdev->dev;
 	struct s3c_hsotg_ep *eps;
 	struct s3c_hsotg_ep *eps;
 	struct s3c_hsotg *hsotg;
 	struct s3c_hsotg *hsotg;
@@ -3500,20 +3510,27 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
 	int ret;
 	int ret;
 	int i;
 	int i;
 
 
-	plat = pdev->dev.platform_data;
-	if (!plat) {
-		dev_err(&pdev->dev, "no platform data defined\n");
-		return -EINVAL;
-	}
-
 	hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
 	hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
 	if (!hsotg) {
 	if (!hsotg) {
 		dev_err(dev, "cannot get memory\n");
 		dev_err(dev, "cannot get memory\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
+	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(phy)) {
+		/* Fallback for pdata */
+		plat = pdev->dev.platform_data;
+		if (!plat) {
+			dev_err(&pdev->dev, "no platform data or transceiver defined\n");
+			return -EPROBE_DEFER;
+		} else {
+			hsotg->plat = plat;
+		}
+	} else {
+		hsotg->phy = phy;
+	}
+
 	hsotg->dev = dev;
 	hsotg->dev = dev;
-	hsotg->plat = plat;
 
 
 	hsotg->clk = devm_clk_get(&pdev->dev, "otg");
 	hsotg->clk = devm_clk_get(&pdev->dev, "otg");
 	if (IS_ERR(hsotg->clk)) {
 	if (IS_ERR(hsotg->clk)) {
@@ -3571,7 +3588,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
 	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
 		hsotg->supplies[i].supply = s3c_hsotg_supply_names[i];
 		hsotg->supplies[i].supply = s3c_hsotg_supply_names[i];
 
 
-	ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
 				 hsotg->supplies);
 				 hsotg->supplies);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "failed to request supplies: %d\n", ret);
 		dev_err(dev, "failed to request supplies: %d\n", ret);
@@ -3661,8 +3678,6 @@ err_ep_mem:
 	kfree(eps);
 	kfree(eps);
 err_supplies:
 err_supplies:
 	s3c_hsotg_phy_disable(hsotg);
 	s3c_hsotg_phy_disable(hsotg);
-	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
-
 err_clk:
 err_clk:
 	clk_disable_unprepare(hsotg->clk);
 	clk_disable_unprepare(hsotg->clk);
 
 
@@ -3687,7 +3702,6 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
 	}
 	}
 
 
 	s3c_hsotg_phy_disable(hsotg);
 	s3c_hsotg_phy_disable(hsotg);
-	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
 
 	clk_disable_unprepare(hsotg->clk);
 	clk_disable_unprepare(hsotg->clk);
 
 

+ 6 - 7
drivers/usb/gadget/s3c-hsudc.c

@@ -435,7 +435,7 @@ static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
 	struct s3c_hsudc_req *hsreq;
 	struct s3c_hsudc_req *hsreq;
 	u32 csr;
 	u32 csr;
 
 
-	csr = readl((u32)hsudc->regs + S3C_ESR);
+	csr = readl(hsudc->regs + S3C_ESR);
 	if (csr & S3C_ESR_STALL) {
 	if (csr & S3C_ESR_STALL) {
 		writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
 		writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
 		return;
 		return;
@@ -468,7 +468,7 @@ static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
 	struct s3c_hsudc_req *hsreq;
 	struct s3c_hsudc_req *hsreq;
 	u32 csr;
 	u32 csr;
 
 
-	csr = readl((u32)hsudc->regs + S3C_ESR);
+	csr = readl(hsudc->regs + S3C_ESR);
 	if (csr & S3C_ESR_STALL) {
 	if (csr & S3C_ESR_STALL) {
 		writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
 		writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
 		return;
 		return;
@@ -901,12 +901,12 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req,
 	if (list_empty(&hsep->queue) && !hsep->stopped) {
 	if (list_empty(&hsep->queue) && !hsep->stopped) {
 		offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
 		offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
 		if (ep_is_in(hsep)) {
 		if (ep_is_in(hsep)) {
-			csr = readl((u32)hsudc->regs + offset);
+			csr = readl(hsudc->regs + offset);
 			if (!(csr & S3C_ESR_TX_SUCCESS) &&
 			if (!(csr & S3C_ESR_TX_SUCCESS) &&
 				(s3c_hsudc_write_fifo(hsep, hsreq) == 1))
 				(s3c_hsudc_write_fifo(hsep, hsreq) == 1))
 				hsreq = NULL;
 				hsreq = NULL;
 		} else {
 		} else {
-			csr = readl((u32)hsudc->regs + offset);
+			csr = readl(hsudc->regs + offset);
 			if ((csr & S3C_ESR_RX_SUCCESS)
 			if ((csr & S3C_ESR_RX_SUCCESS)
 				   && (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
 				   && (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
 				hsreq = NULL;
 				hsreq = NULL;
@@ -1254,7 +1254,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
-static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
+static const struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.get_frame	= s3c_hsudc_gadget_getframe,
 	.get_frame	= s3c_hsudc_gadget_getframe,
 	.udc_start	= s3c_hsudc_start,
 	.udc_start	= s3c_hsudc_start,
 	.udc_stop	= s3c_hsudc_stop,
 	.udc_stop	= s3c_hsudc_stop,
@@ -1286,7 +1286,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
 
 
-	ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
 				 hsudc->supplies);
 				 hsudc->supplies);
 	if (ret != 0) {
 	if (ret != 0) {
 		dev_err(dev, "failed to request supplies: %d\n", ret);
 		dev_err(dev, "failed to request supplies: %d\n", ret);
@@ -1366,7 +1366,6 @@ err_res:
 	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		usb_put_phy(hsudc->transceiver);
 		usb_put_phy(hsudc->transceiver);
 
 
-	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
 err_supplies:
 	return ret;
 	return ret;
 }
 }

+ 12 - 53
drivers/usb/gadget/s3c2410_udc.c

@@ -1538,9 +1538,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 *, struct usb_gadget_driver *));
-static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
+static int s3c2410_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int s3c2410_udc_stop(struct usb_gadget *g,
+		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,
@@ -1549,8 +1550,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,
+	.udc_start		= s3c2410_udc_start,
+	.udc_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)
@@ -1664,33 +1665,14 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
 	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
 	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
 }
 }
 
 
-static int s3c2410_udc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
+static int s3c2410_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct s3c2410_udc *udc = the_controller;
+	struct s3c2410_udc *udc = to_s3c2410(g)
 	int		retval;
 	int		retval;
 
 
 	dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name);
 	dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name);
 
 
-	/* Sanity checks */
-	if (!udc)
-		return -ENODEV;
-
-	if (udc->driver)
-		return -EBUSY;
-
-	if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
-		dev_err(&udc->gadget.dev, "Invalid driver: bind %p setup %p speed %d\n",
-			bind, driver->setup, driver->max_speed);
-		return -EINVAL;
-	}
-#if defined(MODULE)
-	if (!driver->unbind) {
-		dev_err(&udc->gadget.dev, "Invalid driver: no unbind method\n");
-		return -EINVAL;
-	}
-#endif
-
 	/* Hook the driver */
 	/* Hook the driver */
 	udc->driver = driver;
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	udc->gadget.dev.driver = &driver->driver;
@@ -1702,15 +1684,6 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver,
 		goto register_error;
 		goto register_error;
 	}
 	}
 
 
-	dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
-		driver->driver.name);
-
-	retval = bind(&udc->gadget, driver);
-	if (retval) {
-		device_del(&udc->gadget.dev);
-		goto register_error;
-	}
-
 	/* Enable udc */
 	/* Enable udc */
 	s3c2410_udc_enable(udc);
 	s3c2410_udc_enable(udc);
 
 
@@ -1722,24 +1695,10 @@ register_error:
 	return retval;
 	return retval;
 }
 }
 
 
-static int s3c2410_udc_stop(struct usb_gadget_driver *driver)
+static int s3c2410_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct s3c2410_udc *udc = the_controller;
-
-	if (!udc)
-		return -ENODEV;
-
-	if (!driver || driver != udc->driver || !driver->unbind)
-		return -EINVAL;
-
-	dprintk(DEBUG_NORMAL, "usb_gadget_unregister_driver() '%s'\n",
-		driver->driver.name);
-
-	/* report disconnect */
-	if (driver->disconnect)
-		driver->disconnect(&udc->gadget);
-
-	driver->unbind(&udc->gadget);
+	struct s3c2410_udc *udc = to_s3c2410(g);
 
 
 	device_del(&udc->gadget.dev);
 	device_del(&udc->gadget.dev);
 	udc->driver = NULL;
 	udc->driver = NULL;

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

@@ -95,5 +95,6 @@ struct s3c2410_udc {
 	u8				vbus;
 	u8				vbus;
 	struct dentry			*regs_info;
 	struct dentry			*regs_info;
 };
 };
+#define to_s3c2410(g)	(container_of((g), struct s3c2410_udc, gadget))
 
 
 #endif
 #endif

+ 100 - 18
drivers/usb/gadget/serial.c

@@ -36,10 +36,8 @@
  * the runtime footprint, and giving us at least some parts of what
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
  */
-#include "f_acm.c"
 #include "f_obex.c"
 #include "f_obex.c"
 #include "f_serial.c"
 #include "f_serial.c"
-#include "u_serial.c"
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 USB_GADGET_COMPOSITE_OPTIONS();
 USB_GADGET_COMPOSITE_OPTIONS();
@@ -128,20 +126,25 @@ module_param(n_ports, uint, 0);
 MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
 MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
+static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
 
 
-static int __init serial_bind_config(struct usb_configuration *c)
+static int __init serial_bind_obex_config(struct usb_configuration *c)
 {
 {
 	unsigned i;
 	unsigned i;
 	int status = 0;
 	int status = 0;
 
 
-	for (i = 0; i < n_ports && status == 0; i++) {
-		if (use_acm)
-			status = acm_bind_config(c, i);
-		else if (use_obex)
-			status = obex_bind_config(c, i);
-		else
-			status = gser_bind_config(c, i);
-	}
+	for (i = 0; i < n_ports && status == 0; i++)
+		status = obex_bind_config(c, tty_lines[i]);
+	return status;
+}
+
+static int __init serial_bind_gser_config(struct usb_configuration *c)
+{
+	unsigned i;
+	int status = 0;
+
+	for (i = 0; i < n_ports && status == 0; i++)
+		status = gser_bind_config(c, tty_lines[i]);
 	return status;
 	return status;
 }
 }
 
 
@@ -152,13 +155,70 @@ static struct usb_configuration serial_config_driver = {
 	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,
 	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,
 };
 };
 
 
+static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS];
+static struct usb_function *f_serial[MAX_U_SERIAL_PORTS];
+
+static int serial_register_ports(struct usb_composite_dev *cdev,
+		struct usb_configuration *c, const char *f_name)
+{
+	int i;
+	int ret;
+
+	ret = usb_add_config_only(cdev, c);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < n_ports; i++) {
+		struct f_serial_opts *opts;
+
+		fi_serial[i] = usb_get_function_instance(f_name);
+		if (IS_ERR(fi_serial[i])) {
+			ret = PTR_ERR(fi_serial[i]);
+			goto fail;
+		}
+		opts = container_of(fi_serial[i], struct f_serial_opts, func_inst);
+		opts->port_num = tty_lines[i];
+
+		f_serial[i] = usb_get_function(fi_serial[i]);
+		if (IS_ERR(f_serial[i])) {
+			ret = PTR_ERR(f_serial[i]);
+			goto err_get_func;
+		}
+
+		ret = usb_add_function(c, f_serial[i]);
+		if (ret)
+			goto err_add_func;
+	}
+
+	return 0;
+
+err_add_func:
+	usb_put_function(f_serial[i]);
+err_get_func:
+	usb_put_function_instance(fi_serial[i]);
+
+fail:
+	i--;
+	while (i >= 0) {
+		usb_remove_function(c, f_serial[i]);
+		usb_put_function(f_serial[i]);
+		usb_put_function_instance(fi_serial[i]);
+		i--;
+	}
+out:
+	return ret;
+}
+
 static int __init gs_bind(struct usb_composite_dev *cdev)
 static int __init gs_bind(struct usb_composite_dev *cdev)
 {
 {
 	int			status;
 	int			status;
+	int			cur_line;
 
 
-	status = gserial_setup(cdev->gadget, n_ports);
-	if (status < 0)
-		return status;
+	for (cur_line = 0; cur_line < n_ports; cur_line++) {
+		status = gserial_alloc_line(&tty_lines[cur_line]);
+		if (status)
+			goto fail;
+	}
 
 
 	/* Allocate string descriptor numbers ... note that string
 	/* Allocate string descriptor numbers ... note that string
 	 * contents can be overridden by the composite_dev glue.
 	 * contents can be overridden by the composite_dev glue.
@@ -178,8 +238,16 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
 	}
 	}
 
 
 	/* register our configuration */
 	/* register our configuration */
-	status = usb_add_config(cdev, &serial_config_driver,
-			serial_bind_config);
+	if (use_acm) {
+		status  = serial_register_ports(cdev, &serial_config_driver,
+				"acm");
+		usb_ep_autoconfig_reset(cdev->gadget);
+	} else if (use_obex)
+		status = usb_add_config(cdev, &serial_config_driver,
+				serial_bind_obex_config);
+	else
+		status = usb_add_config(cdev, &serial_config_driver,
+				serial_bind_gser_config);
 	if (status < 0)
 	if (status < 0)
 		goto fail;
 		goto fail;
 
 
@@ -189,16 +257,31 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
 	return 0;
 	return 0;
 
 
 fail:
 fail:
-	gserial_cleanup();
+	cur_line--;
+	while (cur_line >= 0)
+		gserial_free_line(tty_lines[cur_line--]);
 	return status;
 	return status;
 }
 }
 
 
+static int gs_unbind(struct usb_composite_dev *cdev)
+{
+	int i;
+
+	for (i = 0; i < n_ports; i++) {
+		usb_put_function(f_serial[i]);
+		usb_put_function_instance(fi_serial[i]);
+		gserial_free_line(tty_lines[i]);
+	}
+	return 0;
+}
+
 static __refdata struct usb_composite_driver gserial_driver = {
 static __refdata 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_SUPER,
 	.max_speed	= USB_SPEED_SUPER,
 	.bind		= gs_bind,
 	.bind		= gs_bind,
+	.unbind		= gs_unbind,
 };
 };
 
 
 static int __init init(void)
 static int __init init(void)
@@ -234,6 +317,5 @@ module_init(init);
 static void __exit cleanup(void)
 static void __exit cleanup(void)
 {
 {
 	usb_composite_unregister(&gserial_driver);
 	usb_composite_unregister(&gserial_driver);
-	gserial_cleanup();
 }
 }
 module_exit(cleanup);
 module_exit(cleanup);

+ 0 - 61
drivers/usb/gadget/storage_common.c

@@ -93,18 +93,6 @@
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/* CBI Interrupt data structure */
-struct interrupt_data {
-	u8	bType;
-	u8	bValue;
-};
-
-#define CBI_INTERRUPT_DATA_LEN		2
-
-/* CBI Accept Device-Specific Command request */
-#define USB_CBI_ADSC_REQUEST		0x00
-
-
 /* Length of a SCSI Command Data Block */
 /* Length of a SCSI Command Data Block */
 #define MAX_COMMAND_SIZE	16
 #define MAX_COMMAND_SIZE	16
 
 
@@ -385,41 +373,6 @@ static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
 	/*.bMaxBurst =		DYNAMIC, */
 	/*.bMaxBurst =		DYNAMIC, */
 };
 };
 
 
-static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
-	.bLength =		USB_DT_USB_EXT_CAP_SIZE,
-	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
-	.bDevCapabilityType =	USB_CAP_TYPE_EXT,
-
-	.bmAttributes =		cpu_to_le32(USB_LPM_SUPPORT),
-};
-
-static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
-	.bLength =		USB_DT_USB_SS_CAP_SIZE,
-	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
-	.bDevCapabilityType =	USB_SS_CAP_TYPE,
-
-	/* .bmAttributes = LTM is not supported yet */
-
-	.wSpeedSupported =	cpu_to_le16(USB_LOW_SPEED_OPERATION
-		| USB_FULL_SPEED_OPERATION
-		| USB_HIGH_SPEED_OPERATION
-		| USB_5GBPS_OPERATION),
-	.bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
-	.bU1devExitLat =	USB_DEFAULT_U1_DEV_EXIT_LAT,
-	.bU2DevExitLat =	cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT),
-};
-
-static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
-	.bLength =		USB_DT_BOS_SIZE,
-	.bDescriptorType =	USB_DT_BOS,
-
-	.wTotalLength =		cpu_to_le16(USB_DT_BOS_SIZE
-				+ USB_DT_USB_EXT_CAP_SIZE
-				+ USB_DT_USB_SS_CAP_SIZE),
-
-	.bNumDeviceCaps =	2,
-};
-
 static struct usb_descriptor_header *fsg_ss_function[] = {
 static struct usb_descriptor_header *fsg_ss_function[] = {
 	(struct usb_descriptor_header *) &fsg_intf_desc,
 	(struct usb_descriptor_header *) &fsg_intf_desc,
 	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
 	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
@@ -429,20 +382,6 @@ static struct usb_descriptor_header *fsg_ss_function[] = {
 	NULL,
 	NULL,
 };
 };
 
 
-/* Maxpacket and other transfer characteristics vary by speed. */
-static __maybe_unused struct usb_endpoint_descriptor *
-fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
-		struct usb_endpoint_descriptor *hs,
-		struct usb_endpoint_descriptor *ss)
-{
-	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
-		return ss;
-	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-		return hs;
-	return fs;
-}
-
-
 /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
 /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
 static struct usb_string		fsg_strings[] = {
 static struct usb_string		fsg_strings[] = {
 	{FSG_STRING_INTERFACE,		fsg_string_interface},
 	{FSG_STRING_INTERFACE,		fsg_string_interface},

+ 157 - 156
drivers/usb/gadget/u_serial.c

@@ -26,6 +26,7 @@
 #include <linux/tty_flip.h>
 #include <linux/tty_flip.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/export.h>
+#include <linux/module.h>
 
 
 #include "u_serial.h"
 #include "u_serial.h"
 
 
@@ -35,11 +36,12 @@
  * "serial port" functionality through the USB gadget stack.  Each such
  * "serial port" functionality through the USB gadget stack.  Each such
  * port is exposed through a /dev/ttyGS* node.
  * port is exposed through a /dev/ttyGS* node.
  *
  *
- * After initialization (gserial_setup), these TTY port devices stay
- * available until they are removed (gserial_cleanup).  Each one may be
- * connected to a USB function (gserial_connect), or disconnected (with
- * gserial_disconnect) when the USB host issues a config change event.
- * Data can only flow when the port is connected to the host.
+ * After this module has been loaded, the individual TTY port can be requested
+ * (gserial_alloc_line()) and it will stay available until they are removed
+ * (gserial_free_line()). Each one may be connected to a USB function
+ * (gserial_connect), or disconnected (with gserial_disconnect) when the USB
+ * host issues a config change event. Data can only flow when the port is
+ * connected to the host.
  *
  *
  * A given TTY port can be made available in multiple configurations.
  * A given TTY port can be made available in multiple configurations.
  * For example, each one might expose a ttyGS0 node which provides a
  * For example, each one might expose a ttyGS0 node which provides a
@@ -119,13 +121,10 @@ struct gs_port {
 	struct usb_cdc_line_coding port_line_coding;	/* 8-N-1 etc */
 	struct usb_cdc_line_coding port_line_coding;	/* 8-N-1 etc */
 };
 };
 
 
-/* increase N_PORTS if you need more */
-#define N_PORTS		4
 static struct portmaster {
 static struct portmaster {
 	struct mutex	lock;			/* protect open/close */
 	struct mutex	lock;			/* protect open/close */
 	struct gs_port	*port;
 	struct gs_port	*port;
-} ports[N_PORTS];
-static unsigned	n_ports;
+} ports[MAX_U_SERIAL_PORTS];
 
 
 #define GS_CLOSE_TIMEOUT		15		/* seconds */
 #define GS_CLOSE_TIMEOUT		15		/* seconds */
 
 
@@ -309,6 +308,7 @@ gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
 
 
 	return req;
 	return req;
 }
 }
+EXPORT_SYMBOL_GPL(gs_alloc_req);
 
 
 /*
 /*
  * gs_free_req
  * gs_free_req
@@ -320,6 +320,7 @@ void gs_free_req(struct usb_ep *ep, struct usb_request *req)
 	kfree(req->buf);
 	kfree(req->buf);
 	usb_ep_free_request(ep, req);
 	usb_ep_free_request(ep, req);
 }
 }
+EXPORT_SYMBOL_GPL(gs_free_req);
 
 
 /*
 /*
  * gs_send_packet
  * gs_send_packet
@@ -1030,10 +1031,19 @@ static int
 gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
 gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
 {
 {
 	struct gs_port	*port;
 	struct gs_port	*port;
+	int		ret = 0;
+
+	mutex_lock(&ports[port_num].lock);
+	if (ports[port_num].port) {
+		ret = -EBUSY;
+		goto out;
+	}
 
 
 	port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
 	port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
-	if (port == NULL)
-		return -ENOMEM;
+	if (port == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 
 	tty_port_init(&port->port);
 	tty_port_init(&port->port);
 	spin_lock_init(&port->port_lock);
 	spin_lock_init(&port->port_lock);
@@ -1049,109 +1059,9 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
 	port->port_line_coding = *coding;
 	port->port_line_coding = *coding;
 
 
 	ports[port_num].port = port;
 	ports[port_num].port = port;
-
-	return 0;
-}
-
-/**
- * gserial_setup - initialize TTY driver for one or more ports
- * @g: gadget to associate with these ports
- * @count: how many ports to support
- * Context: may sleep
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage.  Use this call to set up the ports you will be
- * exporting through USB.  Later, connect them to functions based
- * on what configuration is activated by the USB host; and disconnect
- * them as appropriate.
- *
- * An example would be a two-configuration device in which both
- * configurations expose port 0, but through different functions.
- * One configuration could even expose port 1 while the other
- * one doesn't.
- *
- * Returns negative errno or zero.
- */
-int gserial_setup(struct usb_gadget *g, unsigned count)
-{
-	unsigned			i;
-	struct usb_cdc_line_coding	coding;
-	int				status;
-
-	if (count == 0 || count > N_PORTS)
-		return -EINVAL;
-
-	gs_tty_driver = alloc_tty_driver(count);
-	if (!gs_tty_driver)
-		return -ENOMEM;
-
-	gs_tty_driver->driver_name = "g_serial";
-	gs_tty_driver->name = PREFIX;
-	/* uses dynamically assigned dev_t values */
-
-	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-	gs_tty_driver->init_termios = tty_std_termios;
-
-	/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
-	 * MS-Windows.  Otherwise, most of these flags shouldn't affect
-	 * anything unless we were to actually hook up to a serial line.
-	 */
-	gs_tty_driver->init_termios.c_cflag =
-			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	gs_tty_driver->init_termios.c_ispeed = 9600;
-	gs_tty_driver->init_termios.c_ospeed = 9600;
-
-	coding.dwDTERate = cpu_to_le32(9600);
-	coding.bCharFormat = 8;
-	coding.bParityType = USB_CDC_NO_PARITY;
-	coding.bDataBits = USB_CDC_1_STOP_BITS;
-
-	tty_set_operations(gs_tty_driver, &gs_tty_ops);
-
-	/* make devices be openable */
-	for (i = 0; i < count; i++) {
-		mutex_init(&ports[i].lock);
-		status = gs_port_alloc(i, &coding);
-		if (status) {
-			count = i;
-			goto fail;
-		}
-	}
-	n_ports = count;
-
-	/* export the driver ... */
-	status = tty_register_driver(gs_tty_driver);
-	if (status) {
-		pr_err("%s: cannot register, err %d\n",
-				__func__, status);
-		goto fail;
-	}
-
-	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
-	for (i = 0; i < count; i++) {
-		struct device	*tty_dev;
-
-		tty_dev = tty_port_register_device(&ports[i].port->port,
-				gs_tty_driver, i, &g->dev);
-		if (IS_ERR(tty_dev))
-			pr_warning("%s: no classdev for port %d, err %ld\n",
-				__func__, i, PTR_ERR(tty_dev));
-	}
-
-	pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
-			count, (count == 1) ? "" : "s");
-
-	return status;
-fail:
-	while (count--) {
-		tty_port_destroy(&ports[count].port->port);
-		kfree(ports[count].port);
-	}
-	put_tty_driver(gs_tty_driver);
-	gs_tty_driver = NULL;
-	return status;
+out:
+	mutex_unlock(&ports[port_num].lock);
+	return ret;
 }
 }
 
 
 static int gs_closed(struct gs_port *port)
 static int gs_closed(struct gs_port *port)
@@ -1164,55 +1074,77 @@ static int gs_closed(struct gs_port *port)
 	return cond;
 	return cond;
 }
 }
 
 
-/**
- * gserial_cleanup - remove TTY-over-USB driver and devices
- * Context: may sleep
- *
- * This is called to free all resources allocated by @gserial_setup().
- * Accordingly, it may need to wait until some open /dev/ files have
- * closed.
- *
- * The caller must have issued @gserial_disconnect() for any ports
- * that had previously been connected, so that there is never any
- * I/O pending when it's called.
- */
-void gserial_cleanup(void)
+static void gserial_free_port(struct gs_port *port)
+{
+	tasklet_kill(&port->push);
+	/* wait for old opens to finish */
+	wait_event(port->port.close_wait, gs_closed(port));
+	WARN_ON(port->port_usb != NULL);
+	tty_port_destroy(&port->port);
+	kfree(port);
+}
+
+void gserial_free_line(unsigned char port_num)
 {
 {
-	unsigned	i;
 	struct gs_port	*port;
 	struct gs_port	*port;
 
 
-	if (!gs_tty_driver)
+	mutex_lock(&ports[port_num].lock);
+	if (WARN_ON(!ports[port_num].port)) {
+		mutex_unlock(&ports[port_num].lock);
 		return;
 		return;
+	}
+	port = ports[port_num].port;
+	ports[port_num].port = NULL;
+	mutex_unlock(&ports[port_num].lock);
 
 
-	/* start sysfs and /dev/ttyGS* node removal */
-	for (i = 0; i < n_ports; i++)
-		tty_unregister_device(gs_tty_driver, i);
-
-	for (i = 0; i < n_ports; i++) {
-		/* prevent new opens */
-		mutex_lock(&ports[i].lock);
-		port = ports[i].port;
-		ports[i].port = NULL;
-		mutex_unlock(&ports[i].lock);
-
-		tasklet_kill(&port->push);
+	gserial_free_port(port);
+	tty_unregister_device(gs_tty_driver, port_num);
+}
+EXPORT_SYMBOL_GPL(gserial_free_line);
 
 
-		/* wait for old opens to finish */
-		wait_event(port->port.close_wait, gs_closed(port));
+int gserial_alloc_line(unsigned char *line_num)
+{
+	struct usb_cdc_line_coding	coding;
+	struct device			*tty_dev;
+	int				ret;
+	int				port_num;
 
 
-		WARN_ON(port->port_usb != NULL);
+	coding.dwDTERate = cpu_to_le32(9600);
+	coding.bCharFormat = 8;
+	coding.bParityType = USB_CDC_NO_PARITY;
+	coding.bDataBits = USB_CDC_1_STOP_BITS;
 
 
-		tty_port_destroy(&port->port);
-		kfree(port);
+	for (port_num = 0; port_num < MAX_U_SERIAL_PORTS; port_num++) {
+		ret = gs_port_alloc(port_num, &coding);
+		if (ret == -EBUSY)
+			continue;
+		if (ret)
+			return ret;
+		break;
 	}
 	}
-	n_ports = 0;
+	if (ret)
+		return ret;
 
 
-	tty_unregister_driver(gs_tty_driver);
-	put_tty_driver(gs_tty_driver);
-	gs_tty_driver = NULL;
+	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
+
+	tty_dev = tty_port_register_device(&ports[port_num].port->port,
+			gs_tty_driver, port_num, NULL);
+	if (IS_ERR(tty_dev)) {
+		struct gs_port	*port;
+		pr_err("%s: failed to register tty for port %d, err %ld\n",
+				__func__, port_num, PTR_ERR(tty_dev));
 
 
-	pr_debug("%s: cleaned up ttyGS* support\n", __func__);
+		ret = PTR_ERR(tty_dev);
+		port = ports[port_num].port;
+		ports[port_num].port = NULL;
+		gserial_free_port(port);
+		goto err;
+	}
+	*line_num = port_num;
+err:
+	return ret;
 }
 }
+EXPORT_SYMBOL_GPL(gserial_alloc_line);
 
 
 /**
 /**
  * gserial_connect - notify TTY I/O glue that USB link is active
  * gserial_connect - notify TTY I/O glue that USB link is active
@@ -1229,8 +1161,8 @@ void gserial_cleanup(void)
  *
  *
  * Caller needs to have set up the endpoints and USB function in @dev
  * Caller needs to have set up the endpoints and USB function in @dev
  * before calling this, as well as the appropriate (speed-specific)
  * before calling this, as well as the appropriate (speed-specific)
- * endpoint descriptors, and also have set up the TTY driver by calling
- * @gserial_setup().
+ * endpoint descriptors, and also have allocate @port_num by calling
+ * @gserial_alloc_line().
  *
  *
  * Returns negative errno or zero.
  * Returns negative errno or zero.
  * On success, ep->driver_data will be overwritten.
  * On success, ep->driver_data will be overwritten.
@@ -1241,11 +1173,18 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	unsigned long	flags;
 	unsigned long	flags;
 	int		status;
 	int		status;
 
 
-	if (!gs_tty_driver || port_num >= n_ports)
+	if (port_num >= MAX_U_SERIAL_PORTS)
 		return -ENXIO;
 		return -ENXIO;
 
 
-	/* we "know" gserial_cleanup() hasn't been called */
 	port = ports[port_num].port;
 	port = ports[port_num].port;
+	if (!port) {
+		pr_err("serial line %d not allocated.\n", port_num);
+		return -EINVAL;
+	}
+	if (port->port_usb) {
+		pr_err("serial line %d is in use.\n", port_num);
+		return -EBUSY;
+	}
 
 
 	/* activate the endpoints */
 	/* activate the endpoints */
 	status = usb_ep_enable(gser->in);
 	status = usb_ep_enable(gser->in);
@@ -1292,7 +1231,7 @@ fail_out:
 	gser->in->driver_data = NULL;
 	gser->in->driver_data = NULL;
 	return status;
 	return status;
 }
 }
-
+EXPORT_SYMBOL_GPL(gserial_connect);
 /**
 /**
  * gserial_disconnect - notify TTY I/O glue that USB link is inactive
  * gserial_disconnect - notify TTY I/O glue that USB link is inactive
  * @gser: the function, on which gserial_connect() was called
  * @gser: the function, on which gserial_connect() was called
@@ -1347,3 +1286,65 @@ void gserial_disconnect(struct gserial *gser)
 
 
 	spin_unlock_irqrestore(&port->port_lock, flags);
 	spin_unlock_irqrestore(&port->port_lock, flags);
 }
 }
+EXPORT_SYMBOL_GPL(gserial_disconnect);
+
+static int userial_init(void)
+{
+	unsigned			i;
+	int				status;
+
+	gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS);
+	if (!gs_tty_driver)
+		return -ENOMEM;
+
+	gs_tty_driver->driver_name = "g_serial";
+	gs_tty_driver->name = PREFIX;
+	/* uses dynamically assigned dev_t values */
+
+	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	gs_tty_driver->init_termios = tty_std_termios;
+
+	/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
+	 * MS-Windows.  Otherwise, most of these flags shouldn't affect
+	 * anything unless we were to actually hook up to a serial line.
+	 */
+	gs_tty_driver->init_termios.c_cflag =
+			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	gs_tty_driver->init_termios.c_ispeed = 9600;
+	gs_tty_driver->init_termios.c_ospeed = 9600;
+
+	tty_set_operations(gs_tty_driver, &gs_tty_ops);
+	for (i = 0; i < MAX_U_SERIAL_PORTS; i++)
+		mutex_init(&ports[i].lock);
+
+	/* export the driver ... */
+	status = tty_register_driver(gs_tty_driver);
+	if (status) {
+		pr_err("%s: cannot register, err %d\n",
+				__func__, status);
+		goto fail;
+	}
+
+	pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
+			MAX_U_SERIAL_PORTS,
+			(MAX_U_SERIAL_PORTS == 1) ? "" : "s");
+
+	return status;
+fail:
+	put_tty_driver(gs_tty_driver);
+	gs_tty_driver = NULL;
+	return status;
+}
+module_init(userial_init);
+
+static void userial_cleanup(void)
+{
+	tty_unregister_driver(gs_tty_driver);
+	put_tty_driver(gs_tty_driver);
+	gs_tty_driver = NULL;
+}
+module_exit(userial_cleanup);
+
+MODULE_LICENSE("GPL");

+ 10 - 3
drivers/usb/gadget/u_serial.h

@@ -15,6 +15,13 @@
 #include <linux/usb/composite.h>
 #include <linux/usb/composite.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/cdc.h>
 
 
+#define MAX_U_SERIAL_PORTS	4
+
+struct f_serial_opts {
+	struct usb_function_instance func_inst;
+	u8 port_num;
+};
+
 /*
 /*
  * One non-multiplexed "serial" I/O port ... there can be several of these
  * One non-multiplexed "serial" I/O port ... there can be several of these
  * on any given USB peripheral device, if it provides enough endpoints.
  * on any given USB peripheral device, if it provides enough endpoints.
@@ -49,9 +56,9 @@ struct gserial {
 struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
 struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
 void gs_free_req(struct usb_ep *, struct usb_request *req);
 void gs_free_req(struct usb_ep *, struct usb_request *req);
 
 
-/* port setup/teardown is handled by gadget driver */
-int gserial_setup(struct usb_gadget *g, unsigned n_ports);
-void gserial_cleanup(void);
+/* management of individual TTY ports */
+int gserial_alloc_line(unsigned char *port_line);
+void gserial_free_line(unsigned char port_line);
 
 
 /* connect/disconnect is handled by individual functions */
 /* connect/disconnect is handled by individual functions */
 int gserial_connect(struct gserial *, u8 port_num);
 int gserial_connect(struct gserial *, u8 port_num);

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio