USB patches for 3.9-rc1

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlEmZ/kACgkQMUfUDdst+ylEhwCgyM0JEOgLuW7M8D+oNcitZn51
 g7oAniD0IkLG8RCB8plLj+82AvthalCo
 =bHSs
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2013-02-21 12:20:00 -08:00
commit 74e1a2a393
175 changed files with 6397 additions and 2525 deletions

View File

@ -227,3 +227,12 @@ Contact: Lan Tianyu <tianyu.lan@intel.com>
Description:
The /sys/bus/usb/devices/.../(hub interface)/portX
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.

View File

@ -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;
};

View File

@ -1,8 +1,11 @@
OMAP GLUE
OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS
OMAP MUSB GLUE
- compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
- 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. This is a MUSB configuration-specific setting.
- 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
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
usb_otg_hs: usb_otg_hs@4a0ab000 {
compatible = "ti,omap4-musb";
ti,hwmods = "usb_otg_hs";
ti,has-mailbox;
multipoint = <1>;
num_eps = <16>;
ram_bits = <12>;
ctrl-module = <&omap_control_usb>;
};
Board specific device node entry
@ -31,3 +40,26 @@ Board specific device node entry
mode = <3>;
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>;
};

View File

@ -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>;
};
};

View File

@ -4,14 +4,39 @@ OMAP USB2 PHY
Required properties:
- 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.
usb2phy@4a0ad080 {
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>;
};

View File

@ -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>;
};

View File

@ -7927,9 +7927,10 @@ F: drivers/net/wireless/ath/ar5523/
USB ATTACHED SCSI
M: Matthew Wilcox <willy@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-scsi@vger.kernel.org
S: Supported
S: Maintained
F: drivers/usb/storage/uas.c
USB CDC ETHERNET DRIVER

View File

@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -263,6 +264,7 @@ static void __init omap_2430sdp_init(void)
omap_hsmmc_init(mmc);
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);
board_smc91x_init();

View File

@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/usb/phy.h>
#include <asm/mach-types.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_serial_init();
omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);

View File

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

View File

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

View File

@ -29,6 +29,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
#include <linux/regulator/machine.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);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(devkit8000_nand_partitions,

View File

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

View File

@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/smsc911x.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.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_serial_init();
omap_sdrc_init(NULL, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
ZOOM_NAND_CS, 0, nand_default_timings);

View File

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

View File

@ -41,6 +41,7 @@
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
#include <linux/export.h>
#include <linux/usb/phy.h>
#include <asm/mach-types.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);
usbhs_bdata.reset_gpio_port[1] = 135;
}
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3evm_nand_partitions,

View File

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

View File

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

View File

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

View File

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

View File

@ -30,6 +30,7 @@
#include <linux/regulator/fixed.h>
#include <linux/ti_wilink_st.h>
#include <linux/usb/musb.h>
#include <linux/usb/phy.h>
#include <linux/wl12xx.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);
omap4_twl6030_hsmmc_init(mmc);
omap4_ehci_init();
usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
usb_musb_init(&musb_board_data);
omap4_panda_display_init();
}

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#include <linux/pinctrl/machine.h>
#include <linux/platform_data/omap4-keypad.h>
#include <linux/platform_data/omap_ocp2scp.h>
#include <linux/usb/omap_control_usb.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
@ -254,6 +255,49 @@ static inline void omap_init_camera(void)
#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
*sdp4430_keypad_data, struct omap_board_data *bdata)
{
@ -721,6 +765,7 @@ static int __init omap2_init_devices(void)
omap_init_mbox();
/* If dtb is there, the devices will be created dynamically */
if (!of_have_populated_dt()) {
omap_init_control_usb();
omap_init_dmic();
omap_init_mcpdm();
omap_init_mcspi();

View File

@ -2702,13 +2702,6 @@ static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
.end = 0x4a0ae000,
.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,
.flags = ADDR_TYPE_RT
},
{
/* XXX: Remove this once control module driver is in place */
.pa_start = 0x4a00233c,
.pa_end = 0x4a00233f,
.flags = ADDR_TYPE_RT
},
{ }
};

View File

@ -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.extvbus = board_data->extvbus;
if (cpu_is_omap44xx())
musb_plat.has_mailbox = true;
if (soc_is_am35xx()) {
oh_name = "am35x_otg_hs";
name = "musb-am35x";

View File

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

View File

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

View File

@ -19,7 +19,7 @@ struct usbmisc_usb_device {
struct device *dev; /* usb controller device */
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);

View File

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

View File

@ -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 += config.o file.o buffer.o sysfs.o endpoint.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_ACPI) += usb-acpi.o

View File

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

View File

@ -40,6 +40,7 @@
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#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)
ret = -ENODATA;
else {
strncpy(gd.driver, intf->dev.driver->name,
strlcpy(gd.driver, intf->dev.driver->name,
sizeof(gd.driver));
ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
}

View File

@ -100,7 +100,7 @@ int usb_choose_configuration(struct usb_device *udev)
*/
/* 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++;
continue;
}

View File

@ -620,6 +620,10 @@ nongeneric:
status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
tbuf, wLength);
if (typeReq == GetHubDescriptor)
usb_hub_adjust_deviceremovable(hcd->self.root_hub,
(struct usb_hub_descriptor *)tbuf);
break;
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 */
rhdev->bus_mA = min(500u, hcd->power_budget);
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;

File diff suppressed because it is too large Load Diff

122
drivers/usb/core/hub.h Normal file
View File

@ -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);
}

View File

@ -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)
dev_warn(&dev->dev, "new config #%d exceeds power "
"limit by %dmA\n",

202
drivers/usb/core/port.c Normal file
View File

@ -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);
}

View File

@ -17,7 +17,7 @@
#include "usb.h"
/* 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, \
struct device_attribute *attr, char *buf) \
{ \
@ -28,18 +28,31 @@ static ssize_t show_##field(struct device *dev, \
actconfig = udev->actconfig; \
if (actconfig) \
return sprintf(buf, format_string, \
actconfig->desc.field * multiplier); \
actconfig->desc.field); \
else \
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, 1, "%2d\n")
usb_actconfig_attr(bmAttributes, 1, "%2x\n")
usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
usb_actconfig_attr(bNumInterfaces, "%2d\n")
usb_actconfig_attr(bmAttributes, "%2x\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,
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);
/* configuration value is always present, and r/w */
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
usb_actconfig_show(bConfigurationValue, "%u\n");
static ssize_t
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,

View File

@ -1,6 +1,7 @@
#include <linux/pm.h>
#include <linux/acpi.h>
struct usb_hub_descriptor;
struct dev_state;
/* 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_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 int usb_match_one_id_intf(struct usb_device *dev,
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);
extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
enum usb_port_connect_type type);
extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
struct usb_hub_descriptor *desc);
#ifdef CONFIG_ACPI
extern int usb_acpi_register(void);

View File

@ -1,6 +1,6 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB && USB_GADGET)
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
select USB_OTG_UTILS
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
@ -12,6 +12,35 @@ config 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
bool "Enable Debugging Messages"
help

View File

@ -4,8 +4,14 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.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),)
dwc3-y += debugfs.o

View File

@ -420,18 +420,27 @@ static int dwc3_probe(struct platform_device *pdev)
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)) {
dev_err(dev, "no usb2 phy configured\n");
return -EPROBE_DEFER;
}
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
dev_err(dev, "no usb3 phy configured\n");
return -EPROBE_DEFER;
}
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
@ -450,8 +459,7 @@ static int dwc3_probe(struct platform_device *pdev)
else
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_get_sync(dev);
@ -550,9 +558,9 @@ err0:
static int dwc3_remove(struct platform_device *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_disable(&pdev->dev);
@ -580,11 +588,22 @@ static int dwc3_remove(struct platform_device *pdev)
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 = {
.probe = dwc3_probe,
.remove = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
},
};

View File

@ -55,7 +55,9 @@
#define DWC3_ENDPOINTS_NUM 32
#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_DEV 0
@ -405,7 +407,6 @@ struct dwc3_event_buffer {
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
* @current_uf: Current uf received through last event parameter
* @interval: the intervall on which the ISOC transfer is started
* @name: a human readable name e.g. ep1out-bulk
* @direction: true for TX, false for RX
@ -439,7 +440,6 @@ struct dwc3_ep {
u8 number;
u8 type;
u8 resource_index;
u16 current_uf;
u32 interval;
char name[20];
@ -581,6 +581,7 @@ struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
u32 start_slot;
u8 epnum;
struct dwc3_trb *trb;
@ -721,6 +722,7 @@ struct dwc3 {
struct dwc3_hwparams hwparams;
struct dentry *root;
struct debugfs_regset32 *regset;
u8 test_mode;
u8 test_mode_nr;
@ -862,10 +864,24 @@ union dwc3_event {
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
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);
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);
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 */

View File

@ -59,7 +59,7 @@
.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(GSBUSCFG1),
dump_register(GTXTHRCFG),
@ -376,27 +376,6 @@ static const struct debugfs_reg32 dwc3_regs[] = {
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)
{
struct dwc3 *dwc = s->private;
@ -666,13 +645,23 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
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) {
ret = -ENOMEM;
goto err1;
}
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops);
if (!file) {
@ -693,6 +682,7 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
ret = -ENOMEM;
goto err1;
}
#endif
return 0;

View File

@ -42,7 +42,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
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)
return -ENOMEM;
@ -53,7 +53,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
if (ret)
goto err1;
pdev = platform_device_alloc("nop_usb_xceiv", 1);
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@ -95,13 +95,14 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
struct platform_device *dwc3;
struct dwc3_exynos *exynos;
struct clk *clk;
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
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);
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);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
dev_err(dev, "couldn't allocate dwc3 device\n");
return -ENOMEM;
}
clk = devm_clk_get(dev, "usbdrd30");
if (IS_ERR(clk)) {
dev_err(dev, "couldn't get clock\n");
ret = -EINVAL;
goto err1;
}
clk = clk_get(&pdev->dev, "usbdrd30");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "couldn't get clock\n");
ret = -EINVAL;
goto err3;
}
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
dwc3->dev.parent = &pdev->dev;
dwc3->dev.dma_mask = pdev->dev.dma_mask;
dwc3->dev.dma_parms = pdev->dev.dma_parms;
dwc3->dev.parent = dev;
dwc3->dev.dma_mask = dev->dma_mask;
dwc3->dev.dma_parms = dev->dma_parms;
exynos->dwc3 = dwc3;
exynos->dev = &pdev->dev;
exynos->dev = dev;
exynos->clk = 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,
pdev->num_resources);
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);
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;
err4:
err2:
clk_disable(clk);
clk_put(clk);
err3:
platform_device_put(dwc3);
err1:
kfree(exynos);
err0:
platform_device_put(dwc3);
return ret;
}
@ -179,16 +177,13 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
platform_device_unregister(exynos->usb3_phy);
clk_disable(exynos->clk);
clk_put(exynos->clk);
kfree(exynos);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id exynos_dwc3_match[] = {
{ .compatible = "samsung,exynos-dwc3" },
{ .compatible = "samsung,exynos5250-dwusb3" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);

View File

@ -43,10 +43,13 @@
#include <linux/spinlock.h>
#include <linux/platform_device.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/ioport.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
@ -78,23 +81,6 @@
/* SYSCONFIG REGISTER */
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0
#define USBOTGSS_STANDBYMODE_NO_STANDBY 1
#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2
#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3
#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4)
#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
#define USBOTGSS_IDLEMODE_FORCE_IDLE 0
#define USBOTGSS_IDLEMODE_NO_IDLE 1
#define USBOTGSS_IDLEMODE_SMART_IDLE 2
#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3
#define USBOTGSS_IDLEMODE_MASK (0x03 << 2)
/* IRQ_EOI REGISTER */
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
@ -133,7 +119,6 @@ struct dwc3_omap {
/* device lock */
spinlock_t lock;
struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev;
@ -147,6 +132,8 @@ struct dwc3_omap {
u32 dma_status:1;
};
struct dwc3_omap *_omap;
static inline u32 dwc3_omap_readl(void __iomem *base, u32 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);
}
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)
{
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));
pdev = platform_device_alloc("nop_usb_xceiv", 0);
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
@ -176,7 +214,7 @@ static int dwc3_omap_register_phys(struct dwc3_omap *omap)
if (ret)
goto err1;
pdev = platform_device_alloc("nop_usb_xceiv", 1);
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@ -262,12 +300,20 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
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)
{
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct platform_device *dwc3;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
@ -314,30 +360,32 @@ static int dwc3_omap_probe(struct platform_device *pdev)
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);
if (!context) {
dev_err(dev, "couldn't allocate dwc3 context memory\n");
goto err2;
return -ENOMEM;
}
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->context = context;
omap->dev = dev;
omap->irq = irq;
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);
@ -368,21 +416,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
reg &= ~(USBOTGSS_STANDBYMODE_MASK
| USBOTGSS_IDLEMODE_MASK);
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
if (ret) {
dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
goto err2;
return ret;
}
/* 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);
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;
err2:
platform_device_put(dwc3);
return ret;
}
static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
platform_device_unregister(omap->dwc3);
platform_device_unregister(omap->usb2_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;
}

View File

@ -241,21 +241,23 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status)
{
struct dwc3 *dwc = dep->dwc;
int i;
if (req->queued) {
if (req->request.num_mapped_sgs)
dep->busy_slot += req->request.num_mapped_sgs;
else
i = 0;
do {
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))
dep->busy_slot++;
dep->busy_slot++;
} while(++i < req->request.num_mapped_sgs);
req->queued = false;
}
list_del(&req->list);
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,
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_trb *trb;
unsigned int cur_slot;
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
dep->name, req, (unsigned long long) dma,
length, last ? " last" : "",
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 */
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))
return;
dep->free_slot++;
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
req->trb = 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->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
@ -786,9 +787,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
break;
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;
break;
@ -807,14 +811,13 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
} else {
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
if (last)
trb->ctrl |= DWC3_TRB_CTRL_LST;
} 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)
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) {
unsigned length;
dma_addr_t dma;
last_one = false;
if (req->request.num_mapped_sgs > 0) {
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) ||
sg_is_last(s)) {
last_one = true;
if (list_is_last(&req->list,
&dep->request_list))
last_one = true;
chain = false;
}
@ -912,7 +918,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
chain = false;
dwc3_prepare_one_trb(dep, req, dma, length,
last_one, chain);
last_one, chain, i);
if (last_one)
break;
@ -930,7 +936,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
last_one = 1;
dwc3_prepare_one_trb(dep, req, dma, length,
last_one, false);
last_one, false, 0);
if (last_one)
break;
@ -977,13 +983,14 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
}
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;
else
} else {
cmd = DWC3_DEPCMD_UPDATETRANSFER;
}
cmd |= DWC3_DEPCMD_PARAM(cmd_param);
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) {
int ret;
/*
* If xfernotready is already elapsed and it is a case
* 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.
*/
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;
}
@ -1099,6 +1107,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
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)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
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;
@ -1652,14 +1652,90 @@ static void dwc3_gadget_release(struct device *dev)
}
/* -------------------------------------------------------------------------- */
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)
{
unsigned int count;
unsigned int s_pkt = 0;
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 count;
unsigned int s_pkt = 0;
unsigned int trb_status;
unsigned int slot;
unsigned int i;
int ret;
do {
req = next_request(&dep->req_queued);
@ -1667,62 +1743,44 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
WARN_ON_ONCE(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)
/*
* 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, 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;
}
}
} else {
if (count && (event->status & DEPEVT_STATUS_SHORT))
s_pkt = 1;
}
/*
* We assume here we will always receive the entire data block
* which we should receive. Meaning, if we program RX to
* receive 4K but we receive only 2K, we assume that's all we
* should receive and we simply bounce the request back to the
* gadget driver for further processing.
*/
req->request.actual += req->request.length - count;
dwc3_gadget_giveback(dep, req, status);
if (s_pkt)
break;
if ((event->status & DEPEVT_STATUS_LST) &&
(trb->ctrl & (DWC3_TRB_CTRL_LST |
DWC3_TRB_CTRL_HWO)))
break;
if ((event->status & DEPEVT_STATUS_IOC) &&
(trb->ctrl & DWC3_TRB_CTRL_IOC))
if (ret)
break;
} while (1);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
if (list_empty(&dep->request_list)) {
/*
* 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.
*/
dep->flags = DWC3_EP_PENDING_REQUEST;
} else {
dwc3_stop_active_transfer(dwc, dep->number);
dep->flags = DWC3_EP_ENABLED;
}
return 1;
}
if ((event->status & DEPEVT_STATUS_IOC) &&
(trb->ctrl & DWC3_TRB_CTRL_IOC))
return 0;
@ -2157,6 +2215,26 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
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 */
if (dwc->revision < DWC3_REVISION_194A) {
/* Suspend unneeded PHY */
@ -2463,20 +2541,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
DWC3_DEVTEN_DISCONNEVTEN);
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) {
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_usb3_phy_suspend(dwc, false);
}

View File

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

View File

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

View File

@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.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_NET2272) += net2272.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_ACM_MS) += g_acm_ms.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

View File

@ -40,9 +40,6 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "u_serial.c"
#include "f_acm.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 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.
*/
static int __init acm_ms_do_config(struct usb_configuration *c)
{
struct f_serial_opts *opts;
int status;
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;
}
f_acm_inst = usb_get_function_instance("acm");
if (IS_ERR(f_acm_inst))
return PTR_ERR(f_acm_inst);
status = acm_bind_config(c, 0);
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 = usb_add_function(c, f_acm);
if (status < 0)
return status;
goto err_conf;
status = fsg_bind_config(c->cdev, c, &fsg_common);
if (status < 0)
return status;
goto err_fsg;
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 = {
@ -153,7 +172,7 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
void *retp;
/* set up serial link layer */
status = gserial_setup(cdev->gadget, 1);
status = gserial_alloc_line(&tty_line);
if (status < 0)
return status;
@ -189,14 +208,15 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
fail1:
fsg_common_put(&fsg_common);
fail0:
gserial_cleanup();
gserial_free_line(tty_line);
return status;
}
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;
}

View File

@ -1400,15 +1400,16 @@ static int udc_wakeup(struct usb_gadget *gadget)
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 */
static const struct usb_gadget_ops udc_ops = {
.wakeup = udc_wakeup,
.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 */
@ -1913,41 +1914,22 @@ static int setup_ep0(struct udc *dev)
}
/* 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;
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;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
retval = bind(&dev->gadget, driver);
/* Some gadget drivers use both ep0 directions.
* NOTE: to gadget driver, ep0 is just one endpoint...
*/
dev->ep[UDC_EP0OUT_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 */
setup_ep0(dev);
@ -1969,14 +1951,9 @@ __acquires(dev->lock)
{
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 */
udc_basic_init(dev);
for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
empty_req_queue(&dev->ep[tmp]);
@ -1984,23 +1961,18 @@ __acquires(dev->lock)
}
/* 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;
if (!dev)
return -ENODEV;
if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
udc_mask_unused_interrupts(dev);
shutdown(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
dev->gadget.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);
writel(tmp, &dev->regs->ctl);
DBG(dev, "%s: unregistered\n", driver->driver.name);
return 0;
}

View File

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

View File

@ -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
* 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,
@ -1739,7 +1738,7 @@ static int at91udc_probe(struct platform_device *pdev)
/* rm9200 needs manual D+ pullup; off by default */
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");
retval = -ENODEV;
goto fail0;

View File

@ -42,9 +42,6 @@ USB_GADGET_COMPOSITE_OPTIONS();
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "u_serial.c"
#include "f_acm.c"
#include "f_ecm.c"
#include "u_ether.c"
@ -108,12 +105,16 @@ static struct usb_gadget_strings *dev_strings[] = {
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.
*/
static int __init cdc_do_config(struct usb_configuration *c)
{
struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@ -125,11 +126,26 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (status < 0)
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;
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 = {
@ -158,7 +174,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return status;
/* set up serial link layer */
status = gserial_setup(cdev->gadget, 1);
status = gserial_alloc_line(&tty_line);
if (status < 0)
goto fail0;
@ -184,7 +200,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
gserial_cleanup();
gserial_free_line(tty_line);
fail0:
gether_cleanup();
return status;
@ -192,7 +208,9 @@ fail0:
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();
return 0;
}

View File

@ -28,6 +28,12 @@
* 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
* @t: currect pointer within descriptor array
@ -215,6 +221,18 @@ done:
}
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
* @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);
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,
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->iConfiguration = config->iConfiguration;
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 */
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 */
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
if (result >= 0 && cdev->delayed_status)
@ -664,6 +701,31 @@ done:
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.
* @cdev: wraps the USB gadget
@ -684,30 +746,18 @@ int usb_add_config(struct usb_composite_dev *cdev,
int (*bind)(struct usb_configuration *))
{
int status = -EINVAL;
struct usb_configuration *c;
if (!bind)
goto done;
DBG(cdev, "adding config #%u '%s'/%p\n",
config->bConfigurationValue,
config->label, config);
if (!config->bConfigurationValue || !bind)
status = usb_add_config_only(cdev, config);
if (status)
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);
if (status < 0) {
while (!list_empty(&config->functions)) {
@ -860,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
void *buf, u16 language, int id)
{
struct usb_composite_driver *composite = cdev->driver;
struct usb_gadget_string_container *uc;
struct usb_configuration *c;
struct usb_function *f;
int len;
@ -892,6 +943,12 @@ static int get_string(struct usb_composite_dev *cdev,
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++)
continue;
@ -902,6 +959,15 @@ static int get_string(struct usb_composite_dev *cdev,
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
* table we're told about. These lookups are infrequent;
* 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);
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
* @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
* the work is in config and function specific setup.
*/
static int
int
composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
@ -1300,7 +1479,7 @@ done:
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);
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 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);
@ -1348,19 +1526,21 @@ composite_unbind(struct usb_gadget *gadget)
struct usb_configuration, list);
remove_config(cdev, c);
}
if (cdev->driver->unbind)
if (cdev->driver->unbind && unbind_driver)
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);
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,
const struct usb_device_descriptor *old)
{
@ -1399,34 +1579,25 @@ static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
new->iProduct = iProduct;
}
static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
int composite_dev_prepare(struct usb_composite_driver *composite,
struct usb_composite_dev *cdev)
{
return container_of(gdrv, struct usb_composite_driver, gadget_driver);
}
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);
struct usb_gadget *gadget = cdev->gadget;
int ret = -ENOMEM;
/* preallocate control response and buffer */
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!cdev->req)
goto fail;
return -ENOMEM;
cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
if (!cdev->req->buf)
goto fail;
ret = device_create_file(&gadget->dev, &dev_attr_suspended);
if (ret)
goto fail_dev;
cdev->req->complete = composite_setup_complete;
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
* 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
* 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)
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);
return 0;
fail:
composite_unbind(gadget);
__composite_unbind(gadget, false);
return status;
}
@ -1518,10 +1728,10 @@ composite_resume(struct usb_gadget *gadget)
f->resume(f);
}
maxpower = cdev->config->bMaxPower;
maxpower = cdev->config->MaxPower;
usb_gadget_vbus_draw(gadget, maxpower ?
(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
}
cdev->suspended = 0;

View File

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

View File

@ -16,7 +16,9 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include "u_serial.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_DATA_IDX].s = "CDC ACM Data",
[ACM_IAD_IDX ].s = "CDC Serial",
{ /* ZEROES END LIST */ },
};
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 f_acm *acm = func_to_acm(f);
struct usb_string *us;
int status;
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 */
status = usb_interface_id(c, f);
if (status < 0)
@ -700,24 +715,42 @@ fail:
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
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);
acm_string_defs[0].id = 0;
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);
}
/* 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
* @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.
*
* 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)
{
struct f_acm *acm;
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 */
acm = kzalloc(sizeof *acm, GFP_KERNEL);
acm = acm_alloc_basic_func();
if (!acm)
return -ENOMEM;
spin_lock_init(&acm->lock);
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);
if (status)
kfree(acm);
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

View File

@ -1103,8 +1103,8 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
return 0;
for (;;) {
char *end, *eq, *comma;
unsigned long value;
char *eq, *comma;
/* Option limit */
comma = strchr(opts, ',');
@ -1120,8 +1120,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
*eq = 0;
/* 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);
return -EINVAL;
}

View File

@ -15,10 +15,11 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/usb/composite.h>
#include "g_zero.h"
#include "gadget_chips.h"
/*
* 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);
}
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 f_loopback *loop = func_to_loop(f);
@ -185,6 +184,12 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
return 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 */
loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
@ -223,8 +228,7 @@ autoconf_fail:
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);
kfree(func_to_loop(f));
@ -366,63 +370,64 @@ static void loopback_disable(struct usb_function *f)
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;
int status;
struct f_lb_opts *lb_opts;
loop = kzalloc(sizeof *loop, GFP_KERNEL);
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.bind = loopback_bind;
loop->function.unbind = loopback_unbind;
loop->function.set_alt = loopback_set_alt;
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;
return &loop->function;
}
static struct usb_configuration loopback_driver = {
.label = "loopback",
.strings = loopback_strings,
.bConfigurationValue = 2,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */
};
/**
* 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;
loopback_intf.iInterface = id;
loopback_driver.iConfiguration = id;
/* support autoresume for remote wakeup testing */
if (autoresume)
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
/* support OTG systems */
if (gadget_is_otg(cdev->gadget)) {
loopback_driver.descriptors = otg_desc;
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
return usb_add_config(cdev, &loopback_driver, loopback_bind_config);
lb_opts = container_of(fi, struct f_lb_opts, func_inst);
kfree(lb_opts);
}
static struct usb_function_instance *loopback_alloc_instance(void)
{
struct f_lb_opts *lb_opts;
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);
int __init lb_modinit(void)
{
int ret;
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");

View File

@ -246,20 +246,6 @@ struct fsg_operations {
* set).
*/
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. */
@ -1374,26 +1360,13 @@ static int do_start_stop(struct fsg_common *common)
if (!loej)
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);
down_write(&common->filesem);
fsg_lun_close(curlun);
up_write(&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)
@ -1718,7 +1691,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
int needs_medium, const char *name)
{
int i;
int lun = common->cmnd[1] >> 5;
unsigned int lun = common->cmnd[1] >> 5;
static const char dirletter[4] = {'u', 'o', 'i', 'n'};
char hdlen[20];
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 */
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);
/* Check the LUN */
@ -1804,7 +1777,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
*/
if (common->cmnd[0] != INQUIRY &&
common->cmnd[0] != REQUEST_SENSE) {
DBG(common, "unsupported LUN %d\n", common->lun);
DBG(common, "unsupported LUN %u\n", common->lun);
return -EINVAL;
}
}
@ -2196,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
if (common->data_size == 0)
common->data_dir = DATA_DIR_NONE;
common->lun = cbw->Lun;
if (common->lun >= 0 && common->lun < common->nluns)
if (common->lun < common->nluns)
common->curlun = &common->luns[common->lun];
else
common->curlun = NULL;

View File

@ -56,8 +56,9 @@ struct f_ncm {
u8 notify_state;
bool is_open;
struct ndp_parser_opts *parser_opts;
const struct ndp_parser_opts *parser_opts;
bool is_crc;
u32 ndp_sign;
/*
* for notification, it is accessed from both
@ -390,8 +391,8 @@ struct ndp_parser_opts {
.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)
{
@ -732,8 +733,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
default:
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;
break;
}
@ -875,7 +875,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
int ndp_align;
int ndp_pad;
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;
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;
/* NDP */
put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */
put_unaligned_le32(ncm->ndp_sign, tmp); /* dwSignature */
tmp += 2;
/* wLength */
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;
int ret = -EINVAL;
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;
int dgram_counter;
@ -1002,7 +1002,7 @@ static int ncm_unwrap_ntb(struct gether *port,
/* walk through NDP */
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");
goto err;
}

View File

@ -406,10 +406,6 @@ static inline bool can_support_obex(struct usb_configuration *c)
* Context: single threaded during gadget setup
*
* 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)
{

View File

@ -260,10 +260,6 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
* Context: single threaded during gadget setup
*
* 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)
{

View File

@ -16,11 +16,12 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/usb/composite.h>
#include <linux/err.h>
#include "g_zero.h"
#include "gadget_chips.h"
/*
* SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
* controller drivers.
@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
}
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;
module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
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)
{
struct usb_composite_dev *cdev = c->cdev;
@ -450,7 +488,7 @@ no_iso:
}
static void
sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
sourcesink_free_func(struct usb_function *f)
{
usb_free_all_descriptors(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);
if (pattern != 2)
memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
}
break;
/* 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)
{
struct usb_configuration *c = f->config;
struct usb_request *req = c->cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@ -851,42 +867,76 @@ unknown:
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 */
};
/**
* 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)
static struct usb_function *source_sink_alloc_func(
struct usb_function_instance *fi)
{
int id;
struct f_sourcesink *ss;
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 = kzalloc(sizeof(*ss), GFP_KERNEL);
if (!ss)
return NULL;
source_sink_intf_alt0.iInterface = id;
source_sink_intf_alt1.iInterface = id;
sourcesink_driver.iConfiguration = id;
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;
/* support autoresume for remote wakeup testing */
if (autoresume)
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
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;
/* support OTG systems */
if (gadget_is_otg(cdev->gadget)) {
sourcesink_driver.descriptors = otg_desc;
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
ss->function.free_func = sourcesink_free_func;
return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);
return &ss->function;
}
static void acm_free_instance(struct usb_function_instance *fi)
{
struct f_ss_opts *ss_opts;
ss_opts = container_of(fi, struct f_ss_opts, func_inst);
kfree(ss_opts);
}
static struct usb_function_instance *source_sink_alloc_inst(void)
{
struct f_ss_opts *ss_opts;
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);
static int __init sslb_modinit(void)
{
int ret;
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");

View File

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

View File

@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/video.h>
@ -419,7 +420,7 @@ uvc_register_video(struct uvc_device *uvc)
video->parent = &cdev->gadget->dev;
video->fops = &uvc_v4l2_fops;
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;
video_set_drvdata(video, uvc);

View File

@ -1894,7 +1894,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
/* 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,
.udc_start = fsl_qe_start,
.udc_stop = fsl_qe_stop,

View File

@ -1255,19 +1255,20 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
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 */
static struct usb_gadget_ops fsl_gadget_ops = {
static const struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */
.vbus_session = fsl_vbus_session,
.vbus_draw = fsl_vbus_draw,
.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
@ -1951,22 +1952,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
* Hook to 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;
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 */
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;
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)) {
/* Suspend the controller until OTG enable it */
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_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;
}
/* 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;
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))
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);
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->driver = NULL;
printk(KERN_WARNING "unregistered gadget driver '%s'\n",
driver->driver.name);
return 0;
}

View File

@ -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);

View File

@ -1308,65 +1308,28 @@ static void init_controller(struct fusb300 *fusb300)
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 */
driver->driver.bus = NULL;
fusb300->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;
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);
fusb300->gadget.dev.driver = NULL;
init_controller(fusb300);
device_del(&fusb300->gadget.dev);
fusb300->driver = NULL;
return 0;
@ -1378,10 +1341,10 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
return 0;
}
static struct usb_gadget_ops fusb300_gadget_ops = {
static const struct usb_gadget_ops fusb300_gadget_ops = {
.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)
@ -1505,8 +1468,6 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
the_controller = fusb300;
fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
GFP_KERNEL);
if (fusb300->ep0_req == NULL)
@ -1517,9 +1478,19 @@ static int __init fusb300_probe(struct platform_device *pdev)
if (ret)
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);
return 0;
err_add_device:
usb_del_gadget_udc(&fusb300->gadget);
err_add_udc:
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);

View File

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

View File

@ -6,11 +6,34 @@
#ifndef __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 */
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 *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 */

View File

@ -125,7 +125,7 @@ static struct usb_configuration midi_config = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.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)

View File

@ -993,14 +993,15 @@ static int goku_get_frame(struct usb_gadget *_gadget)
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 = {
.get_frame = goku_get_frame,
.start = goku_start,
.stop = goku_stop,
.udc_start = goku_udc_start,
.udc_stop = goku_udc_stop,
// no remote wakeup
// not selfpowered
};
@ -1339,50 +1340,28 @@ static void udc_enable(struct goku_udc *dev)
* - one function driver, initted second
*/
static struct goku_udc *the_controller;
/* when a driver is successfully registered, it will receive
* control requests including set_configuration(), which enables
* non-control requests. then usb traffic follows until a
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
static int 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 */
driver->driver.bus = NULL;
dev->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.
*/
udc_enable(dev);
DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
return 0;
}
@ -1400,35 +1379,23 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
udc_reset (dev);
for (i = 0; i < 4; i++)
nuke(&dev->ep [i], -ESHUTDOWN);
if (driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
if (dev->driver)
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;
if (!dev)
return -ENODEV;
if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
dev->driver = NULL;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
}
@ -1754,7 +1721,6 @@ static void goku_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
dev->regs = NULL;
the_controller = NULL;
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;
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) {
printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
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);
#endif
the_controller = dev;
retval = device_register(&dev->gadget.dev);
if (retval) {
put_device(&dev->gadget.dev);

View File

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

View File

@ -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 */
driver->driver.bus = NULL;
m66592->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);
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
m66592_start_xclock(m66592);
@ -1510,26 +1484,12 @@ static int m66592_start(struct usb_gadget_driver *driver,
}
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);
@ -1539,8 +1499,8 @@ static int m66592_stop(struct usb_gadget_driver *driver)
init_controller(m66592);
disable_controller(m66592);
device_del(&m66592->gadget.dev);
m66592->driver = NULL;
return 0;
}
@ -1566,10 +1526,10 @@ static int m66592_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
static struct usb_gadget_ops m66592_gadget_ops = {
static const struct usb_gadget_ops m66592_gadget_ops = {
.get_frame = m66592_get_frame,
.start = m66592_start,
.stop = m66592_stop,
.udc_start = m66592_udc_start,
.udc_stop = m66592_udc_stop,
.pullup = m66592_pullup,
};
@ -1578,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev)
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
usb_del_gadget_udc(&m66592->gadget);
device_del(&m66592->gadget.dev);
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
@ -1706,8 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->pipenum2ep[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);
if (m66592->ep0_req == NULL)
goto clean_up3;
@ -1715,6 +1674,12 @@ static int __init m66592_probe(struct platform_device *pdev)
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);
if (ret)
goto err_add_udc;
@ -1723,6 +1688,9 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0;
err_add_udc:
device_del(&m66592->gadget.dev);
err_device_add:
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
clean_up3:

View File

@ -492,6 +492,7 @@ struct m66592 {
int isochronous;
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 m66592_to_gadget(m66592) (&m66592->gadget)

View File

@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include "u_serial.h"
#if defined USB_ETH_RNDIS
# undef USB_ETH_RNDIS
#endif
@ -42,9 +43,6 @@ MODULE_LICENSE("GPL");
*/
#include "f_mass_storage.c"
#include "u_serial.c"
#include "f_acm.c"
#include "f_ecm.c"
#include "f_subset.c"
#ifdef USB_ETH_RNDIS
@ -137,10 +135,13 @@ static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
static unsigned char tty_line;
static struct usb_function_instance *fi_acm;
/********** RNDIS **********/
#ifdef USB_ETH_RNDIS
static struct usb_function *f_acm_rndis;
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)
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);
if (ret < 0)
return ret;
goto err_fsg;
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)
@ -192,6 +203,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
/********** CDC ECM **********/
#ifdef CONFIG_USB_G_MULTI_CDC
static struct usb_function *f_acm_multi;
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)
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);
if (ret < 0)
return ret;
goto err_fsg;
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)
@ -243,10 +266,10 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
/****************************** Gadget Bind ******************************/
static int __ref multi_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct f_serial_opts *opts;
int status;
if (!can_support_ecm(cdev->gadget)) {
@ -261,10 +284,19 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
return status;
/* set up serial link layer */
status = gserial_setup(cdev->gadget, 1);
status = gserial_alloc_line(&tty_line);
if (status < 0)
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 */
{
void *retp;
@ -301,7 +333,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
fail2:
fsg_common_put(&fsg_common);
fail1:
gserial_cleanup();
usb_put_function_instance(fi_acm);
fail0dot5:
gserial_free_line(tty_line);
fail0:
gether_cleanup();
return status;
@ -309,7 +343,14 @@ fail0:
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();
return 0;
}

View File

@ -61,9 +61,6 @@ static DECLARE_COMPLETION(release_done);
static const char driver_name[] = "mv_udc";
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 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;
}
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 */
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 */
.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)
@ -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;
unsigned long flags;
if (!udc)
return -ENODEV;
udc = container_of(gadget, struct mv_udc, gadget);
if (udc->driver)
return -EBUSY;
@ -1399,26 +1394,14 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
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,
&udc->gadget);
if (retval) {
dev_err(&udc->dev->dev,
"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;
}
}
@ -1433,13 +1416,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
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;
if (!udc)
return -ENODEV;
udc = container_of(gadget, struct mv_udc, gadget);
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);
/* unbind gadget driver */
driver->unbind(&udc->gadget);
udc->gadget.dev.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)
{
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_udc *udc;
unsigned long flags;
udc = mvep->udc;
dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
spin_lock_irqsave(&udc->lock, flags);
@ -2123,15 +2108,18 @@ static void mv_udc_vbus_work(struct work_struct *work)
/* release device structure */
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);
}
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);
@ -2140,57 +2128,27 @@ static int mv_udc_remove(struct platform_device *dev)
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 */
if (udc->dtd_pool)
dma_pool_destroy(udc->dtd_pool);
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);
kfree(udc->eps);
if (udc->irq)
free_irq(udc->irq, &dev->dev);
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);
/* free dev, wait for the release() finished */
wait_for_completion(udc->done);
kfree(udc);
the_controller = NULL;
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;
int retval = 0;
int clk_i = 0;
@ -2198,71 +2156,73 @@ static int mv_udc_probe(struct platform_device *dev)
size_t size;
if (pdata == NULL) {
dev_err(&dev->dev, "missing platform_data\n");
dev_err(&pdev->dev, "missing platform_data\n");
return -ENODEV;
}
size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
udc = kzalloc(size, GFP_KERNEL);
udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
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;
}
the_controller = udc;
udc->done = &release_done;
udc->pdata = dev->dev.platform_data;
udc->pdata = pdev->dev.platform_data;
spin_lock_init(&udc->lock);
udc->dev = dev;
udc->dev = pdev;
#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
udc->clknum = pdata->clknum;
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])) {
retval = PTR_ERR(udc->clk[clk_i]);
goto err_put_clk;
return retval;
}
}
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
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 *)
ioremap(r->start, resource_size(r));
devm_ioremap(&pdev->dev, r->start, resource_size(r));
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");
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));
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 */
retval = mv_udc_enable_internal(udc);
if (retval)
goto err_iounmap_phyreg;
return retval;
udc->op_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 = (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);
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;
goto err_disable_clock;
}
@ -2291,7 +2251,7 @@ static int mv_udc_probe(struct platform_device *dev)
/* create dTD dma_pool resource */
udc->dtd_pool = dma_pool_create("mv_dtd",
&dev->dev,
&pdev->dev,
sizeof(struct mv_dtd),
DTD_ALIGNMENT,
DMA_BOUNDARY);
@ -2302,19 +2262,20 @@ static int mv_udc_probe(struct platform_device *dev)
}
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) {
dev_err(&dev->dev, "allocate ep memory failed\n");
dev_err(&pdev->dev, "allocate ep memory failed\n");
retval = -ENOMEM;
goto err_destroy_dma;
}
/* 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) {
dev_err(&dev->dev, "allocate status_req memory failed\n");
dev_err(&pdev->dev, "allocate status_req memory failed\n");
retval = -ENOMEM;
goto err_free_eps;
goto err_destroy_dma;
}
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);
if (r == NULL) {
dev_err(&dev->dev, "no IRQ resource defined\n");
dev_err(&pdev->dev, "no IRQ resource defined\n");
retval = -ENODEV;
goto err_free_status_req;
goto err_destroy_dma;
}
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)) {
dev_err(&dev->dev, "Request irq %d for UDC failed\n",
dev_err(&pdev->dev, "Request irq %d for UDC failed\n",
udc->irq);
retval = -ENODEV;
goto err_free_status_req;
goto err_destroy_dma;
}
/* initialize gadget structure */
@ -2351,26 +2312,27 @@ static int mv_udc_probe(struct platform_device *dev)
/* the "gadget" abstracts/virtualizes the controller */
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.name = driver_name; /* gadget name */
retval = device_register(&udc->gadget.dev);
if (retval)
goto err_free_irq;
goto err_destroy_dma;
eps_init(udc);
/* VBUS detect: we can disable/enable clock on demand.*/
if (!IS_ERR_OR_NULL(udc->transceiver))
if (udc->transceiver)
udc->clock_gating = 1;
else if (pdata->vbus) {
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);
if (retval) {
dev_info(&dev->dev,
dev_info(&pdev->dev,
"Can not request irq for VBUS, "
"disable clock gating\n");
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");
if (!udc->qwork) {
dev_err(&dev->dev, "cannot create workqueue\n");
dev_err(&pdev->dev, "cannot create workqueue\n");
retval = -ENOMEM;
goto err_unregister;
}
@ -2396,53 +2358,40 @@ static int mv_udc_probe(struct platform_device *dev)
else
udc->vbus_active = 1;
retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
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");
return 0;
err_create_workqueue:
destroy_workqueue(udc->qwork);
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);
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:
dma_pool_destroy(udc->dtd_pool);
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);
err_disable_clock:
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;
}
#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 (!IS_ERR_OR_NULL(udc->transceiver))
if (udc->transceiver)
return 0;
if (udc->pdata->vbus && udc->pdata->vbus->poll)
@ -2469,13 +2418,15 @@ static int mv_udc_suspend(struct device *_dev)
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;
udc = dev_get_drvdata(dev);
/* if OTG is enabled, the following will be done in OTG driver*/
if (!IS_ERR_OR_NULL(udc->transceiver))
if (udc->transceiver)
return 0;
if (!udc->clock_gating) {
@ -2499,11 +2450,12 @@ static const struct dev_pm_ops mv_udc_pm_ops = {
};
#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;
udc = platform_get_drvdata(pdev);
/* reset controller mode to IDLE */
mv_udc_enable(udc);
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 = {
.probe = mv_udc_probe,
.remove = __exit_p(mv_udc_remove),
.remove = mv_udc_remove,
.shutdown = mv_udc_shutdown,
.driver = {
.owner = THIS_MODULE,

View File

@ -116,6 +116,10 @@ static bool enable_suspend = 0;
/* "modprobe net2280 enable_suspend=1" etc */
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")
@ -1899,6 +1903,10 @@ static int net2280_start(struct usb_gadget *_gadget,
retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
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
* for set_configuration as well as eventual disconnect.
*/
@ -1957,6 +1965,10 @@ static int net2280_stop(struct usb_gadget *_gadget,
dev->driver = NULL;
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_queues);
@ -2841,6 +2853,9 @@ static void net2280_shutdown (struct pci_dev *pdev)
/* disable the pullup so the host will think we're gone */
writel (0, &dev->usb->usbctl);
/* Disable full-speed test mode */
writel(0, &dev->usb->xcvrdiag);
}

View File

@ -37,7 +37,7 @@
* the runtime footprint, and giving us at least some parts of what
* 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_ecm.c"
#include "f_obex.c"
@ -101,6 +101,15 @@ MODULE_LICENSE("GPL");
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)
{
int status = 0;
@ -109,15 +118,15 @@ static int __init nokia_bind_config(struct usb_configuration *c)
if (status)
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)
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)
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)
printk(KERN_DEBUG "could not bind acm config\n");
@ -133,7 +142,7 @@ static struct usb_configuration nokia_config_500ma_driver = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_ONE,
.bMaxPower = 250, /* 500mA */
.MaxPower = 500,
};
static struct usb_configuration nokia_config_100ma_driver = {
@ -141,21 +150,24 @@ static struct usb_configuration nokia_config_100ma_driver = {
.bConfigurationValue = 2,
/* .iConfiguration = DYNAMIC */
.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)
{
struct usb_gadget *gadget = cdev->gadget;
int status;
int cur_line;
status = gphonet_setup(cdev->gadget);
if (status < 0)
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);
if (status < 0)
@ -192,8 +204,10 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
err_usb:
gether_cleanup();
err_ether:
gserial_cleanup();
err_serial:
cur_line--;
while (cur_line >= 0)
gserial_free_line(tty_lines[cur_line--]);
gphonet_cleanup();
err_phonet:
return status;
@ -201,8 +215,13 @@ err_phonet:
static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{
int i;
gphonet_cleanup();
gserial_cleanup();
for (i = 0; i < TTY_PORTS_MAX; i++)
gserial_free_line(tty_lines[i]);
gether_cleanup();
return 0;

View File

@ -1309,19 +1309,20 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)
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,
.wakeup = omap_wakeup,
.set_selfpowered = omap_set_selfpowered,
.vbus_session = omap_vbus_session,
.vbus_draw = omap_vbus_draw,
.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();
}
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;
struct omap_ep *ep;
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);
if (udc->driver) {
spin_unlock_irqrestore(&udc->lock, flags);
return -EBUSY;
}
/* reset state */
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
ep->irqs = 0;
@ -2084,15 +2072,6 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
if (udc->dc_clk != NULL)
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);
/* connect to bus through transceiver */
@ -2124,19 +2103,16 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
done:
if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
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;
int status = -ENODEV;
if (!udc)
return -ENODEV;
if (!driver || driver != udc->driver || !driver->unbind)
return -EINVAL;
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);
@ -2152,13 +2128,12 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
udc_quiesce(udc);
spin_unlock_irqrestore(&udc->lock, flags);
driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
}

View File

@ -375,6 +375,7 @@ struct pch_udc_dev {
struct pch_udc_cfg_data cfg_data;
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 PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
@ -384,7 +385,6 @@ struct pch_udc_dev {
static const char ep0_string[] = "ep0in";
static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
struct pch_udc_dev *pch_udc; /* pointer to device object */
static bool speed_fs;
module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
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;
}
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 = {
.get_frame = pch_udc_pcd_get_frame,
.wakeup = pch_udc_pcd_wakeup,
@ -1245,8 +1246,8 @@ static const struct usb_gadget_ops pch_udc_ops = {
.pullup = pch_udc_pcd_pullup,
.vbus_session = pch_udc_pcd_vbus_session,
.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;
}
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;
struct pch_udc_dev *dev = to_pch_udc(g);
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;
}
if (!dev)
return -ENODEV;
if (dev->driver) {
dev_err(&dev->pdev->dev, "%s: already bound\n", __func__);
return -EBUSY;
}
driver->driver.bus = NULL;
dev->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 */
pch_udc_setup_ep0(dev);
@ -3026,30 +3002,21 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
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);
/* Assures that there are no pending requests with this driver */
driver->disconnect(&dev->gadget);
driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev->connected = 0;
/* set SD */
pch_udc_set_disconnect(dev);
return 0;
}
@ -3164,11 +3131,6 @@ static int pch_udc_probe(struct pci_dev *pdev,
int retval;
struct pch_udc_dev *dev;
/* one udc only */
if (pch_udc) {
pr_err("%s: already probed\n", __func__);
return -EBUSY;
}
/* init */
dev = kzalloc(sizeof *dev, GFP_KERNEL);
if (!dev) {
@ -3207,7 +3169,6 @@ static int pch_udc_probe(struct pci_dev *pdev,
retval = -ENODEV;
goto finished;
}
pch_udc = dev;
/* initialize the hardware */
if (pch_udc_pcd_init(dev)) {
retval = -ENODEV;

View File

@ -996,9 +996,10 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
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 = {
.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,
.pullup = pxa25x_udc_pullup,
.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
* 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;
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 ... */
dev->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);
if (retval) {
fail:
dev->driver = NULL;
dev->gadget.dev.driver = NULL;
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
* for set_configuration as well as eventual disconnect.
*/
DMSG("registered gadget driver '%s'\n", driver->driver.name);
/* connect to bus through transceiver */
if (!IS_ERR_OR_NULL(dev->transceiver)) {
retval = otg_set_peripheral(dev->transceiver->otg,
&dev->gadget);
if (retval) {
DMSG("can't bind to transceiver\n");
if (driver->unbind)
driver->unbind(&dev->gadget);
if (retval)
goto bind_fail;
}
}
pullup(dev);
@ -1334,22 +1310,14 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
}
del_timer_sync(&dev->timer);
/* report disconnect; the driver is already quiesced */
if (driver)
driver->disconnect(&dev->gadget);
/* re-init driver-visible data structures */
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();
dev->pullup = 0;
@ -1360,14 +1328,12 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
if (!IS_ERR_OR_NULL(dev->transceiver))
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
device_del (&dev->gadget.dev);
DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
dump_state(dev);
return 0;
}

View File

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

View File

@ -1671,9 +1671,10 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
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 = {
.get_frame = pxa_udc_get_frame,
@ -1681,8 +1682,8 @@ static const struct usb_gadget_ops pxa_udc_ops = {
.pullup = pxa_udc_pullup,
.vbus_session = pxa_udc_vbus_session,
.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
*/
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;
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 ... */
udc->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);
if (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)) {
retval = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (retval) {
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);
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->gadget.dev.driver = NULL;
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++)
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
*/
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);
udc_disable(udc);
dplus_pullup(udc, 0);
driver->unbind(&udc->gadget);
udc->driver = NULL;
device_del(&udc->gadget.dev);
dev_info(udc->dev, "unregistered gadget driver '%s'\n",
driver->driver.name);
if (!IS_ERR_OR_NULL(udc->transceiver))
return otg_set_peripheral(udc->transceiver->otg, NULL);

View File

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

View File

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

View File

@ -32,6 +32,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/phy.h>
#include <linux/platform_data/s3c-hsotg.h>
#include <mach/map.h>
@ -133,7 +134,9 @@ struct s3c_hsotg_ep {
* struct s3c_hsotg - driver state.
* @dev: The parent device supplied to the probe function
* @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.
* @irq: The IRQ number we are using
* @supplies: Definition of USB power supplies
@ -153,6 +156,7 @@ struct s3c_hsotg_ep {
struct s3c_hsotg {
struct device *dev;
struct usb_gadget_driver *driver;
struct usb_phy *phy;
struct s3c_hsotg_plat *plat;
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);
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);
}
@ -2869,7 +2876,9 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
{
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);
}
@ -3055,7 +3064,7 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
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,
.udc_start = s3c_hsotg_udc_start,
.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)
{
struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
struct usb_phy *phy;
struct device *dev = &pdev->dev;
struct s3c_hsotg_ep *eps;
struct s3c_hsotg *hsotg;
@ -3500,20 +3510,27 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
int ret;
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);
if (!hsotg) {
dev_err(dev, "cannot get memory\n");
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->plat = plat;
hsotg->clk = devm_clk_get(&pdev->dev, "otg");
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++)
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);
if (ret) {
dev_err(dev, "failed to request supplies: %d\n", ret);
@ -3661,8 +3678,6 @@ err_ep_mem:
kfree(eps);
err_supplies:
s3c_hsotg_phy_disable(hsotg);
regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
err_clk:
clk_disable_unprepare(hsotg->clk);
@ -3687,7 +3702,6 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
}
s3c_hsotg_phy_disable(hsotg);
regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
clk_disable_unprepare(hsotg->clk);

View File

@ -435,7 +435,7 @@ static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
struct s3c_hsudc_req *hsreq;
u32 csr;
csr = readl((u32)hsudc->regs + S3C_ESR);
csr = readl(hsudc->regs + S3C_ESR);
if (csr & S3C_ESR_STALL) {
writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
return;
@ -468,7 +468,7 @@ static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
struct s3c_hsudc_req *hsreq;
u32 csr;
csr = readl((u32)hsudc->regs + S3C_ESR);
csr = readl(hsudc->regs + S3C_ESR);
if (csr & S3C_ESR_STALL) {
writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
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) {
offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
if (ep_is_in(hsep)) {
csr = readl((u32)hsudc->regs + offset);
csr = readl(hsudc->regs + offset);
if (!(csr & S3C_ESR_TX_SUCCESS) &&
(s3c_hsudc_write_fifo(hsep, hsreq) == 1))
hsreq = NULL;
} else {
csr = readl((u32)hsudc->regs + offset);
csr = readl(hsudc->regs + offset);
if ((csr & S3C_ESR_RX_SUCCESS)
&& (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
hsreq = NULL;
@ -1254,7 +1254,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
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,
.udc_start = s3c_hsudc_start,
.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++)
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);
if (ret != 0) {
dev_err(dev, "failed to request supplies: %d\n", ret);
@ -1366,7 +1366,6 @@ err_res:
if (!IS_ERR_OR_NULL(hsudc->transceiver))
usb_put_phy(hsudc->transceiver);
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
return ret;
}

View File

@ -1538,9 +1538,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
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 = {
.get_frame = s3c2410_udc_get_frame,
@ -1549,8 +1550,8 @@ static const struct usb_gadget_ops s3c2410_ops = {
.pullup = s3c2410_udc_pullup,
.vbus_session = s3c2410_udc_vbus_session,
.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)
@ -1664,33 +1665,14 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
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;
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 */
udc->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;
}
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 */
s3c2410_udc_enable(udc);
@ -1722,24 +1695,10 @@ register_error:
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);
udc->driver = NULL;

View File

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

View File

@ -36,10 +36,8 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "f_acm.c"
#include "f_obex.c"
#include "f_serial.c"
#include "u_serial.c"
/*-------------------------------------------------------------------------*/
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");
/*-------------------------------------------------------------------------*/
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;
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;
}
@ -152,13 +155,70 @@ static struct usb_configuration serial_config_driver = {
.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)
{
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
* 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 */
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)
goto fail;
@ -189,16 +257,31 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
return 0;
fail:
gserial_cleanup();
cur_line--;
while (cur_line >= 0)
gserial_free_line(tty_lines[cur_line--]);
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 = {
.name = "g_serial",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.bind = gs_bind,
.unbind = gs_unbind,
};
static int __init init(void)
@ -234,6 +317,5 @@ module_init(init);
static void __exit cleanup(void)
{
usb_composite_unregister(&gserial_driver);
gserial_cleanup();
}
module_exit(cleanup);

View File

@ -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 */
#define MAX_COMMAND_SIZE 16
@ -385,41 +373,6 @@ static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
/*.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[] = {
(struct usb_descriptor_header *) &fsg_intf_desc,
(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
@ -429,20 +382,6 @@ static struct usb_descriptor_header *fsg_ss_function[] = {
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 struct usb_string fsg_strings[] = {
{FSG_STRING_INTERFACE, fsg_string_interface},

View File

@ -26,6 +26,7 @@
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/module.h>
#include "u_serial.h"
@ -35,11 +36,12 @@
* "serial port" functionality through the USB gadget stack. Each such
* 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.
* 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 */
};
/* increase N_PORTS if you need more */
#define N_PORTS 4
static struct portmaster {
struct mutex lock; /* protect open/close */
struct gs_port *port;
} ports[N_PORTS];
static unsigned n_ports;
} ports[MAX_U_SERIAL_PORTS];
#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;
}
EXPORT_SYMBOL_GPL(gs_alloc_req);
/*
* gs_free_req
@ -320,6 +320,7 @@ void gs_free_req(struct usb_ep *ep, struct usb_request *req)
kfree(req->buf);
usb_ep_free_request(ep, req);
}
EXPORT_SYMBOL_GPL(gs_free_req);
/*
* gs_send_packet
@ -1030,10 +1031,19 @@ static int
gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
{
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);
if (port == NULL)
return -ENOMEM;
if (port == NULL) {
ret = -ENOMEM;
goto out;
}
tty_port_init(&port->port);
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;
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)
@ -1164,55 +1074,77 @@ static int gs_closed(struct gs_port *port)
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;
if (!gs_tty_driver)
mutex_lock(&ports[port_num].lock);
if (WARN_ON(!ports[port_num].port)) {
mutex_unlock(&ports[port_num].lock);
return;
/* 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);
/* 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);
}
n_ports = 0;
port = ports[port_num].port;
ports[port_num].port = NULL;
mutex_unlock(&ports[port_num].lock);
tty_unregister_driver(gs_tty_driver);
put_tty_driver(gs_tty_driver);
gs_tty_driver = NULL;
pr_debug("%s: cleaned up ttyGS* support\n", __func__);
gserial_free_port(port);
tty_unregister_device(gs_tty_driver, port_num);
}
EXPORT_SYMBOL_GPL(gserial_free_line);
int gserial_alloc_line(unsigned char *line_num)
{
struct usb_cdc_line_coding coding;
struct device *tty_dev;
int ret;
int port_num;
coding.dwDTERate = cpu_to_le32(9600);
coding.bCharFormat = 8;
coding.bParityType = USB_CDC_NO_PARITY;
coding.bDataBits = USB_CDC_1_STOP_BITS;
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;
}
if (ret)
return ret;
/* ... 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));
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
@ -1229,8 +1161,8 @@ void gserial_cleanup(void)
*
* Caller needs to have set up the endpoints and USB function in @dev
* 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.
* On success, ep->driver_data will be overwritten.
@ -1241,11 +1173,18 @@ int gserial_connect(struct gserial *gser, u8 port_num)
unsigned long flags;
int status;
if (!gs_tty_driver || port_num >= n_ports)
if (port_num >= MAX_U_SERIAL_PORTS)
return -ENXIO;
/* we "know" gserial_cleanup() hasn't been called */
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 */
status = usb_ep_enable(gser->in);
@ -1292,7 +1231,7 @@ fail_out:
gser->in->driver_data = NULL;
return status;
}
EXPORT_SYMBOL_GPL(gserial_connect);
/**
* gserial_disconnect - notify TTY I/O glue that USB link is inactive
* @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);
}
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");

View File

@ -15,6 +15,13 @@
#include <linux/usb/composite.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
* 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);
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 */
int gserial_connect(struct gserial *, u8 port_num);

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