usb: patches for v3.10 merge window

Here is the big Gadget & PHY pull request. Many of us have
 been really busy lately getting multiple drivers to a better
 position.
 
 Since this pull request is so large, I will divide it in sections
 so it's easier to grasp what's included.
 
 - cleanups:
 	. UDC drivers no longer touch gadget->dev, that's now udc-core
 		responsibility
 	. Many more UDC drivers converted to usb_gadget_map/unmap_request()
 	. UDC drivers no longer initialize DMA-related fields from gadget's
 		device structure
 	. UDC drivers don't touch gadget.dev.driver directly
 	. UDC drivers don't assign gadget.dev.release directly
 	. Removal of some unused DMA_ADDR_INVALID
 	. Introduction of CONFIG_USB_PHY
 	. All phy drivers have been moved to drivers/usb/phy and renamed to
 		a common naming scheme
 	. Fix PHY layer so it never returns a NULL pointer, also fix all
 		callers to avoid using IS_ERR_OR_NULL()
 	. Sparse fixes all over the place
 	. drivers/usb/otg/ has been deleted
 	. Marvel drivers (mv_udc, ehci-mv, mv_otg and mv_u3d) improved clock
 		usage
 
 - new features:
 	. UDC core now provides a generic way for tracking and reporting
 		UDC's state (not attached, resuming, suspended, addressed,
 		default, etc)
 	. twl4030-usb learned that it shouldn't be enabled during init
 	. Full DT support for DWC3 has been implemented
 	. ab8500-usb learned about pinctrl framework
 	. nop PHY learned about DeviceTree and regulators
 	. DWC3 learned about suspend/resume
 	. DWC3 can now be compiled in host-only and gadget-only (as well as
 		DRD) configurations
 	. UVC now enables streaming endpoint based on negotiated speed
 	. isp1301 now implements the PHY API properly
 	. configfs-based interface for gadget drivers which will lead to
 		the removal of all code which just combines functions together
 		to build functional gadget drivers.
 	. f_serial and f_obex were converted to new configfs interface while
 		maintaining old interface around.
 
 - non-critical fixes:
 	. UVC gadget driver got fixes for Endpoint usage and stream calculation
 	. ab8500-usb fixed unbalanced clock and regulator API usage
 	. twl4030-usb got a fix for when OMAP3 is booted with cable connected
 	. fusb300_udc got a fix for DMA usage
 	. UVC got fixes for two assertions of the USB Video Class Compliance
 		specification revision 1.1
 	. build warning issues caused by recent addition of __must_check to
 		regulator API
 
 These are all changes which deserve a mention, all other changes are related
 to these one or minor spelling fixes and other similar tasks.
 
 Signed-of-by: Felipe Balbi <balbi@ti.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJRXG8GAAoJEIaOsuA1yqREJzYQAKMLW3J/TKTWS1DDuf7qMtMz
 Ug6qChKZXgT1/QrNjsq2tx4jYIkNdSMtRKiUx0BnIptlUx6gM22gcsN8mXX/UJjC
 FYAiWl+tYe85e9uayqqt+qVCZjTZCc7St4wQalugDHefvA7yCbiZpSaJRGlJMK+x
 mePJ7MfrulDsYBXr0u+m2LOJ0qxMDi40k3/UN3aUu5yzrmBiRpVq1mySruvLwGFp
 Pr6vBnprEc6bW5sRdUR4SICKLvLk5sHwHpvpkzDLYBIb/jXQwbfQri/HKeh4VMk8
 trbsvHZyB7H8uuFsCHiBc6VtjcbZ4mxPUK+1PCq8hG077avdkm3ox0BERk9aRTeC
 jg4mdpyWjgovwi882woPEQXNZoaAXpVDyI8tBRx92a+rGJjXSHhLQI+4Ffi4ZvzV
 d+q1ZzrHxuzwa/BwcPETY76umXQqXWXg+ap1bHDY0RZFoPLdXMpl583NXGSn3gOD
 dUlD0UlgYwb75333tRIPNQn3qOx0HVd6MlYPMNzl9t9c9qqfX78AYRny6ZucupRg
 t9VZ6FO3D2yre9W7u3U3q2c9H7uSAKr/8xaNfvdsIWPncgvvYVIyE8MnR7AiHoPv
 ZYESs/Gs6w9vUsHa9K4J16Ape7D3AMcGpXUoPUxTBHrwBexzt4j27VWtcL4ns/9r
 0kcltUJ4Zq+PIjc7xgxe
 =aF4r
 -----END PGP SIGNATURE-----

Merge tag 'usb-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

usb: patches for v3.10 merge window

Here is the big Gadget & PHY pull request. Many of us have
been really busy lately getting multiple drivers to a better
position.

Since this pull request is so large, I will divide it in sections
so it's easier to grasp what's included.

- cleanups:
	. UDC drivers no longer touch gadget->dev, that's now udc-core
		responsibility
	. Many more UDC drivers converted to usb_gadget_map/unmap_request()
	. UDC drivers no longer initialize DMA-related fields from gadget's
		device structure
	. UDC drivers don't touch gadget.dev.driver directly
	. UDC drivers don't assign gadget.dev.release directly
	. Removal of some unused DMA_ADDR_INVALID
	. Introduction of CONFIG_USB_PHY
	. All phy drivers have been moved to drivers/usb/phy and renamed to
		a common naming scheme
	. Fix PHY layer so it never returns a NULL pointer, also fix all
		callers to avoid using IS_ERR_OR_NULL()
	. Sparse fixes all over the place
	. drivers/usb/otg/ has been deleted
	. Marvel drivers (mv_udc, ehci-mv, mv_otg and mv_u3d) improved clock
		usage

- new features:
	. UDC core now provides a generic way for tracking and reporting
		UDC's state (not attached, resuming, suspended, addressed,
		default, etc)
	. twl4030-usb learned that it shouldn't be enabled during init
	. Full DT support for DWC3 has been implemented
	. ab8500-usb learned about pinctrl framework
	. nop PHY learned about DeviceTree and regulators
	. DWC3 learned about suspend/resume
	. DWC3 can now be compiled in host-only and gadget-only (as well as
		DRD) configurations
	. UVC now enables streaming endpoint based on negotiated speed
	. isp1301 now implements the PHY API properly
	. configfs-based interface for gadget drivers which will lead to
		the removal of all code which just combines functions together
		to build functional gadget drivers.
	. f_serial and f_obex were converted to new configfs interface while
		maintaining old interface around.

- non-critical fixes:
	. UVC gadget driver got fixes for Endpoint usage and stream calculation
	. ab8500-usb fixed unbalanced clock and regulator API usage
	. twl4030-usb got a fix for when OMAP3 is booted with cable connected
	. fusb300_udc got a fix for DMA usage
	. UVC got fixes for two assertions of the USB Video Class Compliance
		specification revision 1.1
	. build warning issues caused by recent addition of __must_check to
		regulator API

These are all changes which deserve a mention, all other changes are related
to these one or minor spelling fixes and other similar tasks.

Signed-of-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Greg Kroah-Hartman 2013-04-05 15:18:00 -07:00
commit 64dc9e2e73
159 changed files with 6868 additions and 4499 deletions

View File

@ -8,10 +8,10 @@ OMAP MUSB GLUE
and disconnect. and disconnect.
- multipoint : Should be "1" indicating the musb controller supports - multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting. multipoint. This is a MUSB configuration-specific setting.
- num_eps : Specifies the number of endpoints. This is also a - num-eps : Specifies the number of endpoints. This is also a
MUSB configuration-specific setting. Should be set to "16" MUSB configuration-specific setting. Should be set to "16"
- ram_bits : Specifies the ram address size. Should be set to "12" - ram-bits : Specifies the ram address size. Should be set to "12"
- interface_type : This is a board specific setting to describe the type of - interface-type : This is a board specific setting to describe the type of
interface between the controller and the phy. It should be "0" or "1" interface between the controller and the phy. It should be "0" or "1"
specifying ULPI and UTMI respectively. specifying ULPI and UTMI respectively.
- mode : Should be "3" to represent OTG. "1" signifies HOST and "2" - mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
@ -29,18 +29,46 @@ usb_otg_hs: usb_otg_hs@4a0ab000 {
ti,hwmods = "usb_otg_hs"; ti,hwmods = "usb_otg_hs";
ti,has-mailbox; ti,has-mailbox;
multipoint = <1>; multipoint = <1>;
num_eps = <16>; num-eps = <16>;
ram_bits = <12>; ram-bits = <12>;
ctrl-module = <&omap_control_usb>; ctrl-module = <&omap_control_usb>;
}; };
Board specific device node entry Board specific device node entry
&usb_otg_hs { &usb_otg_hs {
interface_type = <1>; interface-type = <1>;
mode = <3>; mode = <3>;
power = <50>; power = <50>;
}; };
OMAP DWC3 GLUE
- compatible : Should be "ti,dwc3"
- ti,hwmods : Should be "usb_otg_ss"
- reg : Address and length of the register set for the device.
- interrupts : The irq number of this device that is used to interrupt the
MPU
- #address-cells, #size-cells : Must be present if the device has sub-nodes
- utmi-mode : controls the source of UTMI/PIPE status for VBUS and OTG ID.
It should be set to "1" for HW mode and "2" for SW mode.
- ranges: the child address space are mapped 1:1 onto the parent address space
Sub-nodes:
The dwc3 core should be added as subnode to omap dwc3 glue.
- dwc3 :
The binding details of dwc3 can be found in:
Documentation/devicetree/bindings/usb/dwc3.txt
omap_dwc3 {
compatible = "ti,dwc3";
ti,hwmods = "usb_otg_ss";
reg = <0x4a020000 0x1ff>;
interrupts = <0 93 4>;
#address-cells = <1>;
#size-cells = <1>;
utmi-mode = <2>;
ranges;
};
OMAP CONTROL USB OMAP CONTROL USB
Required properties: Required properties:

View File

@ -1,20 +1,25 @@
* Samsung's usb phy transceiver SAMSUNG USB-PHY controllers
The Samsung's phy transceiver is used for controlling usb phy for ** Samsung's usb 2.0 phy transceiver
s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
across Samsung SOCs. The Samsung's usb 2.0 phy transceiver is used for controlling
usb 2.0 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 TODO: Adding the PHY binding with controller(s) according to the under
developement generic PHY driver. developement generic PHY driver.
Required properties: Required properties:
Exynos4210: Exynos4210:
- compatible : should be "samsung,exynos4210-usbphy" - compatible : should be "samsung,exynos4210-usb2phy"
- reg : base physical address of the phy registers and length of memory mapped - reg : base physical address of the phy registers and length of memory mapped
region. region.
- clocks: Clock IDs array as required by the controller.
- clock-names: names of clock correseponding IDs clock property as requested
by the controller driver.
Exynos5250: Exynos5250:
- compatible : should be "samsung,exynos5250-usbphy" - compatible : should be "samsung,exynos5250-usb2phy"
- reg : base physical address of the phy registers and length of memory mapped - reg : base physical address of the phy registers and length of memory mapped
region. region.
@ -44,12 +49,69 @@ Example:
usbphy@125B0000 { usbphy@125B0000 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "samsung,exynos4210-usbphy"; compatible = "samsung,exynos4210-usb2phy";
reg = <0x125B0000 0x100>; reg = <0x125B0000 0x100>;
ranges; ranges;
clocks = <&clock 2>, <&clock 305>;
clock-names = "xusbxti", "otg";
usbphy-sys { usbphy-sys {
/* USB device and host PHY_CONTROL registers */ /* USB device and host PHY_CONTROL registers */
reg = <0x10020704 0x8>; reg = <0x10020704 0x8>;
}; };
}; };
** Samsung's usb 3.0 phy transceiver
Starting exynso5250, Samsung's SoC have usb 3.0 phy transceiver
which is used for controlling usb 3.0 phy for dwc3-exynos usb 3.0
controllers across Samsung SOCs.
Required properties:
Exynos5250:
- compatible : should be "samsung,exynos5250-usb3phy"
- reg : base physical address of the phy registers and length of memory mapped
region.
- clocks: Clock IDs array as required by the controller.
- clock-names: names of clocks correseponding to IDs in the clock property
as requested by the controller driver.
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:
usbphy@12100000 {
compatible = "samsung,exynos5250-usb3phy";
reg = <0x12100000 0x100>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&clock 1>, <&clock 286>;
clock-names = "ext_xtal", "usbdrd30";
usbphy-sys {
/* USB device and host PHY_CONTROL registers */
reg = <0x10040704 0x8>;
};
};

View File

@ -0,0 +1,34 @@
USB NOP PHY
Required properties:
- compatible: should be usb-nop-xceiv
Optional properties:
- clocks: phandle to the PHY clock. Use as per Documentation/devicetree
/bindings/clock/clock-bindings.txt
This property is required if clock-frequency is specified.
- clock-names: Should be "main_clk"
- clock-frequency: the clock frequency (in Hz) that the PHY clock must
be configured to.
- vcc-supply: phandle to the regulator that provides RESET to the PHY.
- reset-supply: phandle to the regulator that provides power to the PHY.
Example:
hsusb1_phy {
compatible = "usb-nop-xceiv";
clock-frequency = <19200000>;
clocks = <&osc 0>;
clock-names = "main_clk";
vcc-supply = <&hsusb1_vcc_regulator>;
reset-supply = <&hsusb1_reset_regulator>;
};
hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
hsusb1_vcc_regulator provides power to the PHY and hsusb1_reset_regulator
controls RESET.

View File

@ -223,13 +223,7 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
}; };
#if defined(CONFIG_USB_EHCI_MV) #if defined(CONFIG_USB_EHCI_MV)
static char *pxa168_sph_clock_name[] = {
[0] = "PXA168-USBCLK",
};
static struct mv_usb_platform_data pxa168_sph_pdata = { static struct mv_usb_platform_data pxa168_sph_pdata = {
.clknum = 1,
.clkname = pxa168_sph_clock_name,
.mode = MV_USB_MODE_HOST, .mode = MV_USB_MODE_HOST,
.phy_init = pxa_usb_phy_init, .phy_init = pxa_usb_phy_init,
.phy_deinit = pxa_usb_phy_deinit, .phy_deinit = pxa_usb_phy_deinit,

View File

@ -162,13 +162,7 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
#ifdef CONFIG_USB_SUPPORT #ifdef CONFIG_USB_SUPPORT
#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O) #if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
static char *pxa910_usb_clock_name[] = {
[0] = "U2OCLK",
};
static struct mv_usb_platform_data ttc_usb_pdata = { static struct mv_usb_platform_data ttc_usb_pdata = {
.clknum = 1,
.clkname = pxa910_usb_clock_name,
.vbus = NULL, .vbus = NULL,
.mode = MV_USB_MODE_OTG, .mode = MV_USB_MODE_OTG,
.otg_force_a_bus_req = 1, .otg_force_a_bus_req = 1,

View File

@ -169,7 +169,7 @@ static int usbhsf_get_id(struct platform_device *pdev)
return USBHS_GADGET; return USBHS_GADGET;
} }
static void usbhsf_power_ctrl(struct platform_device *pdev, static int usbhsf_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable) void __iomem *base, int enable)
{ {
struct usbhsf_private *priv = usbhsf_get_priv(pdev); struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@ -223,6 +223,8 @@ static void usbhsf_power_ctrl(struct platform_device *pdev,
clk_disable(priv->pci); /* usb work around */ clk_disable(priv->pci); /* usb work around */
clk_disable(priv->usb24); /* usb work around */ clk_disable(priv->usb24); /* usb work around */
} }
return 0;
} }
static int usbhsf_get_vbus(struct platform_device *pdev) static int usbhsf_get_vbus(struct platform_device *pdev)
@ -239,7 +241,7 @@ static irqreturn_t usbhsf_interrupt(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void usbhsf_hardware_exit(struct platform_device *pdev) static int usbhsf_hardware_exit(struct platform_device *pdev)
{ {
struct usbhsf_private *priv = usbhsf_get_priv(pdev); struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@ -264,6 +266,8 @@ static void usbhsf_hardware_exit(struct platform_device *pdev)
priv->usbh_base = NULL; priv->usbh_base = NULL;
free_irq(IRQ7, pdev); free_irq(IRQ7, pdev);
return 0;
} }
static int usbhsf_hardware_init(struct platform_device *pdev) static int usbhsf_hardware_init(struct platform_device *pdev)

View File

@ -155,12 +155,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
return !((1 << 7) & __raw_readw(priv->cr2)); return !((1 << 7) & __raw_readw(priv->cr2));
} }
static void usbhs_phy_reset(struct platform_device *pdev) static int usbhs_phy_reset(struct platform_device *pdev)
{ {
struct usbhs_private *priv = usbhs_get_priv(pdev); struct usbhs_private *priv = usbhs_get_priv(pdev);
/* init phy */ /* init phy */
__raw_writew(0x8a0a, priv->cr2); __raw_writew(0x8a0a, priv->cr2);
return 0;
} }
static int usbhs_get_id(struct platform_device *pdev) static int usbhs_get_id(struct platform_device *pdev)
@ -202,7 +204,7 @@ static int usbhs_hardware_init(struct platform_device *pdev)
return 0; return 0;
} }
static void usbhs_hardware_exit(struct platform_device *pdev) static int usbhs_hardware_exit(struct platform_device *pdev)
{ {
struct usbhs_private *priv = usbhs_get_priv(pdev); struct usbhs_private *priv = usbhs_get_priv(pdev);
@ -210,6 +212,8 @@ static void usbhs_hardware_exit(struct platform_device *pdev)
__raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy); __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy);
free_irq(IRQ15, pdev); free_irq(IRQ15, pdev);
return 0;
} }
static u32 usbhs_pipe_cfg[] = { static u32 usbhs_pipe_cfg[] = {

View File

@ -596,12 +596,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
return usbhs_is_connected(usbhs_get_priv(pdev)); return usbhs_is_connected(usbhs_get_priv(pdev));
} }
static void usbhs_phy_reset(struct platform_device *pdev) static int usbhs_phy_reset(struct platform_device *pdev)
{ {
struct usbhs_private *priv = usbhs_get_priv(pdev); struct usbhs_private *priv = usbhs_get_priv(pdev);
/* init phy */ /* init phy */
__raw_writew(0x8a0a, priv->usbcrcaddr); __raw_writew(0x8a0a, priv->usbcrcaddr);
return 0;
} }
static int usbhs0_get_id(struct platform_device *pdev) static int usbhs0_get_id(struct platform_device *pdev)
@ -628,11 +630,13 @@ static int usbhs0_hardware_init(struct platform_device *pdev)
return 0; return 0;
} }
static void usbhs0_hardware_exit(struct platform_device *pdev) static int usbhs0_hardware_exit(struct platform_device *pdev)
{ {
struct usbhs_private *priv = usbhs_get_priv(pdev); struct usbhs_private *priv = usbhs_get_priv(pdev);
cancel_delayed_work_sync(&priv->work); cancel_delayed_work_sync(&priv->work);
return 0;
} }
static struct usbhs_private usbhs0_private = { static struct usbhs_private usbhs0_private = {
@ -735,7 +739,7 @@ static int usbhs1_hardware_init(struct platform_device *pdev)
return 0; return 0;
} }
static void usbhs1_hardware_exit(struct platform_device *pdev) static int usbhs1_hardware_exit(struct platform_device *pdev)
{ {
struct usbhs_private *priv = usbhs_get_priv(pdev); struct usbhs_private *priv = usbhs_get_priv(pdev);
@ -743,6 +747,8 @@ static void usbhs1_hardware_exit(struct platform_device *pdev)
__raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr); __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
free_irq(IRQ8, pdev); free_irq(IRQ8, pdev);
return 0;
} }
static int usbhs1_get_id(struct platform_device *pdev) static int usbhs1_get_id(struct platform_device *pdev)

View File

@ -18,8 +18,8 @@ config ARCH_TEGRA_2x_SOC
select PL310_ERRATA_727915 if CACHE_L2X0 select PL310_ERRATA_727915 if CACHE_L2X0
select PL310_ERRATA_769419 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT select USB_ARCH_HAS_EHCI if USB_SUPPORT
select USB_ULPI if USB select USB_ULPI if USB_PHY
select USB_ULPI_VIEWPORT if USB_SUPPORT select USB_ULPI_VIEWPORT if USB_PHY
help help
Support for NVIDIA Tegra AP20 and T20 processors, based on the Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@ -37,8 +37,8 @@ config ARCH_TEGRA_3x_SOC
select PINCTRL_TEGRA30 select PINCTRL_TEGRA30
select PL310_ERRATA_769419 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT select USB_ARCH_HAS_EHCI if USB_SUPPORT
select USB_ULPI if USB select USB_ULPI if USB_PHY
select USB_ULPI_VIEWPORT if USB_SUPPORT select USB_ULPI_VIEWPORT if USB_PHY
help help
Support for NVIDIA Tegra T30 processor family, based on the Support for NVIDIA Tegra T30 processor family, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller ARM CortexA9MP CPU and the ARM PL310 L2 cache controller

View File

@ -254,11 +254,13 @@ static int usbhs_get_id(struct platform_device *pdev)
return gpio_get_value(GPIO_PTB3); return gpio_get_value(GPIO_PTB3);
} }
static void usbhs_phy_reset(struct platform_device *pdev) static int usbhs_phy_reset(struct platform_device *pdev)
{ {
/* enable vbus if HOST */ /* enable vbus if HOST */
if (!gpio_get_value(GPIO_PTB3)) if (!gpio_get_value(GPIO_PTB3))
gpio_set_value(GPIO_PTB5, 1); gpio_set_value(GPIO_PTB5, 1);
return 0;
} }
static struct renesas_usbhs_platform_info usbhs_info = { static struct renesas_usbhs_platform_info usbhs_info = {

View File

@ -79,7 +79,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_UWB) += uwb/
obj-$(CONFIG_USB_OTG_UTILS) += usb/ obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/ obj-$(CONFIG_USB_GADGET) += usb/

View File

@ -254,7 +254,7 @@ config BATTERY_RX51
config CHARGER_ISP1704 config CHARGER_ISP1704
tristate "ISP1704 USB Charger Detection" tristate "ISP1704 USB Charger Detection"
depends on USB_OTG_UTILS depends on USB_PHY
help help
Say Y to enable support for USB Charger Detection with Say Y to enable support for USB Charger Detection with
ISP1707/ISP1704 USB transceivers. ISP1707/ISP1704 USB transceivers.

View File

@ -35,7 +35,7 @@ static struct timer_list supply_timer;
static struct timer_list polling_timer; static struct timer_list polling_timer;
static int polling; static int polling;
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
static struct usb_phy *transceiver; static struct usb_phy *transceiver;
static struct notifier_block otg_nb; static struct notifier_block otg_nb;
#endif #endif
@ -218,7 +218,7 @@ static void polling_timer_func(unsigned long unused)
jiffies + msecs_to_jiffies(pdata->polling_interval)); jiffies + msecs_to_jiffies(pdata->polling_interval));
} }
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
static int otg_is_usb_online(void) static int otg_is_usb_online(void)
{ {
return (transceiver->last_event == USB_EVENT_VBUS || return (transceiver->last_event == USB_EVENT_VBUS ||
@ -315,7 +315,7 @@ static int pda_power_probe(struct platform_device *pdev)
pda_psy_usb.num_supplicants = pdata->num_supplicants; pda_psy_usb.num_supplicants = pdata->num_supplicants;
} }
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
transceiver = usb_get_phy(USB_PHY_TYPE_USB2); transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(transceiver)) { if (!IS_ERR_OR_NULL(transceiver)) {
if (!pdata->is_usb_online) if (!pdata->is_usb_online)
@ -367,7 +367,7 @@ static int pda_power_probe(struct platform_device *pdev)
} }
} }
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) { if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
otg_nb.notifier_call = otg_handle_notification; otg_nb.notifier_call = otg_handle_notification;
ret = usb_register_notifier(transceiver, &otg_nb); ret = usb_register_notifier(transceiver, &otg_nb);
@ -391,7 +391,7 @@ static int pda_power_probe(struct platform_device *pdev)
return 0; return 0;
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
otg_reg_notifier_failed: otg_reg_notifier_failed:
if (pdata->is_usb_online && usb_irq) if (pdata->is_usb_online && usb_irq)
free_irq(usb_irq->start, &pda_psy_usb); free_irq(usb_irq->start, &pda_psy_usb);
@ -402,7 +402,7 @@ static int pda_power_probe(struct platform_device *pdev)
usb_supply_failed: usb_supply_failed:
if (pdata->is_ac_online && ac_irq) if (pdata->is_ac_online && ac_irq)
free_irq(ac_irq->start, &pda_psy_ac); free_irq(ac_irq->start, &pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver)) if (!IS_ERR_OR_NULL(transceiver))
usb_put_phy(transceiver); usb_put_phy(transceiver);
#endif #endif
@ -437,7 +437,7 @@ static int pda_power_remove(struct platform_device *pdev)
power_supply_unregister(&pda_psy_usb); power_supply_unregister(&pda_psy_usb);
if (pdata->is_ac_online) if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac); power_supply_unregister(&pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS #if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver)) if (!IS_ERR_OR_NULL(transceiver))
usb_put_phy(transceiver); usb_put_phy(transceiver);
#endif #endif

View File

@ -186,6 +186,4 @@ source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig" source "drivers/usb/gadget/Kconfig"
source "drivers/usb/otg/Kconfig"
endif # USB_SUPPORT endif # USB_SUPPORT

View File

@ -6,8 +6,6 @@
obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MON) += mon/
@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_OTG_UTILS) += phy/ obj-$(CONFIG_USB_PHY) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_ATM) += atm/

View File

@ -1638,16 +1638,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
return retval; return retval;
} }
/**
* udc_release: driver release function
* @dev: device
*
* Currently does nothing
*/
static void udc_release(struct device *dev)
{
}
/** /**
* udc_start: initialize gadget role * udc_start: initialize gadget role
* @ci: chipidea controller * @ci: chipidea controller
@ -1667,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list); INIT_LIST_HEAD(&ci->gadget.ep_list);
dev_set_name(&ci->gadget.dev, "gadget");
ci->gadget.dev.dma_mask = dev->dma_mask;
ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
ci->gadget.dev.parent = dev;
ci->gadget.dev.release = udc_release;
/* alloc resources */ /* alloc resources */
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev, ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
sizeof(struct ci13xxx_qh), sizeof(struct ci13xxx_qh),
@ -1710,17 +1694,11 @@ static int udc_start(struct ci13xxx *ci)
goto put_transceiver; goto put_transceiver;
} }
retval = device_register(&ci->gadget.dev);
if (retval) {
put_device(&ci->gadget.dev);
goto put_transceiver;
}
if (!IS_ERR_OR_NULL(ci->transceiver)) { if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg, retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget); &ci->gadget);
if (retval) if (retval)
goto unreg_device; goto put_transceiver;
} }
retval = usb_add_gadget_udc(dev, &ci->gadget); retval = usb_add_gadget_udc(dev, &ci->gadget);
@ -1740,8 +1718,6 @@ static int udc_start(struct ci13xxx *ci)
} }
dev_err(dev, "error = %i\n", retval); dev_err(dev, "error = %i\n", retval);
unreg_device:
device_unregister(&ci->gadget.dev);
put_transceiver: put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy) if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver); usb_put_phy(ci->transceiver);
@ -1776,7 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy) if (ci->global_phy)
usb_put_phy(ci->transceiver); usb_put_phy(ci->transceiver);
} }
device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */ /* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget)); memset(&ci->gadget, 0, sizeof(ci->gadget));
} }

View File

@ -1,7 +1,6 @@
config USB_DWC3 config USB_DWC3
tristate "DesignWare USB3 DRD Core Support" tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
select USB_OTG_UTILS
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help help
Say Y or M here if your system has a Dual Role SuperSpeed Say Y or M here if your system has a Dual Role SuperSpeed

View File

@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
* Returns a pointer to the allocated event buffer structure on success * Returns a pointer to the allocated event buffer structure on success
* otherwise ERR_PTR(errno). * otherwise ERR_PTR(errno).
*/ */
static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
unsigned length)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
} }
} }
static void dwc3_core_num_eps(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
dwc->num_in_eps, dwc->num_out_eps);
}
static void dwc3_cache_hwparams(struct dwc3 *dwc) static void dwc3_cache_hwparams(struct dwc3 *dwc)
{ {
struct dwc3_hwparams *parms = &dwc->hwparams; struct dwc3_hwparams *parms = &dwc->hwparams;
@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->revision < DWC3_REVISION_190A) if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN; reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_core_num_eps(dwc);
ret = dwc3_event_buffers_setup(dwc); dwc3_writel(dwc->regs, DWC3_GCTL, reg);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err0;
}
return 0; return 0;
@ -351,8 +359,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
static void dwc3_core_exit(struct dwc3 *dwc) static void dwc3_core_exit(struct dwc3 *dwc)
{ {
dwc3_event_buffers_cleanup(dwc);
usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb3_phy);
} }
@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
} }
if (IS_ERR_OR_NULL(dwc->usb2_phy)) { if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
/*
* if -ENXIO is returned, it means PHY layer wasn't
* enabled, so it makes no sense to return -EPROBE_DEFER
* in that case, since no PHY driver will ever probe.
*/
if (ret == -ENXIO)
return ret;
dev_err(dev, "no usb2 phy configured\n"); dev_err(dev, "no usb2 phy configured\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
if (IS_ERR_OR_NULL(dwc->usb3_phy)) { if (IS_ERR(dwc->usb3_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
/*
* if -ENXIO is returned, it means PHY layer wasn't
* enabled, so it makes no sense to return -EPROBE_DEFER
* in that case, since no PHY driver will ever probe.
*/
if (ret == -ENXIO)
return ret;
dev_err(dev, "no usb3 phy configured\n"); dev_err(dev, "no usb3 phy configured\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs_size = resource_size(res); dwc->regs_size = resource_size(res);
dwc->dev = dev; dwc->dev = dev;
dev->dma_mask = dev->parent->dma_mask;
dev->dma_parms = dev->parent->dma_parms;
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
if (!strncmp("super", maximum_speed, 5)) if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
else if (!strncmp("high", maximum_speed, 4)) else if (!strncmp("high", maximum_speed, 4))
@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
mode = DWC3_MODE(dwc->hwparams.hwparams0); ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err1;
}
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
mode = DWC3_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
mode = DWC3_MODE_DEVICE;
else
mode = DWC3_MODE_DRD;
switch (mode) { switch (mode) {
case DWC3_MODE_DEVICE: case DWC3_MODE_DEVICE:
@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_gadget_init(dwc); ret = dwc3_gadget_init(dwc);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize gadget\n"); dev_err(dev, "failed to initialize gadget\n");
goto err1; goto err2;
} }
break; break;
case DWC3_MODE_HOST: case DWC3_MODE_HOST:
@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc); ret = dwc3_host_init(dwc);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize host\n"); dev_err(dev, "failed to initialize host\n");
goto err1; goto err2;
} }
break; break;
case DWC3_MODE_DRD: case DWC3_MODE_DRD:
@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc); ret = dwc3_host_init(dwc);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize host\n"); dev_err(dev, "failed to initialize host\n");
goto err1; goto err2;
} }
ret = dwc3_gadget_init(dwc); ret = dwc3_gadget_init(dwc);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize gadget\n"); dev_err(dev, "failed to initialize gadget\n");
goto err1; goto err2;
} }
break; break;
default: default:
dev_err(dev, "Unsupported mode of operation %d\n", mode); dev_err(dev, "Unsupported mode of operation %d\n", mode);
goto err1; goto err2;
} }
dwc->mode = mode; dwc->mode = mode;
ret = dwc3_debugfs_init(dwc); ret = dwc3_debugfs_init(dwc);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize debugfs\n"); dev_err(dev, "failed to initialize debugfs\n");
goto err2; goto err3;
} }
pm_runtime_allow(dev); pm_runtime_allow(dev);
return 0; return 0;
err2: err3:
switch (mode) { switch (mode) {
case DWC3_MODE_DEVICE: case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc); dwc3_gadget_exit(dwc);
@ -546,6 +587,9 @@ static int dwc3_probe(struct platform_device *pdev)
break; break;
} }
err2:
dwc3_event_buffers_cleanup(dwc);
err1: err1:
dwc3_core_exit(dwc); dwc3_core_exit(dwc);
@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev)
break; break;
} }
dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc); dwc3_free_event_buffers(dwc);
dwc3_core_exit(dwc); dwc3_core_exit(dwc);
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int dwc3_prepare(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
switch (dwc->mode) {
case DWC3_MODE_DEVICE:
case DWC3_MODE_DRD:
dwc3_gadget_prepare(dwc);
/* FALLTHROUGH */
case DWC3_MODE_HOST:
default:
dwc3_event_buffers_cleanup(dwc);
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static void dwc3_complete(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
switch (dwc->mode) {
case DWC3_MODE_DEVICE:
case DWC3_MODE_DRD:
dwc3_gadget_complete(dwc);
/* FALLTHROUGH */
case DWC3_MODE_HOST:
default:
dwc3_event_buffers_setup(dwc);
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
}
static int dwc3_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
switch (dwc->mode) {
case DWC3_MODE_DEVICE:
case DWC3_MODE_DRD:
dwc3_gadget_suspend(dwc);
/* FALLTHROUGH */
case DWC3_MODE_HOST:
default:
/* do nothing */
break;
}
dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
spin_unlock_irqrestore(&dwc->lock, flags);
usb_phy_shutdown(dwc->usb3_phy);
usb_phy_shutdown(dwc->usb2_phy);
return 0;
}
static int dwc3_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
usb_phy_init(dwc->usb3_phy);
usb_phy_init(dwc->usb2_phy);
msleep(100);
spin_lock_irqsave(&dwc->lock, flags);
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
switch (dwc->mode) {
case DWC3_MODE_DEVICE:
case DWC3_MODE_DRD:
dwc3_gadget_resume(dwc);
/* FALLTHROUGH */
case DWC3_MODE_HOST:
default:
/* do nothing */
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
}
static const struct dev_pm_ops dwc3_dev_pm_ops = {
.prepare = dwc3_prepare,
.complete = dwc3_complete,
SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
};
#define DWC3_PM_OPS &(dwc3_dev_pm_ops)
#else
#define DWC3_PM_OPS NULL
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id of_dwc3_match[] = { static const struct of_device_id of_dwc3_match[] = {
{ {
@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = {
.driver = { .driver = {
.name = "dwc3", .name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match), .of_match_table = of_match_ptr(of_dwc3_match),
.pm = DWC3_PM_OPS,
}, },
}; };

View File

@ -154,8 +154,9 @@
/* OTG Registers */ /* OTG Registers */
#define DWC3_OCFG 0xcc00 #define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04 #define DWC3_OCTL 0xcc04
#define DWC3_OEVTEN 0xcc08 #define DWC3_OEVT 0xcc08
#define DWC3_OSTS 0xcc0C #define DWC3_OEVTEN 0xcc0C
#define DWC3_OSTS 0xcc10
/* Bit fields */ /* Bit fields */
@ -369,6 +370,9 @@ struct dwc3_trb;
* @list: a list of event buffers * @list: a list of event buffers
* @buf: _THE_ buffer * @buf: _THE_ buffer
* @length: size of this buffer * @length: size of this buffer
* @lpos: event offset
* @count: cache of last read event count register
* @flags: flags related to this event buffer
* @dma: dma_addr_t * @dma: dma_addr_t
* @dwc: pointer to DWC controller * @dwc: pointer to DWC controller
*/ */
@ -376,6 +380,10 @@ struct dwc3_event_buffer {
void *buf; void *buf;
unsigned length; unsigned length;
unsigned int lpos; unsigned int lpos;
unsigned int count;
unsigned int flags;
#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma; dma_addr_t dma;
@ -487,12 +495,6 @@ enum dwc3_link_state {
DWC3_LINK_STATE_MASK = 0x0f, DWC3_LINK_STATE_MASK = 0x0f,
}; };
enum dwc3_device_state {
DWC3_DEFAULT_STATE,
DWC3_ADDRESS_STATE,
DWC3_CONFIGURED_STATE,
};
/* TRB Length, PCM and Status */ /* TRB Length, PCM and Status */
#define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_MASK (0x00ffffff)
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
@ -574,6 +576,14 @@ struct dwc3_hwparams {
/* HWPARAMS1 */ /* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
/* HWPARAMS3 */
#define DWC3_NUM_IN_EPS_MASK (0x1f << 18)
#define DWC3_NUM_EPS_MASK (0x3f << 12)
#define DWC3_NUM_EPS(p) (((p)->hwparams3 & \
(DWC3_NUM_EPS_MASK)) >> 12)
#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \
(DWC3_NUM_IN_EPS_MASK)) >> 18)
/* HWPARAMS7 */ /* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver * @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers * @regs: base address for our registers
* @regs_size: address space size * @regs_size: address space size
* @irq: IRQ number
* @num_event_buffers: calculated number of event buffers * @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround * @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes) * @maximum_speed: maximum speed requested (mainly for testing purposes)
@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
* @mode: mode of operation * @mode: mode of operation
* @usb2_phy: pointer to USB2 PHY * @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY * @usb3_phy: pointer to USB3 PHY
* @dcfg: saved contents of DCFG register
* @gctl: saved contents of GCTL register
* @is_selfpowered: true when we are selfpowered * @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup * @three_stage_setup: set if we perform a three phase setup
* @ep0_bounced: true when we used bounce buffer * @ep0_bounced: true when we used bounce buffer
@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
* @u2pel: parameter from Set SEL request. * @u2pel: parameter from Set SEL request.
* @u1sel: parameter from Set SEL request. * @u1sel: parameter from Set SEL request.
* @u1pel: parameter from Set SEL request. * @u1pel: parameter from Set SEL request.
* @num_out_eps: number of out endpoints
* @num_in_eps: number of in endpoints
* @ep0_next_event: hold the next expected event * @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero * @ep0state: state of endpoint zero
* @link_state: link state * @link_state: link state
@ -656,8 +669,10 @@ struct dwc3 {
dma_addr_t ep0_trb_addr; dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr; dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req; struct dwc3_request ep0_usb_req;
/* device lock */ /* device lock */
spinlock_t lock; spinlock_t lock;
struct device *dev; struct device *dev;
struct platform_device *xhci; struct platform_device *xhci;
@ -675,6 +690,10 @@ struct dwc3 {
void __iomem *regs; void __iomem *regs;
size_t regs_size; size_t regs_size;
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
u32 num_event_buffers; u32 num_event_buffers;
u32 u1u2; u32 u1u2;
u32 maximum_speed; u32 maximum_speed;
@ -694,6 +713,9 @@ struct dwc3 {
#define DWC3_REVISION_202A 0x5533202a #define DWC3_REVISION_202A 0x5533202a
#define DWC3_REVISION_210A 0x5533210a #define DWC3_REVISION_210A 0x5533210a
#define DWC3_REVISION_220A 0x5533220a #define DWC3_REVISION_220A 0x5533220a
#define DWC3_REVISION_230A 0x5533230a
#define DWC3_REVISION_240A 0x5533240a
#define DWC3_REVISION_250A 0x5533250a
unsigned is_selfpowered:1; unsigned is_selfpowered:1;
unsigned three_stage_setup:1; unsigned three_stage_setup:1;
@ -704,11 +726,11 @@ struct dwc3 {
unsigned delayed_status:1; unsigned delayed_status:1;
unsigned needs_fifo_resize:1; unsigned needs_fifo_resize:1;
unsigned resize_fifos:1; unsigned resize_fifos:1;
unsigned pullups_connected:1;
enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state; enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state; enum dwc3_link_state link_state;
enum dwc3_device_state dev_state;
u16 isoch_delay; u16 isoch_delay;
u16 u2sel; u16 u2sel;
@ -718,6 +740,9 @@ struct dwc3 {
u8 speed; u8 speed;
u8 num_out_eps;
u8 num_in_eps;
void *mem; void *mem;
struct dwc3_hwparams hwparams; struct dwc3_hwparams hwparams;
@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ } { }
#endif #endif
/* power management interface */
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
int dwc3_gadget_prepare(struct dwc3 *dwc);
void dwc3_gadget_complete(struct dwc3 *dwc);
int dwc3_gadget_suspend(struct dwc3 *dwc);
int dwc3_gadget_resume(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_prepare(struct dwc3 *dwc)
{
return 0;
}
static inline void dwc3_gadget_complete(struct dwc3 *dwc)
{
}
static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
{
return 0;
}
static inline int dwc3_gadget_resume(struct dwc3 *dwc)
{
return 0;
}
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
#endif /* __DRIVERS_USB_DWC3_CORE_H */ #endif /* __DRIVERS_USB_DWC3_CORE_H */

View File

@ -59,7 +59,7 @@
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
} }
static struct debugfs_reg32 dwc3_regs[] = { static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GSBUSCFG0), dump_register(GSBUSCFG0),
dump_register(GSBUSCFG1), dump_register(GSBUSCFG1),
dump_register(GTXTHRCFG), dump_register(GTXTHRCFG),
@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = {
dump_register(OCFG), dump_register(OCFG),
dump_register(OCTL), dump_register(OCTL),
dump_register(OEVT),
dump_register(OEVTEN), dump_register(OEVTEN),
dump_register(OSTS), dump_register(OSTS),
}; };
@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
case DWC3_LINK_STATE_LPBK: case DWC3_LINK_STATE_LPBK:
seq_printf(s, "Loopback\n"); seq_printf(s, "Loopback\n");
break; break;
case DWC3_LINK_STATE_RESET:
seq_printf(s, "Reset\n");
break;
case DWC3_LINK_STATE_RESUME:
seq_printf(s, "Resume\n");
break;
default: default:
seq_printf(s, "UNKNOWN %d\n", reg); seq_printf(s, "UNKNOWN %d\n", state);
} }
return 0; return 0;
@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
goto err1; goto err1;
} }
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops); dwc, &dwc3_mode_fops);
if (!file) { if (!file) {
ret = -ENOMEM; ret = -ENOMEM;
goto err1; goto err1;
}
} }
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
dwc, &dwc3_testmode_fops); IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
if (!file) { file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
ret = -ENOMEM; dwc, &dwc3_testmode_fops);
goto err1; if (!file) {
} ret = -ENOMEM;
goto err1;
}
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_link_state_fops); dwc, &dwc3_link_state_fops);
if (!file) { if (!file) {
ret = -ENOMEM; ret = -ENOMEM;
goto err1; goto err1;
}
} }
#endif
return 0; return 0;

View File

@ -22,9 +22,9 @@
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h> #include <linux/usb/nop-usb-xceiv.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h>
struct dwc3_exynos { struct dwc3_exynos {
struct platform_device *dwc3;
struct platform_device *usb2_phy; struct platform_device *usb2_phy;
struct platform_device *usb3_phy; struct platform_device *usb3_phy;
struct device *dev; struct device *dev;
@ -86,21 +86,30 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
return ret; return ret;
} }
static int dwc3_exynos_remove_child(struct device *dev, void *unused)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
static int dwc3_exynos_probe(struct platform_device *pdev) static int dwc3_exynos_probe(struct platform_device *pdev)
{ {
struct platform_device *dwc3;
struct dwc3_exynos *exynos; struct dwc3_exynos *exynos;
struct clk *clk; struct clk *clk;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
int ret = -ENOMEM; int ret = -ENOMEM;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos) { if (!exynos) {
dev_err(dev, "not enough memory\n"); dev_err(dev, "not enough memory\n");
return -ENOMEM; goto err1;
} }
/* /*
@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now. * Since shared usb code relies on it, set it here for now.
* Once we move to full device tree support this will vanish off. * Once we move to full device tree support this will vanish off.
*/ */
if (!pdev->dev.dma_mask) if (!dev->dma_mask)
pdev->dev.dma_mask = &dwc3_exynos_dma_mask; dev->dma_mask = &dwc3_exynos_dma_mask;
platform_set_drvdata(pdev, exynos); platform_set_drvdata(pdev, exynos);
ret = dwc3_exynos_register_phys(exynos); ret = dwc3_exynos_register_phys(exynos);
if (ret) { if (ret) {
dev_err(dev, "couldn't register PHYs\n"); dev_err(dev, "couldn't register PHYs\n");
return ret; goto err1;
}
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
return -ENOMEM;
} }
clk = devm_clk_get(dev, "usbdrd30"); clk = devm_clk_get(dev, "usbdrd30");
@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
goto err1; goto err1;
} }
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;
exynos->dwc3 = dwc3;
exynos->dev = dev; exynos->dev = dev;
exynos->clk = clk; exynos->clk = clk;
clk_enable(exynos->clk); clk_prepare_enable(exynos->clk);
ret = platform_device_add_resources(dwc3, pdev->resource, if (node) {
pdev->num_resources); ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) { if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n"); dev_err(dev, "failed to add dwc3 core\n");
goto err2; goto err2;
} }
} else {
ret = platform_device_add(dwc3); dev_err(dev, "no device node, failed to add dwc3 core\n");
if (ret) { ret = -ENODEV;
dev_err(dev, "failed to register dwc3 device\n");
goto err2; goto err2;
} }
return 0; return 0;
err2: err2:
clk_disable(clk); clk_disable_unprepare(clk);
err1: err1:
platform_device_put(dwc3);
return ret; return ret;
} }
@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{ {
struct dwc3_exynos *exynos = platform_get_drvdata(pdev); struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
platform_device_unregister(exynos->dwc3);
platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy); platform_device_unregister(exynos->usb3_phy);
device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
clk_disable(exynos->clk); clk_disable_unprepare(exynos->clk);
return 0; return 0;
} }
@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
MODULE_DEVICE_TABLE(of, exynos_dwc3_match); MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
#endif #endif
#ifdef CONFIG_PM_SLEEP
static int dwc3_exynos_suspend(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
clk_disable(exynos->clk);
return 0;
}
static int dwc3_exynos_resume(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
clk_enable(exynos->clk);
/* runtime set active to reflect active state. */
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
}
static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
};
#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static struct platform_driver dwc3_exynos_driver = { static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe, .probe = dwc3_exynos_probe,
.remove = dwc3_exynos_remove, .remove = dwc3_exynos_remove,
.driver = { .driver = {
.name = "exynos-dwc3", .name = "exynos-dwc3",
.of_match_table = of_match_ptr(exynos_dwc3_match), .of_match_table = of_match_ptr(exynos_dwc3_match),
.pm = DEV_PM_OPS,
}, },
}; };

View File

@ -52,7 +52,6 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
/* /*
* All these registers belong to OMAP's Wrapper around the * All these registers belong to OMAP's Wrapper around the
@ -117,20 +116,17 @@ struct dwc3_omap {
/* device lock */ /* device lock */
spinlock_t lock; spinlock_t lock;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev; struct device *dev;
int irq; int irq;
void __iomem *base; void __iomem *base;
void *context; u32 utmi_otg_status;
u32 resource_size;
u32 dma_status:1; u32 dma_status:1;
}; };
struct dwc3_omap *_omap; static struct dwc3_omap *_omap;
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{ {
@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
writel(value, base + offset); writel(value, base + offset);
} }
void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{ {
u32 val; u32 val;
struct dwc3_omap *omap = _omap; struct dwc3_omap *omap = _omap;
if (!omap)
return -EPROBE_DEFER;
switch (status) { switch (status) {
case OMAP_DWC3_ID_GROUND: case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n"); dev_dbg(omap->dev, "ID GND\n");
@ -189,64 +188,10 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
dev_dbg(omap->dev, "ID float\n"); dev_dbg(omap->dev, "ID float\n");
} }
return; return 0;
} }
EXPORT_SYMBOL_GPL(dwc3_omap_mailbox); EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
static int dwc3_omap_register_phys(struct dwc3_omap *omap)
{
struct nop_usb_xceiv_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
omap->usb2_phy = pdev;
pdata.type = USB_PHY_TYPE_USB2;
ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
if (ret)
goto err1;
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
}
omap->usb3_phy = pdev;
pdata.type = USB_PHY_TYPE_USB3;
ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
if (ret)
goto err2;
ret = platform_device_add(omap->usb2_phy);
if (ret)
goto err2;
ret = platform_device_add(omap->usb3_phy);
if (ret)
goto err3;
return 0;
err3:
platform_device_del(omap->usb2_phy);
err2:
platform_device_put(omap->usb3_phy);
err1:
platform_device_put(omap->usb2_phy);
return ret;
}
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{ {
struct dwc3_omap *omap = _omap; struct dwc3_omap *omap = _omap;
@ -307,121 +252,10 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
return 0; return 0;
} }
static int dwc3_omap_probe(struct platform_device *pdev) static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{ {
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
int size;
int ret = -ENOMEM;
int irq;
const u32 *utmi_mode;
u32 reg; u32 reg;
void __iomem *base;
void *context;
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, omap);
irq = platform_get_irq(pdev, 1);
if (irq < 0) {
dev_err(dev, "missing IRQ resource\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(dev, "missing memory base resource\n");
return -EINVAL;
}
base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!base) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
ret = dwc3_omap_register_phys(omap);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
return ret;
}
context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
if (!context) {
dev_err(dev, "couldn't allocate dwc3 context memory\n");
return -ENOMEM;
}
spin_lock_init(&omap->lock);
omap->resource_size = resource_size(res);
omap->context = context;
omap->dev = dev;
omap->irq = irq;
omap->base = base;
/*
* 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);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
reg |= *utmi_mode;
} else {
if (!pdata) {
dev_dbg(dev, "missing platform data\n");
} else {
switch (pdata->utmi_mode) {
case DWC3_OMAP_UTMI_MODE_SW:
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
case DWC3_OMAP_UTMI_MODE_HW:
reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
default:
dev_dbg(dev, "UNKNOWN utmi mode %d\n",
pdata->utmi_mode);
}
}
}
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
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);
return ret;
}
/* enable all IRQs */ /* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST; reg = USBOTGSS_IRQO_COREIRQ_ST;
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
@ -437,14 +271,120 @@ static int dwc3_omap_probe(struct platform_device *pdev)
USBOTGSS_IRQ1_IDPULLUP_FALL); USBOTGSS_IRQ1_IDPULLUP_FALL);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
}
if (node) { static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
ret = of_platform_populate(node, NULL, NULL, dev); {
if (ret) { /* disable all IRQs */
dev_err(&pdev->dev, dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
"failed to add create dwc3 core\n"); dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
return ret; }
}
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
static int dwc3_omap_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
int irq;
int utmi_mode = 0;
u32 reg;
void __iomem *base;
if (!node) {
dev_err(dev, "device node not found\n");
return -EINVAL;
}
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, omap);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "missing IRQ resource\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory base resource\n");
return -EINVAL;
}
base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!base) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
spin_lock_init(&omap->lock);
omap->dev = dev;
omap->irq = irq;
omap->base = base;
dev->dma_mask = &dwc3_omap_dma_mask;
/*
* 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);
of_property_read_u32(node, "utmi-mode", &utmi_mode);
switch (utmi_mode) {
case DWC3_OMAP_UTMI_MODE_SW:
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
case DWC3_OMAP_UTMI_MODE_HW:
reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
default:
dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
}
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
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);
return ret;
}
dwc3_omap_enable_irqs(omap);
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(&pdev->dev, "failed to create dwc3 core\n");
return ret;
} }
return 0; return 0;
@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{ {
struct dwc3_omap *omap = platform_get_drvdata(pdev); struct dwc3_omap *omap = platform_get_drvdata(pdev);
platform_device_unregister(omap->usb2_phy); dwc3_omap_disable_irqs(omap);
platform_device_unregister(omap->usb3_phy);
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core); device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev)
static const struct of_device_id of_dwc3_match[] = { static const struct of_device_id of_dwc3_match[] = {
{ {
"ti,dwc3", .compatible = "ti,dwc3"
}, },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, of_dwc3_match); MODULE_DEVICE_TABLE(of, of_dwc3_match);
#ifdef CONFIG_PM_SLEEP
static int dwc3_omap_prepare(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
dwc3_omap_disable_irqs(omap);
return 0;
}
static void dwc3_omap_complete(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
dwc3_omap_enable_irqs(omap);
}
static int dwc3_omap_suspend(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
omap->utmi_otg_status = dwc3_omap_readl(omap->base,
USBOTGSS_UTMI_OTG_STATUS);
return 0;
}
static int dwc3_omap_resume(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
omap->utmi_otg_status);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
}
static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
.prepare = dwc3_omap_prepare,
.complete = dwc3_omap_complete,
SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
};
#define DEV_PM_OPS (&dwc3_omap_dev_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static struct platform_driver dwc3_omap_driver = { static struct platform_driver dwc3_omap_driver = {
.probe = dwc3_omap_probe, .probe = dwc3_omap_probe,
.remove = dwc3_omap_remove, .remove = dwc3_omap_remove,
.driver = { .driver = {
.name = "omap-dwc3", .name = "omap-dwc3",
.of_match_table = of_dwc3_match, .of_match_table = of_dwc3_match,
.pm = DEV_PM_OPS,
}, },
}; };

View File

@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
}; };
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
#ifdef CONFIG_PM
static int dwc3_pci_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
pci_disable_device(pci);
return 0;
}
static int dwc3_pci_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
int ret;
ret = pci_enable_device(pci);
if (ret) {
dev_err(dev, "can't re-enable device --> %d\n", ret);
return ret;
}
pci_set_master(pci);
return 0;
}
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
};
#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static struct pci_driver dwc3_pci_driver = { static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci", .name = "dwc3-pci",
.id_table = dwc3_pci_id_table, .id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe, .probe = dwc3_pci_probe,
.remove = dwc3_pci_remove, .remove = dwc3_pci_remove,
.driver = {
.pm = DEV_PM_OPS,
},
}; };
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");

View File

@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 wIndex; u32 wIndex;
u32 reg; u32 reg;
int ret; int ret;
enum usb_device_state state;
wValue = le16_to_cpu(ctrl->wValue); wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex); wIndex = le16_to_cpu(ctrl->wIndex);
recip = ctrl->bRequestType & USB_RECIP_MASK; recip = ctrl->bRequestType & USB_RECIP_MASK;
state = dwc->gadget.state;
switch (recip) { switch (recip) {
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
* default control pipe * default control pipe
*/ */
case USB_DEVICE_U1_ENABLE: case USB_DEVICE_U1_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE) if (state != USB_STATE_CONFIGURED)
return -EINVAL; return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED) if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL; return -EINVAL;
@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
break; break;
case USB_DEVICE_U2_ENABLE: case USB_DEVICE_U2_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE) if (state != USB_STATE_CONFIGURED)
return -EINVAL; return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED) if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL; return -EINVAL;
@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{ {
enum usb_device_state state = dwc->gadget.state;
u32 addr; u32 addr;
u32 reg; u32 reg;
@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return -EINVAL; return -EINVAL;
} }
if (dwc->dev_state == DWC3_CONFIGURED_STATE) { if (state == USB_STATE_CONFIGURED) {
dev_dbg(dwc->dev, "trying to set address when configured\n"); dev_dbg(dwc->dev, "trying to set address when configured\n");
return -EINVAL; return -EINVAL;
} }
@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc3_writel(dwc->regs, DWC3_DCFG, reg);
if (addr) if (addr)
dwc->dev_state = DWC3_ADDRESS_STATE; usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
else else
dwc->dev_state = DWC3_DEFAULT_STATE; usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
return 0; return 0;
} }
@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{ {
enum usb_device_state state = dwc->gadget.state;
u32 cfg; u32 cfg;
int ret; int ret;
u32 reg; u32 reg;
@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc->start_config_issued = false; dwc->start_config_issued = false;
cfg = le16_to_cpu(ctrl->wValue); cfg = le16_to_cpu(ctrl->wValue);
switch (dwc->dev_state) { switch (state) {
case DWC3_DEFAULT_STATE: case USB_STATE_DEFAULT:
return -EINVAL; return -EINVAL;
break; break;
case DWC3_ADDRESS_STATE: case USB_STATE_ADDRESS:
ret = dwc3_ep0_delegate_req(dwc, ctrl); ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */ /* if the cfg matches and the cfg is non zero */
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
dwc->dev_state = DWC3_CONFIGURED_STATE; usb_gadget_set_state(&dwc->gadget,
USB_STATE_CONFIGURED);
/* /*
* Enable transition to U1/U2 state when * Enable transition to U1/U2 state when
* nothing is pending from application. * nothing is pending from application.
@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
} }
break; break;
case DWC3_CONFIGURED_STATE: case USB_STATE_CONFIGURED:
ret = dwc3_ep0_delegate_req(dwc, ctrl); ret = dwc3_ep0_delegate_req(dwc, ctrl);
if (!cfg) if (!cfg)
dwc->dev_state = DWC3_ADDRESS_STATE; usb_gadget_set_state(&dwc->gadget,
USB_STATE_ADDRESS);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep;
enum usb_device_state state = dwc->gadget.state;
u16 wLength; u16 wLength;
u16 wValue; u16 wValue;
if (dwc->dev_state == DWC3_DEFAULT_STATE) if (state == USB_STATE_DEFAULT)
return -EINVAL; return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue); wValue = le16_to_cpu(ctrl->wValue);

View File

@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
if (dwc->revision >= DWC3_REVISION_194A) if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT; reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP; reg |= DWC3_DCTL_RUN_STOP;
dwc->pullups_connected = true;
} else { } else {
reg &= ~DWC3_DCTL_RUN_STOP; reg &= ~DWC3_DCTL_RUN_STOP;
dwc->pullups_connected = false;
} }
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return ret; return ret;
} }
static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
{
u32 reg;
/* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN |
DWC3_DEVTEN_CMDCMPLTEN |
DWC3_DEVTEN_ERRTICERREN |
DWC3_DEVTEN_WKUPEVTEN |
DWC3_DEVTEN_ULSTCNGEN |
DWC3_DEVTEN_CONNECTDONEEN |
DWC3_DEVTEN_USBRSTEN |
DWC3_DEVTEN_DISCONNEVTEN);
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
}
static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
{
/* mask all interrupts */
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
static int dwc3_gadget_start(struct usb_gadget *g, static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver) struct usb_gadget_driver *driver)
{ {
@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
struct dwc3_ep *dep; struct dwc3_ep *dep;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
int irq;
u32 reg; u32 reg;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
} }
dwc->gadget_driver = driver; dwc->gadget_driver = driver;
dwc->gadget.dev.driver = &driver->driver;
reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK); reg &= ~(DWC3_DCFG_SPEED_MASK);
@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->ep0state = EP0_SETUP_PHASE; dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc); dwc3_ep0_out_start(dwc);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
goto err1;
}
dwc3_gadget_enable_irq(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
return 0; return 0;
@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
{ {
struct dwc3 *dwc = gadget_to_dwc(g); struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags; unsigned long flags;
int irq;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_disable_irq(dwc);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
free_irq(irq, dwc);
__dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]); __dwc3_gadget_ep_disable(dwc->eps[1]);
dwc->gadget_driver = NULL; dwc->gadget_driver = NULL;
dwc->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
u8 num, u32 direction)
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep;
u8 epnum; u8 i;
INIT_LIST_HEAD(&dwc->gadget.ep_list); for (i = 0; i < num; i++) {
u8 epnum = (i << 1) | (!!direction);
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = kzalloc(sizeof(*dep), GFP_KERNEL); dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep) { if (!dep) {
dev_err(dwc->dev, "can't allocate endpoint %d\n", dev_err(dwc->dev, "can't allocate endpoint %d\n",
@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
(epnum & 1) ? "in" : "out"); (epnum & 1) ? "in" : "out");
dep->endpoint.name = dep->name; dep->endpoint.name = dep->name;
dep->direction = (epnum & 1); dep->direction = (epnum & 1);
@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
return 0; return 0;
} }
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
{
int ret;
INIT_LIST_HEAD(&dwc->gadget.ep_list);
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
return ret;
}
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
return ret;
}
return 0;
}
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep;
@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_free_trb_pool(dep); dwc3_free_trb_pool(dep);
if (epnum != 0 && epnum != 1) if (epnum != 0 && epnum != 1)
@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
} }
} }
static void dwc3_gadget_release(struct device *dev)
{
dev_dbg(dev, "%s\n", __func__);
}
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
struct dwc3_request *req, struct dwc3_trb *trb, struct dwc3_request *req, struct dwc3_trb *trb,
const struct dwc3_event_depevt *event, int status) const struct dwc3_event_depevt *event, int status)
@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
struct dwc3_ep *dep; struct dwc3_ep *dep;
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_ENABLED)) if (!(dep->flags & DWC3_EP_ENABLED))
continue; continue;
@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
int ret; int ret;
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_STALL)) if (!(dep->flags & DWC3_EP_STALL))
continue; continue;
@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
} }
/* after reset -> Default State */ /* after reset -> Default State */
dwc->dev_state = DWC3_DEFAULT_STATE; usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
/* Recent versions support automatic phy suspend and don't need this */ /* Recent versions support automatic phy suspend and don't need this */
if (dwc->revision < DWC3_REVISION_194A) { if (dwc->revision < DWC3_REVISION_194A) {
@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo) unsigned int evtinfo)
{ {
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
unsigned int pwropt;
/*
* WORKAROUND: DWC3 < 2.50a have an issue when configured without
* Hibernation mode enabled which would show up when device detects
* host-initiated U3 exit.
*
* In that case, device will generate a Link State Change Interrupt
* from U3 to RESUME which is only necessary if Hibernation is
* configured in.
*
* There are no functional changes due to such spurious event and we
* just need to ignore it.
*
* Refers to:
*
* STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
* operational mode
*/
pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
if ((dwc->revision < DWC3_REVISION_250A) &&
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
return;
}
}
/* /*
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
} }
} }
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
{
struct dwc3 *dwc = _dwc;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
int i;
spin_lock_irqsave(&dwc->lock, flags);
for (i = 0; i < dwc->num_event_buffers; i++) {
struct dwc3_event_buffer *evt;
int left;
evt = dwc->ev_buffs[i];
left = evt->count;
if (!(evt->flags & DWC3_EVENT_PENDING))
continue;
while (left > 0) {
union dwc3_event event;
event.raw = *(u32 *) (evt->buf + evt->lpos);
dwc3_process_event_entry(dwc, &event);
/*
* FIXME we wrap around correctly to the next entry as
* almost all entries are 4 bytes in size. There is one
* entry which has 12 bytes which is a regular entry
* followed by 8 bytes data. ATM I don't know how
* things are organized if we get next to the a
* boundary so I worry about that once we try to handle
* that.
*/
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
}
evt->count = 0;
evt->flags &= ~DWC3_EVENT_PENDING;
ret = IRQ_HANDLED;
}
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
int left;
u32 count; u32 count;
evt = dwc->ev_buffs[buf];
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count &= DWC3_GEVNTCOUNT_MASK; count &= DWC3_GEVNTCOUNT_MASK;
if (!count) if (!count)
return IRQ_NONE; return IRQ_NONE;
evt = dwc->ev_buffs[buf]; evt->count = count;
left = count; evt->flags |= DWC3_EVENT_PENDING;
while (left > 0) { return IRQ_WAKE_THREAD;
union dwc3_event event;
event.raw = *(u32 *) (evt->buf + evt->lpos);
dwc3_process_event_entry(dwc, &event);
/*
* XXX we wrap around correctly to the next entry as almost all
* entries are 4 bytes in size. There is one entry which has 12
* bytes which is a regular entry followed by 8 bytes data. ATM
* I don't know how things are organized if were get next to the
* a boundary so I worry about that once we try to handle that.
*/
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
}
return IRQ_HANDLED;
} }
static irqreturn_t dwc3_interrupt(int irq, void *_dwc) static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
irqreturn_t status; irqreturn_t status;
status = dwc3_process_event_buf(dwc, i); status = dwc3_process_event_buf(dwc, i);
if (status == IRQ_HANDLED) if (status == IRQ_WAKE_THREAD)
ret = status; ret = status;
} }
@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{ {
u32 reg; u32 reg;
int ret; int ret;
int irq;
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
&dwc->ctrl_req_addr, GFP_KERNEL); &dwc->ctrl_req_addr, GFP_KERNEL);
@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3; goto err3;
} }
dev_set_name(&dwc->gadget.dev, "gadget");
dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER; dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.dev.parent = dwc->dev;
dwc->gadget.sg_supported = true; dwc->gadget.sg_supported = true;
dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
dwc->gadget.dev.release = dwc3_gadget_release;
dwc->gadget.name = "dwc3-gadget"; dwc->gadget.name = "dwc3-gadget";
/* /*
@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret) if (ret)
goto err4; goto err4;
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
"dwc3", dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
goto err5;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP; reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc3_writel(dwc->regs, DWC3_DCFG, reg);
/* Enable all but Start and End of Frame IRQs */ /* Enable USB2 LPM and automatic phy suspend only on recent versions */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN |
DWC3_DEVTEN_CMDCMPLTEN |
DWC3_DEVTEN_ERRTICERREN |
DWC3_DEVTEN_WKUPEVTEN |
DWC3_DEVTEN_ULSTCNGEN |
DWC3_DEVTEN_CONNECTDONEEN |
DWC3_DEVTEN_USBRSTEN |
DWC3_DEVTEN_DISCONNEVTEN);
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
/* automatic phy suspend only on recent versions */
if (dwc->revision >= DWC3_REVISION_194A) { if (dwc->revision >= DWC3_REVISION_194A) {
dwc3_gadget_usb2_phy_suspend(dwc, false); dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_gadget_usb3_phy_suspend(dwc, false);
} }
ret = device_register(&dwc->gadget.dev);
if (ret) {
dev_err(dwc->dev, "failed to register gadget device\n");
put_device(&dwc->gadget.dev);
goto err6;
}
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) { if (ret) {
dev_err(dwc->dev, "failed to register udc\n"); dev_err(dwc->dev, "failed to register udc\n");
goto err7; goto err5;
} }
return 0; return 0;
err7:
device_unregister(&dwc->gadget.dev);
err6:
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
free_irq(irq, dwc);
err5: err5:
dwc3_gadget_free_endpoints(dwc); dwc3_gadget_free_endpoints(dwc);
@ -2588,15 +2674,11 @@ int dwc3_gadget_init(struct dwc3 *dwc)
return ret; return ret;
} }
/* -------------------------------------------------------------------------- */
void dwc3_gadget_exit(struct dwc3 *dwc) void dwc3_gadget_exit(struct dwc3 *dwc)
{ {
int irq;
usb_del_gadget_udc(&dwc->gadget); usb_del_gadget_udc(&dwc->gadget);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
free_irq(irq, dwc);
dwc3_gadget_free_endpoints(dwc); dwc3_gadget_free_endpoints(dwc);
@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
dwc->ctrl_req, dwc->ctrl_req_addr); dwc->ctrl_req, dwc->ctrl_req_addr);
}
device_unregister(&dwc->gadget.dev);
int dwc3_gadget_prepare(struct dwc3 *dwc)
{
if (dwc->pullups_connected)
dwc3_gadget_disable_irq(dwc);
return 0;
}
void dwc3_gadget_complete(struct dwc3 *dwc)
{
if (dwc->pullups_connected) {
dwc3_gadget_enable_irq(dwc);
dwc3_gadget_run_stop(dwc, true);
}
}
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
return 0;
}
int dwc3_gadget_resume(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int ret;
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret)
goto err0;
dep = dwc->eps[1];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret)
goto err1;
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
return 0;
err1:
__dwc3_gadget_ep_disable(dwc->eps[0]);
err0:
return ret;
} }

View File

@ -196,7 +196,6 @@ config USB_OMAP
tristate "OMAP USB Device Controller" tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1 depends on ARCH_OMAP1
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
select USB_OTG_UTILS if ARCH_OMAP
help help
Many Texas Instruments OMAP processors have flexible full Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30 speed USB device controllers, with support for up to 30
@ -211,7 +210,6 @@ config USB_OMAP
config USB_PXA25X config USB_PXA25X
tristate "PXA 25x or IXP 4xx" tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
select USB_OTG_UTILS
help help
Intel's PXA 25x series XScale ARM-5TE processors include Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The an integrated full speed USB 1.1 device controller. The
@ -259,8 +257,6 @@ config USB_RENESAS_USBHS_UDC
config USB_PXA27X config USB_PXA27X
tristate "PXA 27x" tristate "PXA 27x"
depends on ARCH_PXA && (PXA27x || PXA3xx)
select USB_OTG_UTILS
help help
Intel's PXA 27x series XScale ARM v5TE processors include Intel's PXA 27x series XScale ARM v5TE processors include
an integrated full speed USB 1.1 device controller. an integrated full speed USB 1.1 device controller.
@ -329,9 +325,6 @@ config USB_MV_UDC
config USB_MV_U3D config USB_MV_U3D
tristate "MARVELL PXA2128 USB 3.0 controller" tristate "MARVELL PXA2128 USB 3.0 controller"
depends on CPU_MMP3
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
help help
MARVELL PXA2128 Processor series include a super speed USB3.0 device MARVELL PXA2128 Processor series include a super speed USB3.0 device
controller, which support super speed USB peripheral. controller, which support super speed USB peripheral.
@ -501,6 +494,7 @@ endmenu
# composite based drivers # composite based drivers
config USB_LIBCOMPOSITE config USB_LIBCOMPOSITE
tristate tristate
select CONFIGFS_FS
depends on USB_GADGET depends on USB_GADGET
config USB_F_ACM config USB_F_ACM
@ -512,6 +506,12 @@ config USB_F_SS_LB
config USB_U_SERIAL config USB_U_SERIAL
tristate tristate
config USB_F_SERIAL
tristate
config USB_F_OBEX
tristate
choice choice
tristate "USB Gadget Drivers" tristate "USB Gadget Drivers"
default USB_ETH default USB_ETH
@ -766,6 +766,8 @@ config USB_G_SERIAL
depends on TTY depends on TTY
select USB_U_SERIAL select USB_U_SERIAL
select USB_F_ACM select USB_F_ACM
select USB_F_SERIAL
select USB_F_OBEX
select USB_LIBCOMPOSITE select USB_LIBCOMPOSITE
help help
The Serial Gadget talks to the Linux-USB generic serial driver. The Serial Gadget talks to the Linux-USB generic serial driver.
@ -839,6 +841,7 @@ config USB_G_NOKIA
depends on PHONET depends on PHONET
select USB_LIBCOMPOSITE select USB_LIBCOMPOSITE
select USB_U_SERIAL select USB_U_SERIAL
select USB_F_ACM
help help
The Nokia composite gadget provides support for acm, obex The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver. and phonet in only one composite gadget driver.
@ -957,6 +960,7 @@ config USB_G_WEBCAM
tristate "USB Webcam Gadget" tristate "USB Webcam Gadget"
depends on VIDEO_DEV depends on VIDEO_DEV
select USB_LIBCOMPOSITE select USB_LIBCOMPOSITE
select VIDEOBUF2_VMALLOC
help help
The Webcam Gadget acts as a composite USB Audio and Video Class The Webcam Gadget acts as a composite USB Audio and Video Class
device. It provides a userspace API to process UVC control requests device. It provides a userspace API to process UVC control requests

View File

@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
libcomposite-y := usbstring.o config.o epautoconf.o libcomposite-y := usbstring.o config.o epautoconf.o
libcomposite-y += composite.o functions.o libcomposite-y += composite.o functions.o configfs.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_NET2280) += net2280.o
@ -36,10 +36,15 @@ obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
# USB Functions # USB Functions
obj-$(CONFIG_USB_F_ACM) += f_acm.o usb_f_acm-y := f_acm.o
f_ss_lb-y := f_loopback.o f_sourcesink.o obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o
obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o usb_f_ss_lb-y := f_loopback.o f_sourcesink.o
obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o
obj-$(CONFIG_USB_U_SERIAL) += u_serial.o obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
usb_f_serial-y := f_serial.o
obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
usb_f_obex-y := f_obex.o
obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
# #
# USB gadget drivers # USB gadget drivers

View File

@ -109,7 +109,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common fsg_common; static struct fsg_common fsg_common;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static unsigned char tty_line;
static struct usb_function *f_acm; static struct usb_function *f_acm;
static struct usb_function_instance *f_acm_inst; static struct usb_function_instance *f_acm_inst;
/* /*
@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst;
*/ */
static int __init acm_ms_do_config(struct usb_configuration *c) static int __init acm_ms_do_config(struct usb_configuration *c)
{ {
struct f_serial_opts *opts;
int status; int status;
if (gadget_is_otg(c->cdev->gadget)) { if (gadget_is_otg(c->cdev->gadget)) {
@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
if (IS_ERR(f_acm_inst)) if (IS_ERR(f_acm_inst))
return PTR_ERR(f_acm_inst); return PTR_ERR(f_acm_inst);
opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
opts->port_num = tty_line;
f_acm = usb_get_function(f_acm_inst); f_acm = usb_get_function(f_acm_inst);
if (IS_ERR(f_acm)) { if (IS_ERR(f_acm)) {
status = PTR_ERR(f_acm); status = PTR_ERR(f_acm);
@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
int status; int status;
void *retp; void *retp;
/* set up serial link layer */
status = gserial_alloc_line(&tty_line);
if (status < 0)
return status;
/* set up mass storage function */ /* set up mass storage function */
retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
if (IS_ERR(retp)) { if (IS_ERR(retp)) {
status = PTR_ERR(retp); status = PTR_ERR(retp);
goto fail0; return PTR_ERR(retp);
} }
/* /*
@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
/* error recovery */ /* error recovery */
fail1: fail1:
fsg_common_put(&fsg_common); fsg_common_put(&fsg_common);
fail0:
gserial_free_line(tty_line);
return status; return status;
} }
@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
{ {
usb_put_function(f_acm); usb_put_function(f_acm);
usb_put_function_instance(f_acm_inst); usb_put_function_instance(f_acm_inst);
gserial_free_line(tty_line);
return 0; return 0;
} }

View File

@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL; driver->driver.bus = NULL;
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
/* Some gadget drivers use both ep0 directions. /* Some gadget drivers use both ep0 directions.
* NOTE: to gadget driver, ep0 is just one endpoint... * NOTE: to gadget driver, ep0 is just one endpoint...
@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g,
shutdown(dev, driver); shutdown(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
/* set SD */ /* set SD */
@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
if (dev->active) if (dev->active)
pci_disable_device(pdev); pci_disable_device(pdev);
device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
udc_remove(dev); udc_remove(dev);
@ -3245,8 +3242,6 @@ static int udc_pci_probe(
dev->phys_addr = resource; dev->phys_addr = resource;
dev->irq = pdev->irq; dev->irq = pdev->irq;
dev->pdev = pdev; dev->pdev = pdev;
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
/* general probing */ /* general probing */
if (udc_probe(dev) == 0) if (udc_probe(dev) == 0)
@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.ops = &udc_ops; dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget"); dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.release = gadget_release;
dev->gadget.name = name; dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH; dev->gadget.max_speed = USB_SPEED_HIGH;
@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev)
"driver version: %s(for Geode5536 B1)\n", tmp); "driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev; udc = dev;
retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget); retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
gadget_release);
if (retval) if (retval)
goto finished; goto finished;
retval = device_register(&dev->gadget.dev);
if (retval) {
usb_del_gadget_udc(&dev->gadget);
put_device(&dev->gadget.dev);
goto finished;
}
/* timer init */ /* timer init */
init_timer(&udc_timer); init_timer(&udc_timer);
udc_timer.function = udc_timer_function; udc_timer.function = udc_timer_function;

View File

@ -472,7 +472,6 @@ struct udc_request {
/* flags */ /* flags */
unsigned dma_going : 1, unsigned dma_going : 1,
dma_mapping : 1,
dma_done : 1; dma_done : 1;
/* phys. address */ /* phys. address */
dma_addr_t td_phys; dma_addr_t td_phys;

View File

@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget,
udc = container_of(gadget, struct at91_udc, gadget); udc = container_of(gadget, struct at91_udc, gadget);
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node; udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1; udc->enabled = 1;
udc->selfpowered = 1; udc->selfpowered = 1;
@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget,
at91_udp_write(udc, AT91_UDP_IDR, ~0); at91_udp_write(udc, AT91_UDP_IDR, ~0);
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
DBG("unbound from %s\n", driver->driver.name); DBG("unbound from %s\n", driver->driver.name);
@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev)
DBG("clocks missing\n"); DBG("clocks missing\n");
retval = -ENODEV; retval = -ENODEV;
/* NOTE: we "know" here that refcounts on these are NOPs */ /* NOTE: we "know" here that refcounts on these are NOPs */
goto fail0b; goto fail1;
}
retval = device_register(&udc->gadget.dev);
if (retval < 0) {
put_device(&udc->gadget.dev);
goto fail0b;
} }
/* don't do anything until we have both gadget driver and VBUS */ /* don't do anything until we have both gadget driver and VBUS */
@ -1857,8 +1849,6 @@ static int at91udc_probe(struct platform_device *pdev)
fail2: fail2:
free_irq(udc->udp_irq, udc); free_irq(udc->udp_irq, udc);
fail1: fail1:
device_unregister(&udc->gadget.dev);
fail0b:
iounmap(udc->udp_baseaddr); iounmap(udc->udp_baseaddr);
fail0a: fail0a:
if (cpu_is_at91rm9200()) if (cpu_is_at91rm9200())
@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev)
gpio_free(udc->board.vbus_pin); gpio_free(udc->board.vbus_pin);
} }
free_irq(udc->udp_irq, udc); free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
iounmap(udc->udp_baseaddr); iounmap(udc->udp_baseaddr);
if (cpu_is_at91rm9200()) if (cpu_is_at91rm9200())

View File

@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
if (req->req.status == -EINPROGRESS) if (req->req.status == -EINPROGRESS)
req->req.status = status; req->req.status = status;
if (req->mapped) { if (req->using_dma)
dma_unmap_single( usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
&udc->pdev->dev, req->req.dma, req->req.length,
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
}
DBG(DBG_GADGET | DBG_REQ, DBG(DBG_GADGET | DBG_REQ,
"%s: req %p complete: status %d, actual %u\n", "%s: req %p complete: status %d, actual %u\n",
@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
return NULL; return NULL;
INIT_LIST_HEAD(&req->queue); INIT_LIST_HEAD(&req->queue);
req->req.dma = DMA_ADDR_INVALID;
return &req->req; return &req->req;
} }
@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
return -EINVAL; return -EINVAL;
} }
ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
if (ret)
return ret;
req->using_dma = 1; req->using_dma = 1;
if (req->req.dma == DMA_ADDR_INVALID) {
req->req.dma = dma_map_single(
&udc->pdev->dev, req->req.buf, req->req.length,
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
} else {
dma_sync_single_for_device(
&udc->pdev->dev, req->req.dma, req->req.length,
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 0;
}
req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
clk_enable(udc->pclk); clk_enable(udc->pclk);
@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
toggle_bias(0); toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK); usba_writel(udc, CTRL, USBA_DISABLE_MASK);
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
clk_disable(udc->hclk); clk_disable(udc->hclk);
@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
(unsigned long)fifo->start, udc->fifo); (unsigned long)fifo->start, udc->fifo);
device_initialize(&udc->gadget.dev);
udc->gadget.dev.parent = &pdev->dev;
udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
platform_set_drvdata(pdev, udc); platform_set_drvdata(pdev, udc);
/* Make sure we start from a clean slate */ /* Make sure we start from a clean slate */
@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
} }
udc->irq = irq; udc->irq = irq;
ret = device_add(&udc->gadget.dev);
if (ret) {
dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
goto err_device_add;
}
if (gpio_is_valid(pdata->vbus_pin)) { if (gpio_is_valid(pdata->vbus_pin)) {
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin; udc->vbus_pin = pdata->vbus_pin;
@ -2007,9 +1980,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
gpio_free(udc->vbus_pin); gpio_free(udc->vbus_pin);
} }
device_unregister(&udc->gadget.dev);
err_device_add:
free_irq(irq, udc); free_irq(irq, udc);
err_request_irq: err_request_irq:
kfree(usba_ep); kfree(usba_ep);
@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
clk_put(udc->hclk); clk_put(udc->hclk);
clk_put(udc->pclk); clk_put(udc->pclk);
device_unregister(&udc->gadget.dev);
return 0; return 0;
} }

View File

@ -216,12 +216,6 @@
#define EP0_EPT_SIZE USBA_EPT_SIZE_64 #define EP0_EPT_SIZE USBA_EPT_SIZE_64
#define EP0_NR_BANKS 1 #define EP0_NR_BANKS 1
/*
* REVISIT: Try to eliminate this value. Can we rely on req->mapped to
* provide this information?
*/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define FIFO_IOMEM_ID 0 #define FIFO_IOMEM_ID 0
#define CTRL_IOMEM_ID 1 #define CTRL_IOMEM_ID 1

View File

@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
udc->driver = driver; udc->driver = driver;
driver->driver.bus = NULL; driver->driver.bus = NULL;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node; udc->gadget.dev.of_node = udc->dev->of_node;
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&udc->lock, flags); spin_lock_irqsave(&udc->lock, flags);
udc->driver = NULL; udc->driver = NULL;
udc->gadget.dev.driver = NULL;
/* /*
* If we switch the PHY too abruptly after dropping D+, the host * If we switch the PHY too abruptly after dropping D+, the host
@ -2305,17 +2303,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
* Driver init/exit * Driver init/exit
***********************************************************************/ ***********************************************************************/
/**
* bcm63xx_udc_gadget_release - Called from device_release().
* @dev: Unused.
*
* We get a warning if this function doesn't exist, but it's empty because
* we don't have to free any of the memory allocated with the devm_* APIs.
*/
static void bcm63xx_udc_gadget_release(struct device *dev)
{
}
/** /**
* bcm63xx_udc_probe - Initialize a new instance of the UDC. * bcm63xx_udc_probe - Initialize a new instance of the UDC.
* @pdev: Platform device struct from the bcm63xx BSP code. * @pdev: Platform device struct from the bcm63xx BSP code.
@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
spin_lock_init(&udc->lock); spin_lock_init(&udc->lock);
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process); INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.ops = &bcm63xx_udc_ops; udc->gadget.ops = &bcm63xx_udc_ops;
udc->gadget.name = dev_name(dev); udc->gadget.name = dev_name(dev);
udc->gadget.dev.parent = dev;
udc->gadget.dev.release = bcm63xx_udc_gadget_release;
udc->gadget.dev.dma_mask = dev->dma_mask;
if (!pd->use_fullspeed && !use_fullspeed) if (!pd->use_fullspeed && !use_fullspeed)
udc->gadget.max_speed = USB_SPEED_HIGH; udc->gadget.max_speed = USB_SPEED_HIGH;
@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
} }
} }
rc = device_register(&udc->gadget.dev);
if (rc)
goto out_uninit;
bcm63xx_udc_init_debugfs(udc); bcm63xx_udc_init_debugfs(udc);
rc = usb_add_gadget_udc(dev, &udc->gadget); rc = usb_add_gadget_udc(dev, &udc->gadget);
if (!rc) if (!rc)
return 0; return 0;
bcm63xx_udc_cleanup_debugfs(udc); bcm63xx_udc_cleanup_debugfs(udc);
device_unregister(&udc->gadget.dev);
out_uninit: out_uninit:
bcm63xx_uninit_udc_hw(udc); bcm63xx_uninit_udc_hw(udc);
return rc; return rc;
@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
bcm63xx_udc_cleanup_debugfs(udc); bcm63xx_udc_cleanup_debugfs(udc);
usb_del_gadget_udc(&udc->gadget); usb_del_gadget_udc(&udc->gadget);
device_unregister(&udc->gadget.dev);
BUG_ON(udc->driver); BUG_ON(udc->driver);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);

View File

@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = {
}; };
static u8 hostaddr[ETH_ALEN]; static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_function *f_acm; static struct usb_function *f_acm;
static struct usb_function_instance *fi_serial; static struct usb_function_instance *fi_serial;
static unsigned char tty_line;
/* /*
* We _always_ have both CDC ECM and CDC ACM functions. * We _always_ have both CDC ECM and CDC ACM functions.
*/ */
static int __init cdc_do_config(struct usb_configuration *c) static int __init cdc_do_config(struct usb_configuration *c)
{ {
struct f_serial_opts *opts;
int status; int status;
if (gadget_is_otg(c->cdev->gadget)) { if (gadget_is_otg(c->cdev->gadget)) {
@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
status = ecm_bind_config(c, hostaddr); status = ecm_bind_config(c, hostaddr, the_dev);
if (status < 0) if (status < 0)
return status; return status;
@ -130,9 +128,6 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (IS_ERR(fi_serial)) if (IS_ERR(fi_serial))
return PTR_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); f_acm = usb_get_function(fi_serial);
if (IS_ERR(f_acm)) if (IS_ERR(f_acm))
goto err_func_acm; goto err_func_acm;
@ -169,14 +164,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
} }
/* set up network link layer */ /* set up network link layer */
status = gether_setup(cdev->gadget, hostaddr); the_dev = gether_setup(cdev->gadget, hostaddr);
if (status < 0) if (IS_ERR(the_dev))
return status; return PTR_ERR(the_dev);
/* set up serial link layer */
status = gserial_alloc_line(&tty_line);
if (status < 0)
goto fail0;
/* Allocate string descriptor numbers ... note that string /* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue. * contents can be overridden by the composite_dev glue.
@ -200,9 +190,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0; return 0;
fail1: fail1:
gserial_free_line(tty_line); gether_cleanup(the_dev);
fail0:
gether_cleanup();
return status; return status;
} }
@ -210,8 +198,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
{ {
usb_put_function(f_acm); usb_put_function(f_acm);
usb_put_function_instance(fi_serial); usb_put_function_instance(fi_serial);
gserial_free_line(tty_line); gether_cleanup(the_dev);
gether_cleanup();
return 0; return 0;
} }

View File

@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
kfree(cdev->req->buf); kfree(cdev->req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->req); usb_ep_free_request(cdev->gadget->ep0, cdev->req);
} }
cdev->next_string_id = 0;
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
} }

File diff suppressed because it is too large Load Diff

View File

@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
dum->devstatus = 0; dum->devstatus = 0;
dum->driver = driver; dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n", dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name); driver->driver.name);
return 0; return 0;
@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
driver->driver.name); driver->driver.name);
dum->gadget.dev.driver = NULL;
dum->driver = NULL; dum->driver = NULL;
return 0; return 0;
@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
/* The gadget structure is stored inside the hcd structure and will be /* The gadget structure is stored inside the hcd structure and will be
* released along with it. */ * released along with it. */
static void dummy_gadget_release(struct device *dev)
{
return;
}
static void init_dummy_udc_hw(struct dummy *dum) static void init_dummy_udc_hw(struct dummy *dum)
{ {
int i; int i;
@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
dum->gadget.ops = &dummy_ops; dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER; dum->gadget.max_speed = USB_SPEED_SUPER;
dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev; dum->gadget.dev.parent = &pdev->dev;
dum->gadget.dev.release = dummy_gadget_release;
rc = device_register(&dum->gadget.dev);
if (rc < 0) {
put_device(&dum->gadget.dev);
return rc;
}
init_dummy_udc_hw(dum); init_dummy_udc_hw(dum);
rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
err_dev: err_dev:
usb_del_gadget_udc(&dum->gadget); usb_del_gadget_udc(&dum->gadget);
err_udc: err_udc:
device_unregister(&dum->gadget.dev);
return rc; return rc;
} }
@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&dum->gadget); usb_del_gadget_udc(&dum->gadget);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
device_remove_file(&dum->gadget.dev, &dev_attr_function); device_remove_file(&dum->gadget.dev, &dev_attr_function);
device_unregister(&dum->gadget.dev);
return 0; return 0;
} }
@ -1923,7 +1906,7 @@ static int dummy_hub_status(struct usb_hcd *hcd, char *buf)
} }
/* usb 3.0 root hub device descriptor */ /* usb 3.0 root hub device descriptor */
struct { static struct {
struct usb_bos_descriptor bos; struct usb_bos_descriptor bos;
struct usb_ss_cap_descriptor ss_cap; struct usb_ss_cap_descriptor ss_cap;
} __packed usb3_bos_desc = { } __packed usb3_bos_desc = {

View File

@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = {
}; };
static u8 hostaddr[ETH_ALEN]; static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* /*
@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
return rndis_bind_config(c, hostaddr); return rndis_bind_config(c, hostaddr, the_dev);
} }
static struct usb_configuration rndis_config_driver = { static struct usb_configuration rndis_config_driver = {
@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c)
} }
if (use_eem) if (use_eem)
return eem_bind_config(c); return eem_bind_config(c, the_dev);
else if (can_support_ecm(c->cdev->gadget)) else if (can_support_ecm(c->cdev->gadget))
return ecm_bind_config(c, hostaddr); return ecm_bind_config(c, hostaddr, the_dev);
else else
return geth_bind_config(c, hostaddr); return geth_bind_config(c, hostaddr, the_dev);
} }
static struct usb_configuration eth_config_driver = { static struct usb_configuration eth_config_driver = {
@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
int status; int status;
/* set up network link layer */ /* set up network link layer */
status = gether_setup(cdev->gadget, hostaddr); the_dev = gether_setup(cdev->gadget, hostaddr);
if (status < 0) if (IS_ERR(the_dev))
return status; return PTR_ERR(the_dev);
/* set up main config label and device descriptor */ /* set up main config label and device descriptor */
if (use_eem) { if (use_eem) {
@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return 0; return 0;
fail: fail:
gether_cleanup(); gether_cleanup(the_dev);
return status; return status;
} }
static int __exit eth_unbind(struct usb_composite_dev *cdev) static int __exit eth_unbind(struct usb_composite_dev *cdev)
{ {
gether_cleanup(); gether_cleanup(the_dev);
return 0; return 0;
} }

View File

@ -715,72 +715,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
return status; return status;
} }
static struct f_acm *acm_alloc_basic_func(void)
{
struct f_acm *acm;
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm)
return NULL;
spin_lock_init(&acm->lock);
acm->port.connect = acm_connect;
acm->port.disconnect = acm_disconnect;
acm->port.send_break = acm_send_break;
acm->port.func.name = "acm";
/* descriptors are per-instance copies */
acm->port.func.bind = acm_bind;
acm->port.func.set_alt = acm_set_alt;
acm->port.func.setup = acm_setup;
acm->port.func.disable = acm_disable;
return acm;
}
#ifdef USB_FACM_INCLUDED
static void
acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_acm *acm = func_to_acm(f);
usb_free_all_descriptors(f);
if (acm->notify_req)
gs_free_req(acm->notify, acm->notify_req);
kfree(acm);
}
/**
* acm_bind_config - add a CDC ACM function to a configuration
* @c: the configuration to support the CDC ACM instance
* @port_num: /dev/ttyGS* port this interface will use
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*
*/
int acm_bind_config(struct usb_configuration *c, u8 port_num)
{
struct f_acm *acm;
int status;
/* allocate and initialize one new instance */
acm = acm_alloc_basic_func();
if (!acm)
return -ENOMEM;
acm->port_num = port_num;
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) static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
{ {
struct f_acm *acm = func_to_acm(f); struct f_acm *acm = func_to_acm(f);
@ -803,10 +737,24 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
struct f_serial_opts *opts; struct f_serial_opts *opts;
struct f_acm *acm; struct f_acm *acm;
acm = acm_alloc_basic_func(); acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm) if (!acm)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
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";
acm->port.func.strings = acm_strings;
/* 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;
opts = container_of(fi, struct f_serial_opts, func_inst); opts = container_of(fi, struct f_serial_opts, func_inst);
acm->port_num = opts->port_num; acm->port_num = opts->port_num;
acm->port.func.unbind = acm_unbind; acm->port.func.unbind = acm_unbind;
@ -815,24 +763,85 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
return &acm->port.func; return &acm->port.func;
} }
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_serial_opts,
func_inst.group);
}
CONFIGFS_ATTR_STRUCT(f_serial_opts);
static ssize_t f_acm_attr_show(struct config_item *item,
struct configfs_attribute *attr,
char *page)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
struct f_serial_opts_attribute *f_serial_opts_attr =
container_of(attr, struct f_serial_opts_attribute, attr);
ssize_t ret = 0;
if (f_serial_opts_attr->show)
ret = f_serial_opts_attr->show(opts, page);
return ret;
}
static void acm_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations acm_item_ops = {
.release = acm_attr_release,
.show_attribute = f_acm_attr_show,
};
static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
{
return sprintf(page, "%u\n", opts->port_num);
}
static struct f_serial_opts_attribute f_acm_port_num =
__CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
static struct configfs_attribute *acm_attrs[] = {
&f_acm_port_num.attr,
NULL,
};
static struct config_item_type acm_func_type = {
.ct_item_ops = &acm_item_ops,
.ct_attrs = acm_attrs,
.ct_owner = THIS_MODULE,
};
static void acm_free_instance(struct usb_function_instance *fi) static void acm_free_instance(struct usb_function_instance *fi)
{ {
struct f_serial_opts *opts; struct f_serial_opts *opts;
opts = container_of(fi, struct f_serial_opts, func_inst); opts = container_of(fi, struct f_serial_opts, func_inst);
gserial_free_line(opts->port_num);
kfree(opts); kfree(opts);
} }
static struct usb_function_instance *acm_alloc_instance(void) static struct usb_function_instance *acm_alloc_instance(void)
{ {
struct f_serial_opts *opts; struct f_serial_opts *opts;
int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL); opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts) if (!opts)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = acm_free_instance; opts->func_inst.free_func_inst = acm_free_instance;
ret = gserial_alloc_line(&opts->port_num);
if (ret) {
kfree(opts);
return ERR_PTR(ret);
}
config_group_init_type_name(&opts->func_inst.group, "",
&acm_func_type);
return &opts->func_inst; return &opts->func_inst;
} }
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#endif

View File

@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
* for calling @gether_cleanup() before module unload. * for calling @gether_cleanup() before module unload.
*/ */
int int
ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev)
{ {
struct f_ecm *ecm; struct f_ecm *ecm;
int status; int status;
@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr); snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
ecm_string_defs[1].s = ecm->ethaddr; ecm_string_defs[1].s = ecm->ethaddr;
ecm->port.ioport = dev;
ecm->port.cdc_filter = DEFAULT_FILTER; ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet"; ecm->port.func.name = "cdc_ethernet";

View File

@ -528,7 +528,7 @@ static int eem_unwrap(struct gether *port,
* Caller must have called @gether_setup(). Caller is also responsible * Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload. * for calling @gether_cleanup() before module unload.
*/ */
int __init eem_bind_config(struct usb_configuration *c) int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
{ {
struct f_eem *eem; struct f_eem *eem;
int status; int status;
@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
if (!eem) if (!eem)
return -ENOMEM; return -ENOMEM;
eem->port.ioport = dev;
eem->port.cdc_filter = DEFAULT_FILTER; eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem"; eem->port.func.name = "cdc_eem";

View File

@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible * Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload. * for calling @gether_cleanup() before module unload.
*/ */
int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev)
{ {
struct f_ncm *ncm; struct f_ncm *ncm;
int status; int status;
@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
spin_lock_init(&ncm->lock); spin_lock_init(&ncm->lock);
ncm_reset_values(ncm); ncm_reset_values(ncm);
ncm->port.ioport = dev;
ncm->port.is_fixed = true; ncm->port.is_fixed = true;
ncm->port.func.name = "cdc_network"; ncm->port.func.name = "cdc_network";

View File

@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_interface_descriptor obex_control_intf __initdata = { static struct usb_interface_descriptor obex_control_intf = {
.bLength = sizeof(obex_control_intf), .bLength = sizeof(obex_control_intf),
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
.bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX,
}; };
static struct usb_interface_descriptor obex_data_nop_intf __initdata = { static struct usb_interface_descriptor obex_data_nop_intf = {
.bLength = sizeof(obex_data_nop_intf), .bLength = sizeof(obex_data_nop_intf),
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1, .bInterfaceNumber = 1,
@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceClass = USB_CLASS_CDC_DATA,
}; };
static struct usb_interface_descriptor obex_data_intf __initdata = { static struct usb_interface_descriptor obex_data_intf = {
.bLength = sizeof(obex_data_intf), .bLength = sizeof(obex_data_intf),
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 2, .bInterfaceNumber = 2,
@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceClass = USB_CLASS_CDC_DATA,
}; };
static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = { static struct usb_cdc_header_desc obex_cdc_header_desc = {
.bLength = sizeof(obex_cdc_header_desc), .bLength = sizeof(obex_cdc_header_desc),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE, .bDescriptorSubType = USB_CDC_HEADER_TYPE,
.bcdCDC = cpu_to_le16(0x0120), .bcdCDC = cpu_to_le16(0x0120),
}; };
static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { static struct usb_cdc_union_desc obex_cdc_union_desc = {
.bLength = sizeof(obex_cdc_union_desc), .bLength = sizeof(obex_cdc_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE, .bDescriptorSubType = USB_CDC_UNION_TYPE,
@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
.bSlaveInterface0 = 2, .bSlaveInterface0 = 2,
}; };
static struct usb_cdc_obex_desc obex_desc __initdata = { static struct usb_cdc_obex_desc obex_desc = {
.bLength = sizeof(obex_desc), .bLength = sizeof(obex_desc),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_OBEX_TYPE, .bDescriptorSubType = USB_CDC_OBEX_TYPE,
@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
/* High-Speed Support */ /* High-Speed Support */
static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512), .wMaxPacketSize = cpu_to_le16(512),
}; };
static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512), .wMaxPacketSize = cpu_to_le16(512),
}; };
static struct usb_descriptor_header *hs_function[] __initdata = { static struct usb_descriptor_header *hs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf, (struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc, (struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc, (struct usb_descriptor_header *) &obex_desc,
@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
/* Full-Speed Support */ /* Full-Speed Support */
static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
}; };
static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
}; };
static struct usb_descriptor_header *fs_function[] __initdata = { static struct usb_descriptor_header *fs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf, (struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc, (struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc, (struct usb_descriptor_header *) &obex_desc,
@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int __init /* Some controllers can't support CDC OBEX ... */
obex_bind(struct usb_configuration *c, struct usb_function *f) static inline bool can_support_obex(struct usb_configuration *c)
{
/* Since the first interface is a NOP, we can ignore the
* issue of multi-interface support on most controllers.
*
* Altsettings are mandatory, however...
*/
if (!gadget_supports_altsettings(c->cdev->gadget))
return false;
/* everything else is *probably* fine ... */
return true;
}
static int obex_bind(struct usb_configuration *c, struct usb_function *f)
{ {
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct f_obex *obex = func_to_obex(f); struct f_obex *obex = func_to_obex(f);
int status; int status;
struct usb_ep *ep; struct usb_ep *ep;
if (!can_support_obex(c))
return -EINVAL;
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
status = usb_string_ids_tab(c->cdev, obex_string_defs);
if (status < 0)
return status;
obex_control_intf.iInterface =
obex_string_defs[OBEX_CTRL_IDX].id;
status = obex_string_defs[OBEX_DATA_IDX].id;
obex_data_nop_intf.iInterface = status;
obex_data_intf.iInterface = status;
}
/* allocate instance-specific interface IDs, and patch descriptors */ /* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f); status = usb_interface_id(c, f);
@ -376,29 +405,16 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
return status; return status;
} }
#ifdef USBF_OBEX_INCLUDED
static void static void
obex_unbind(struct usb_configuration *c, struct usb_function *f) obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
{ {
obex_string_defs[OBEX_CTRL_IDX].id = 0; obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f); usb_free_all_descriptors(f);
kfree(func_to_obex(f)); kfree(func_to_obex(f));
} }
/* Some controllers can't support CDC OBEX ... */
static inline bool can_support_obex(struct usb_configuration *c)
{
/* Since the first interface is a NOP, we can ignore the
* issue of multi-interface support on most controllers.
*
* Altsettings are mandatory, however...
*/
if (!gadget_supports_altsettings(c->cdev->gadget))
return false;
/* everything else is *probably* fine ... */
return true;
}
/** /**
* obex_bind_config - add a CDC OBEX function to a configuration * obex_bind_config - add a CDC OBEX function to a configuration
* @c: the configuration to support the CDC OBEX instance * @c: the configuration to support the CDC OBEX instance
@ -412,21 +428,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
struct f_obex *obex; struct f_obex *obex;
int status; int status;
if (!can_support_obex(c))
return -EINVAL;
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
status = usb_string_ids_tab(c->cdev, obex_string_defs);
if (status < 0)
return status;
obex_control_intf.iInterface =
obex_string_defs[OBEX_CTRL_IDX].id;
status = obex_string_defs[OBEX_DATA_IDX].id;
obex_data_nop_intf.iInterface = status;
obex_data_intf.iInterface = status;
}
/* allocate and initialize one new instance */ /* allocate and initialize one new instance */
obex = kzalloc(sizeof *obex, GFP_KERNEL); obex = kzalloc(sizeof *obex, GFP_KERNEL);
if (!obex) if (!obex)
@ -441,7 +442,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
obex->port.func.strings = obex_strings; obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */ /* descriptors are per-instance copies */
obex->port.func.bind = obex_bind; obex->port.func.bind = obex_bind;
obex->port.func.unbind = obex_unbind; obex->port.func.unbind = obex_old_unbind;
obex->port.func.set_alt = obex_set_alt; obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt; obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable; obex->port.func.disable = obex_disable;
@ -453,5 +454,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
return status; return status;
} }
#else
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_serial_opts,
func_inst.group);
}
CONFIGFS_ATTR_STRUCT(f_serial_opts);
static ssize_t f_obex_attr_show(struct config_item *item,
struct configfs_attribute *attr,
char *page)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
struct f_serial_opts_attribute *f_serial_opts_attr =
container_of(attr, struct f_serial_opts_attribute, attr);
ssize_t ret = 0;
if (f_serial_opts_attr->show)
ret = f_serial_opts_attr->show(opts, page);
return ret;
}
static void obex_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations obex_item_ops = {
.release = obex_attr_release,
.show_attribute = f_obex_attr_show,
};
static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
{
return sprintf(page, "%u\n", opts->port_num);
}
static struct f_serial_opts_attribute f_obex_port_num =
__CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
static struct configfs_attribute *acm_attrs[] = {
&f_obex_port_num.attr,
NULL,
};
static struct config_item_type obex_func_type = {
.ct_item_ops = &obex_item_ops,
.ct_attrs = acm_attrs,
.ct_owner = THIS_MODULE,
};
static void obex_free_inst(struct usb_function_instance *f)
{
struct f_serial_opts *opts;
opts = container_of(f, struct f_serial_opts, func_inst);
gserial_free_line(opts->port_num);
kfree(opts);
}
static struct usb_function_instance *obex_alloc_inst(void)
{
struct f_serial_opts *opts;
int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = obex_free_inst;
ret = gserial_alloc_line(&opts->port_num);
if (ret) {
kfree(opts);
return ERR_PTR(ret);
}
config_group_init_type_name(&opts->func_inst.group, "",
&obex_func_type);
return &opts->func_inst;
}
static void obex_free(struct usb_function *f)
{
struct f_obex *obex;
obex = func_to_obex(f);
kfree(obex);
}
static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
{
obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f);
}
struct usb_function *obex_alloc(struct usb_function_instance *fi)
{
struct f_obex *obex;
struct f_serial_opts *opts;
/* allocate and initialize one new instance */
obex = kzalloc(sizeof(*obex), GFP_KERNEL);
if (!obex)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_serial_opts, func_inst);
obex->port_num = opts->port_num;
obex->port.connect = obex_connect;
obex->port.disconnect = obex_disconnect;
obex->port.func.name = "obex";
obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */
obex->port.func.bind = obex_bind;
obex->port.func.unbind = obex_unbind;
obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable;
obex->port.func.free_func = obex_free;
return &obex->port.func;
}
DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
#endif
MODULE_AUTHOR("Felipe Balbi"); MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
int int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer) u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{ {
struct f_rndis *rndis; struct f_rndis *rndis;
int status; int status;
@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->vendorID = vendorID; rndis->vendorID = vendorID;
rndis->manufacturer = manufacturer; rndis->manufacturer = manufacturer;
rndis->port.ioport = dev;
/* RNDIS activates when the host changes this filter */ /* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0; rndis->port.cdc_filter = 0;

View File

@ -12,6 +12,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include "u_serial.h" #include "u_serial.h"
@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
/* interface descriptor: */ /* interface descriptor: */
static struct usb_interface_descriptor gser_interface_desc __initdata = { static struct usb_interface_descriptor gser_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */ /* .bInterfaceNumber = DYNAMIC */
@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
/* full speed support: */ /* full speed support: */
static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = { static struct usb_endpoint_descriptor gser_fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
}; };
static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = { static struct usb_endpoint_descriptor gser_fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT, .bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
}; };
static struct usb_descriptor_header *gser_fs_function[] __initdata = { static struct usb_descriptor_header *gser_fs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_fs_in_desc, (struct usb_descriptor_header *) &gser_fs_in_desc,
(struct usb_descriptor_header *) &gser_fs_out_desc, (struct usb_descriptor_header *) &gser_fs_out_desc,
@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
/* high speed support: */ /* high speed support: */
static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = { static struct usb_endpoint_descriptor gser_hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512), .wMaxPacketSize = cpu_to_le16(512),
}; };
static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = { static struct usb_endpoint_descriptor gser_hs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512), .wMaxPacketSize = cpu_to_le16(512),
}; };
static struct usb_descriptor_header *gser_hs_function[] __initdata = { static struct usb_descriptor_header *gser_hs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_hs_in_desc, (struct usb_descriptor_header *) &gser_hs_in_desc,
(struct usb_descriptor_header *) &gser_hs_out_desc, (struct usb_descriptor_header *) &gser_hs_out_desc,
NULL, NULL,
}; };
static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = { static struct usb_endpoint_descriptor gser_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024), .wMaxPacketSize = cpu_to_le16(1024),
}; };
static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = { static struct usb_endpoint_descriptor gser_ss_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024), .wMaxPacketSize = cpu_to_le16(1024),
}; };
static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = { static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
.bLength = sizeof gser_ss_bulk_comp_desc, .bLength = sizeof gser_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
}; };
static struct usb_descriptor_header *gser_ss_function[] __initdata = { static struct usb_descriptor_header *gser_ss_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_ss_in_desc, (struct usb_descriptor_header *) &gser_ss_in_desc,
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc, (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
/* serial function driver setup/binding */ /* serial function driver setup/binding */
static int __init static int gser_bind(struct usb_configuration *c, struct usb_function *f)
gser_bind(struct usb_configuration *c, struct usb_function *f)
{ {
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct f_gser *gser = func_to_gser(f); struct f_gser *gser = func_to_gser(f);
int status; int status;
struct usb_ep *ep; struct usb_ep *ep;
/* REVISIT might want instance-specific strings to help
* distinguish instances ...
*/
/* maybe allocate device-global string ID */
if (gser_string_defs[0].id == 0) {
status = usb_string_id(c->cdev);
if (status < 0)
return status;
gser_string_defs[0].id = status;
}
/* allocate instance-specific interface IDs */ /* allocate instance-specific interface IDs */
status = usb_interface_id(c, f); status = usb_interface_id(c, f);
if (status < 0) if (status < 0)
@ -246,44 +258,115 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
return status; return status;
} }
static void static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
gser_unbind(struct usb_configuration *c, struct usb_function *f)
{ {
usb_free_all_descriptors(f); return container_of(to_config_group(item), struct f_serial_opts,
kfree(func_to_gser(f)); func_inst.group);
} }
/** CONFIGFS_ATTR_STRUCT(f_serial_opts);
* gser_bind_config - add a generic serial function to a configuration static ssize_t f_serial_attr_show(struct config_item *item,
* @c: the configuration to support the serial instance struct configfs_attribute *attr,
* @port_num: /dev/ttyGS* port this interface will use char *page)
* Context: single threaded during gadget setup {
* struct f_serial_opts *opts = to_f_serial_opts(item);
* Returns zero on success, else negative errno. struct f_serial_opts_attribute *f_serial_opts_attr =
*/ container_of(attr, struct f_serial_opts_attribute, attr);
int __init gser_bind_config(struct usb_configuration *c, u8 port_num) ssize_t ret = 0;
if (f_serial_opts_attr->show)
ret = f_serial_opts_attr->show(opts, page);
return ret;
}
static void serial_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
usb_put_function_instance(&opts->func_inst);
}
static struct configfs_item_operations serial_item_ops = {
.release = serial_attr_release,
.show_attribute = f_serial_attr_show,
};
static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
{
return sprintf(page, "%u\n", opts->port_num);
}
static struct f_serial_opts_attribute f_serial_port_num =
__CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
static struct configfs_attribute *acm_attrs[] = {
&f_serial_port_num.attr,
NULL,
};
static struct config_item_type serial_func_type = {
.ct_item_ops = &serial_item_ops,
.ct_attrs = acm_attrs,
.ct_owner = THIS_MODULE,
};
static void gser_free_inst(struct usb_function_instance *f)
{
struct f_serial_opts *opts;
opts = container_of(f, struct f_serial_opts, func_inst);
gserial_free_line(opts->port_num);
kfree(opts);
}
static struct usb_function_instance *gser_alloc_inst(void)
{
struct f_serial_opts *opts;
int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = gser_free_inst;
ret = gserial_alloc_line(&opts->port_num);
if (ret) {
kfree(opts);
return ERR_PTR(ret);
}
config_group_init_type_name(&opts->func_inst.group, "",
&serial_func_type);
return &opts->func_inst;
}
static void gser_free(struct usb_function *f)
{
struct f_gser *serial;
serial = func_to_gser(f);
kfree(serial);
}
static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
{
usb_free_all_descriptors(f);
}
struct usb_function *gser_alloc(struct usb_function_instance *fi)
{ {
struct f_gser *gser; struct f_gser *gser;
int status; struct f_serial_opts *opts;
/* REVISIT might want instance-specific strings to help
* distinguish instances ...
*/
/* maybe allocate device-global string ID */
if (gser_string_defs[0].id == 0) {
status = usb_string_id(c->cdev);
if (status < 0)
return status;
gser_string_defs[0].id = status;
}
/* allocate and initialize one new instance */ /* allocate and initialize one new instance */
gser = kzalloc(sizeof *gser, GFP_KERNEL); gser = kzalloc(sizeof(*gser), GFP_KERNEL);
if (!gser) if (!gser)
return -ENOMEM; return ERR_PTR(-ENOMEM);
gser->port_num = port_num; opts = container_of(fi, struct f_serial_opts, func_inst);
gser->port_num = opts->port_num;
gser->port.func.name = "gser"; gser->port.func.name = "gser";
gser->port.func.strings = gser_strings; gser->port.func.strings = gser_strings;
@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
gser->port.func.unbind = gser_unbind; gser->port.func.unbind = gser_unbind;
gser->port.func.set_alt = gser_set_alt; gser->port.func.set_alt = gser_set_alt;
gser->port.func.disable = gser_disable; gser->port.func.disable = gser_disable;
gser->port.func.free_func = gser_free;
status = usb_add_function(c, &gser->port.func); return &gser->port.func;
if (status)
kfree(gser);
return status;
} }
DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Al Borchers");
MODULE_AUTHOR("David Brownell");

View File

@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible * Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload. * for calling @gether_cleanup() before module unload.
*/ */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev)
{ {
struct f_gether *geth; struct f_gether *geth;
int status; int status;
@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr); snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
geth_string_defs[1].s = geth->ethaddr; geth_string_defs[1].s = geth->ethaddr;
geth->port.ioport = dev;
geth->port.cdc_filter = DEFAULT_FILTER; geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset"; geth->port.func.name = "cdc_subset";

View File

@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* module parameters specific to the Video streaming endpoint */ /* module parameters specific to the Video streaming endpoint */
static unsigned streaming_interval = 1; static unsigned int streaming_interval = 1;
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_interval, "1 - 16"); MODULE_PARM_DESC(streaming_interval, "1 - 16");
static unsigned streaming_maxpacket = 1024; static unsigned int streaming_maxpacket = 1024;
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
static unsigned streaming_mult; static unsigned int streaming_maxburst;
module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
static unsigned streaming_maxburst;
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
/* string IDs are assigned dynamically */ /* string IDs are assigned dynamically */
#define UVC_STRING_ASSOCIATION_IDX 0 #define UVC_STRING_CONTROL_IDX 0
#define UVC_STRING_CONTROL_IDX 1 #define UVC_STRING_STREAMING_IDX 1
#define UVC_STRING_STREAMING_IDX 2
static struct usb_string uvc_en_us_strings[] = { static struct usb_string uvc_en_us_strings[] = {
[UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera", [UVC_STRING_CONTROL_IDX].s = "UVC Camera",
[UVC_STRING_CONTROL_IDX].s = "Video Control",
[UVC_STRING_STREAMING_IDX].s = "Video Streaming", [UVC_STRING_STREAMING_IDX].s = "Video Streaming",
{ } { }
}; };
@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
#define UVC_INTF_VIDEO_CONTROL 0 #define UVC_INTF_VIDEO_CONTROL 0
#define UVC_INTF_VIDEO_STREAMING 1 #define UVC_INTF_VIDEO_STREAMING 1
#define STATUS_BYTECOUNT 16 /* 16 bytes status */ #define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */
static struct usb_interface_assoc_descriptor uvc_iad __initdata = { static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
.bLength = sizeof(uvc_iad), .bLength = sizeof(uvc_iad),
@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
.iInterface = 0, .iInterface = 0,
}; };
static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT, .bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), .wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
.bInterval = 8, .bInterval = 8,
}; };
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
.bLength = sizeof(uvc_ss_control_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* The following 3 values can be tweaked if necessary. */
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
};
static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubType = UVC_EP_INTERRUPT, .bDescriptorSubType = UVC_EP_INTERRUPT,
.wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT), .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
}; };
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
.iInterface = 0, .iInterface = 0,
}; };
static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
.wMaxPacketSize = cpu_to_le16(512), | USB_ENDPOINT_XFER_ISOC,
.bInterval = 1, /* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
.wMaxPacketSize = 0,
.bInterval = 0,
}; };
static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
.wMaxPacketSize = cpu_to_le16(1024), | USB_ENDPOINT_XFER_ISOC,
.bInterval = 1, /* The wMaxPacketSize and bInterval values will be initialized from
}; * module parameters.
*/
/* super speed support */ .wMaxPacketSize = 0,
static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { .bInterval = 0,
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
.bInterval = 8,
};
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
.bLength = sizeof uvc_ss_control_comp,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* the following 3 values can be tweaked if necessary */
/* .bMaxBurst = 0, */
/* .bmAttributes = 0, */
.wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
}; };
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN, .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
.wMaxPacketSize = cpu_to_le16(1024), | USB_ENDPOINT_XFER_ISOC,
.bInterval = 4, /* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
.wMaxPacketSize = 0,
.bInterval = 0,
}; };
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
.bLength = sizeof uvc_ss_streaming_comp, .bLength = sizeof(uvc_ss_streaming_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* The following 3 values can be tweaked if necessary. */
/* the following 3 values can be tweaked if necessary */ .bMaxBurst = 0,
.bMaxBurst = 0, .bmAttributes = 0,
.bmAttributes = 0, .wBytesPerInterval = cpu_to_le16(1024),
.wBytesPerInterval = cpu_to_le16(1024),
}; };
static const struct usb_descriptor_header * const uvc_fs_streaming[] = { static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
return 0; return 0;
} }
void uvc_function_setup_continue(struct uvc_device *uvc)
{
struct usb_composite_dev *cdev = uvc->func.config->cdev;
usb_composite_setup_continue(cdev);
}
static int static int
uvc_function_get_alt(struct usb_function *f, unsigned interface) uvc_function_get_alt(struct usb_function *f, unsigned interface)
{ {
@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
v4l2_event_queue(uvc->vdev, &v4l2_event); v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED; uvc->state = UVC_STATE_CONNECTED;
break; return 0;
case 1: case 1:
if (uvc->state != UVC_STATE_CONNECTED) if (uvc->state != UVC_STATE_CONNECTED)
@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
memset(&v4l2_event, 0, sizeof(v4l2_event)); memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event); v4l2_event_queue(uvc->vdev, &v4l2_event);
return USB_GADGET_DELAYED_STATUS;
uvc->state = UVC_STATE_STREAMING;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
return 0;
} }
static void static void
@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
const struct uvc_descriptor_header * const *uvc_streaming_cls; const struct uvc_descriptor_header * const *uvc_streaming_cls;
const struct usb_descriptor_header * const *uvc_streaming_std; const struct usb_descriptor_header * const *uvc_streaming_std;
const struct usb_descriptor_header * const *src; const struct usb_descriptor_header * const *src;
static struct usb_endpoint_descriptor *uvc_control_ep;
struct usb_descriptor_header **dst; struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr; struct usb_descriptor_header **hdr;
unsigned int control_size; unsigned int control_size;
@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.ss_control; uvc_control_desc = uvc->desc.ss_control;
uvc_streaming_cls = uvc->desc.ss_streaming; uvc_streaming_cls = uvc->desc.ss_streaming;
uvc_streaming_std = uvc_ss_streaming; uvc_streaming_std = uvc_ss_streaming;
uvc_control_ep = &uvc_ss_control_ep;
break; break;
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
uvc_control_desc = uvc->desc.fs_control; uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.hs_streaming; uvc_streaming_cls = uvc->desc.hs_streaming;
uvc_streaming_std = uvc_hs_streaming; uvc_streaming_std = uvc_hs_streaming;
uvc_control_ep = &uvc_fs_control_ep;
break; break;
case USB_SPEED_FULL: case USB_SPEED_FULL:
@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.fs_control; uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.fs_streaming; uvc_streaming_cls = uvc->desc.fs_streaming;
uvc_streaming_std = uvc_fs_streaming; uvc_streaming_std = uvc_fs_streaming;
uvc_control_ep = &uvc_fs_control_ep;
break; break;
} }
@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
* Class-specific UVC control descriptors * Class-specific UVC control descriptors
* uvc_control_ep * uvc_control_ep
* uvc_control_cs_ep * uvc_control_cs_ep
* uvc_ss_control_comp (for SS only)
* uvc_streaming_intf_alt0 * uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors * Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming * uvc_{fs|hs}_streaming
@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
control_size = 0; control_size = 0;
streaming_size = 0; streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength bytes = uvc_iad.bLength + uvc_control_intf.bLength
+ uvc_control_ep->bLength + uvc_control_cs_ep.bLength + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+ uvc_streaming_intf_alt0.bLength; + uvc_streaming_intf_alt0.bLength;
if (speed == USB_SPEED_SUPER) { if (speed == USB_SPEED_SUPER) {
@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
} }
for (src = (const struct usb_descriptor_header **)uvc_control_desc; for (src = (const struct usb_descriptor_header **)uvc_control_desc;
*src; ++src) { *src; ++src) {
control_size += (*src)->bLength; control_size += (*src)->bLength;
bytes += (*src)->bLength; bytes += (*src)->bLength;
n_desc++; n_desc++;
} }
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
*src; ++src) { *src; ++src) {
streaming_size += (*src)->bLength; streaming_size += (*src)->bLength;
bytes += (*src)->bLength; bytes += (*src)->bLength;
n_desc++; n_desc++;
@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_header->bInCollection = 1; uvc_control_header->bInCollection = 1;
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
if (speed == USB_SPEED_SUPER) if (speed == USB_SPEED_SUPER)
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
UVC_COPY_DESCRIPTORS(mem, dst, UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header**)uvc_streaming_cls); (const struct usb_descriptor_header**)uvc_streaming_cls);
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
uvc_streaming_header->bEndpointAddress = uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
uvc_fs_streaming_ep.bEndpointAddress;
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep->driver_data = NULL; uvc->control_ep->driver_data = NULL;
uvc->video.ep->driver_data = NULL; uvc->video.ep->driver_data = NULL;
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0; uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0;
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf); kfree(uvc->control_buf);
@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{ {
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
unsigned int max_packet_mult;
unsigned int max_packet_size;
struct usb_ep *ep; struct usb_ep *ep;
int ret = -EINVAL; int ret = -EINVAL;
INFO(cdev, "uvc_function_bind\n"); INFO(cdev, "uvc_function_bind\n");
/* sanity check the streaming endpoint module parameters */ /* Sanity check the streaming endpoint module parameters.
if (streaming_interval < 1)
streaming_interval = 1;
if (streaming_interval > 16)
streaming_interval = 16;
if (streaming_mult > 2)
streaming_mult = 2;
if (streaming_maxburst > 15)
streaming_maxburst = 15;
/*
* fill in the FS video streaming specific descriptors from the
* module parameters
*/ */
uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ? streaming_interval = clamp(streaming_interval, 1U, 16U);
1023 : streaming_maxpacket; streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
streaming_maxburst = min(streaming_maxburst, 15U);
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
* module parameters.
*
* NOTE: We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
if (streaming_maxpacket <= 1024) {
max_packet_mult = 1;
max_packet_size = streaming_maxpacket;
} else if (streaming_maxpacket <= 2048) {
max_packet_mult = 2;
max_packet_size = streaming_maxpacket / 2;
} else {
max_packet_mult = 3;
max_packet_size = streaming_maxpacket / 3;
}
uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
uvc_fs_streaming_ep.bInterval = streaming_interval; uvc_fs_streaming_ep.bInterval = streaming_interval;
uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
uvc_hs_streaming_ep.bInterval = streaming_interval;
uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
uvc_ss_streaming_ep.bInterval = streaming_interval;
uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
max_packet_size * max_packet_mult * streaming_maxburst;
/* Allocate endpoints. */ /* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep); ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) { if (!ep) {
INFO(cdev, "Unable to allocate control EP\n"); INFO(cdev, "Unable to allocate control EP\n");
goto error; goto error;
@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep = ep; uvc->control_ep = ep;
ep->driver_data = uvc; ep->driver_data = uvc;
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); if (gadget_is_superspeed(c->cdev->gadget))
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
&uvc_ss_streaming_comp);
else if (gadget_is_dualspeed(cdev->gadget))
ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
else
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
if (!ep) { if (!ep) {
INFO(cdev, "Unable to allocate streaming EP\n"); INFO(cdev, "Unable to allocate streaming EP\n");
goto error; goto error;
@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->video.ep = ep; uvc->video.ep = ep;
ep->driver_data = uvc; ep->driver_data = uvc;
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
/* Allocate interface IDs. */ /* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0) if ((ret = usb_interface_id(c, f)) < 0)
goto error; goto error;
@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret; uvc->streaming_intf = ret;
/* sanity check the streaming endpoint module parameters */
if (streaming_maxpacket > 1024)
streaming_maxpacket = 1024;
/*
* Fill in the HS descriptors from the module parameters for the Video
* Streaming endpoint.
* NOTE: We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
uvc_hs_streaming_ep.bInterval = streaming_interval;
uvc_hs_streaming_ep.bEndpointAddress =
uvc_fs_streaming_ep.bEndpointAddress;
/*
* Fill in the SS descriptors from the module parameters for the Video
* Streaming endpoint.
* NOTE: We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
uvc_ss_streaming_ep.bInterval = streaming_interval;
uvc_ss_streaming_comp.bmAttributes = streaming_mult;
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
streaming_maxpacket * (streaming_mult + 1) *
(streaming_maxburst + 1);
uvc_ss_streaming_ep.bEndpointAddress =
uvc_fs_streaming_ep.bEndpointAddress;
/* Copy descriptors */ /* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
if (gadget_is_dualspeed(cdev->gadget)) if (gadget_is_dualspeed(cdev->gadget))
@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c,
/* Validate the descriptors. */ /* Validate the descriptors. */
if (fs_control == NULL || fs_control[0] == NULL || if (fs_control == NULL || fs_control[0] == NULL ||
fs_control[0]->bDescriptorSubType != UVC_VC_HEADER) fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error; goto error;
if (ss_control == NULL || ss_control[0] == NULL || if (ss_control == NULL || ss_control[0] == NULL ||
ss_control[0]->bDescriptorSubType != UVC_VC_HEADER) ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error; goto error;
if (fs_streaming == NULL || fs_streaming[0] == NULL || if (fs_streaming == NULL || fs_streaming[0] == NULL ||
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error; goto error;
if (hs_streaming == NULL || hs_streaming[0] == NULL || if (hs_streaming == NULL || hs_streaming[0] == NULL ||
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error; goto error;
if (ss_streaming == NULL || ss_streaming[0] == NULL || if (ss_streaming == NULL || ss_streaming[0] == NULL ||
ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error; goto error;
uvc->desc.fs_control = fs_control; uvc->desc.fs_control = fs_control;
@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c,
uvc->desc.hs_streaming = hs_streaming; uvc->desc.hs_streaming = hs_streaming;
uvc->desc.ss_streaming = ss_streaming; uvc->desc.ss_streaming = ss_streaming;
/* Allocate string descriptor numbers. */ /* String descriptors are global, we only need to allocate string IDs
if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { * for the first UVC function. UVC functions beyond the first (if any)
* will reuse the same IDs.
*/
if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) {
ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
if (ret) if (ret)
goto error; goto error;
uvc_iad.iFunction = uvc_iad.iFunction =
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id; uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
uvc_control_intf.iInterface = uvc_control_intf.iInterface =
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id;

View File

@ -16,12 +16,12 @@
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include <linux/usb/video.h> #include <linux/usb/video.h>
extern int uvc_bind_config(struct usb_configuration *c, int uvc_bind_config(struct usb_configuration *c,
const struct uvc_descriptor_header * const *fs_control, const struct uvc_descriptor_header * const *fs_control,
const struct uvc_descriptor_header * const *hs_control, const struct uvc_descriptor_header * const *hs_control,
const struct uvc_descriptor_header * const *fs_streaming, const struct uvc_descriptor_header * const *fs_streaming,
const struct uvc_descriptor_header * const *hs_streaming, const struct uvc_descriptor_header * const *hs_streaming,
const struct uvc_descriptor_header * const *ss_streaming); const struct uvc_descriptor_header * const *ss_streaming);
#endif /* _F_UVC_H_ */ #endif /* _F_UVC_H_ */

View File

@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
driver->driver.bus = NULL; driver->driver.bus = NULL;
/* hook up the driver */ /* hook up the driver */
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.speed = driver->max_speed; udc->gadget.speed = driver->max_speed;
/* Enable IRQ reg and Set usbcmd reg EN bit */ /* Enable IRQ reg and Set usbcmd reg EN bit */
@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
nuke(loop_ep, -ESHUTDOWN); nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
/* name: Identifies the controller hardware type. */ /* name: Identifies the controller hardware type. */
udc->gadget.name = driver_name; udc->gadget.name = driver_name;
device_initialize(&udc->gadget.dev);
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.dev.release = qe_udc_release;
udc->gadget.dev.parent = &ofdev->dev; udc->gadget.dev.parent = &ofdev->dev;
/* initialize qe_ep struct */ /* initialize qe_ep struct */
@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev)
goto err5; goto err5;
} }
ret = device_add(&udc->gadget.dev); ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget,
qe_udc_release);
if (ret) if (ret)
goto err6; goto err6;
ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
if (ret)
goto err7;
dev_set_drvdata(&ofdev->dev, udc); dev_set_drvdata(&ofdev->dev, udc);
dev_info(udc->dev, dev_info(udc->dev,
"%s USB controller initialized as device\n", "%s USB controller initialized as device\n",
(udc->soc_type == PORT_QE) ? "QE" : "CPM"); (udc->soc_type == PORT_QE) ? "QE" : "CPM");
return 0; return 0;
err7:
device_unregister(&udc->gadget.dev);
err6: err6:
free_irq(udc->usb_irq, udc); free_irq(udc->usb_irq, udc);
err5: err5:
@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev)
iounmap(udc->usb_regs); iounmap(udc->usb_regs);
device_unregister(&udc->gadget.dev);
/* wait for release() of gadget.dev to free udc */ /* wait for release() of gadget.dev to free udc */
wait_for_completion(&done); wait_for_completion(&done);

View File

@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
} }
if (req->mapped) { usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
ep_is_in(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
} else
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
ep_is_in(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
if (status && (status != -ESHUTDOWN)) if (status && (status != -ESHUTDOWN))
VDBG("complete %s req %p stat %d len %u/%u", VDBG("complete %s req %p stat %d len %u/%u",
@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
struct fsl_req *req = container_of(_req, struct fsl_req, req); struct fsl_req *req = container_of(_req, struct fsl_req, req);
struct fsl_udc *udc; struct fsl_udc *udc;
unsigned long flags; unsigned long flags;
int ret;
/* catch various bogus parameters */ /* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf if (!_req || !req->req.complete || !req->req.buf
@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep; req->ep = ep;
/* map virtual address to hardware */ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
if (req->req.dma == DMA_ADDR_INVALID) { if (ret)
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, return ret;
req->req.buf,
req->req.length, ep_is_in(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->mapped = 1;
} else {
dma_sync_single_for_device(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
ep_is_in(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->mapped = 0;
}
req->req.status = -EINPROGRESS; req->req.status = -EINPROGRESS;
req->req.actual = 0; req->req.actual = 0;
@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
{ {
struct fsl_req *req = udc->status_req; struct fsl_req *req = udc->status_req;
struct fsl_ep *ep; struct fsl_ep *ep;
int ret;
if (direction == EP_DIR_IN) if (direction == EP_DIR_IN)
udc->ep0_dir = USB_DIR_IN; udc->ep0_dir = USB_DIR_IN;
@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
req->req.complete = NULL; req->req.complete = NULL;
req->dtd_count = 0; req->dtd_count = 0;
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
req->req.buf, req->req.length, if (ret)
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); return ret;
req->mapped = 1;
if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0) if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req); fsl_queue_td(ep, req);
@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
u16 tmp = 0; /* Status, cpu endian */ u16 tmp = 0; /* Status, cpu endian */
struct fsl_req *req; struct fsl_req *req;
struct fsl_ep *ep; struct fsl_ep *ep;
int ret;
ep = &udc->eps[0]; ep = &udc->eps[0];
@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->req.complete = NULL; req->req.complete = NULL;
req->dtd_count = 0; req->dtd_count = 0;
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
req->req.buf, req->req.length, if (ret)
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); goto stall;
req->mapped = 1;
/* prime the data phase */ /* prime the data phase */
if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0)) if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL; driver->driver.bus = NULL;
/* hook up the driver */ /* hook up the driver */
udc_controller->driver = driver; udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags); spin_unlock_irqrestore(&udc_controller->lock, flags);
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) { if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g,
if (retval < 0) { if (retval < 0) {
ERR("can't bind to transceiver\n"); ERR("can't bind to transceiver\n");
driver->unbind(&udc_controller->gadget); driver->unbind(&udc_controller->gadget);
udc_controller->gadget.dev.driver = 0;
udc_controller->driver = 0; udc_controller->driver = 0;
return retval; return retval;
} }
@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g,
nuke(loop_ep, -ESHUTDOWN); nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc_controller->lock, flags); spin_unlock_irqrestore(&udc_controller->lock, flags);
udc_controller->gadget.dev.driver = NULL;
udc_controller->driver = NULL; udc_controller->driver = NULL;
return 0; return 0;
@ -2521,12 +2493,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
/* Setup gadget.dev and register with kernel */ /* Setup gadget.dev and register with kernel */
dev_set_name(&udc_controller->gadget.dev, "gadget"); dev_set_name(&udc_controller->gadget.dev, "gadget");
udc_controller->gadget.dev.release = fsl_udc_release;
udc_controller->gadget.dev.parent = &pdev->dev;
udc_controller->gadget.dev.of_node = pdev->dev.of_node; udc_controller->gadget.dev.of_node = pdev->dev.of_node;
ret = device_register(&udc_controller->gadget.dev);
if (ret < 0)
goto err_free_irq;
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) if (!IS_ERR_OR_NULL(udc_controller->transceiver))
udc_controller->gadget.is_otg = 1; udc_controller->gadget.is_otg = 1;
@ -2559,10 +2526,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
DTD_ALIGNMENT, UDC_DMA_BOUNDARY); DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
if (udc_controller->td_pool == NULL) { if (udc_controller->td_pool == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_unregister; goto err_free_irq;
} }
ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget,
fsl_udc_release);
if (ret) if (ret)
goto err_del_udc; goto err_del_udc;
@ -2571,8 +2539,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
err_del_udc: err_del_udc:
dma_pool_destroy(udc_controller->td_pool); dma_pool_destroy(udc_controller->td_pool);
err_unregister:
device_unregister(&udc_controller->gadget.dev);
err_free_irq: err_free_irq:
free_irq(udc_controller->irq, udc_controller); free_irq(udc_controller->irq, udc_controller);
err_iounmap: err_iounmap:
@ -2622,7 +2588,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
if (pdata->operating_mode == FSL_USB2_DR_DEVICE) if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
device_unregister(&udc_controller->gadget.dev);
/* free udc --wait for the release() finished */ /* free udc --wait for the release() finished */
wait_for_completion(&done); wait_for_completion(&done);
@ -2747,21 +2712,7 @@ static struct platform_driver udc_driver = {
}, },
}; };
static int __init udc_init(void) module_platform_driver_probe(udc_driver, fsl_udc_probe);
{
printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
return platform_driver_probe(&udc_driver, fsl_udc_probe);
}
module_init(udc_init);
static void __exit udc_exit(void)
{
platform_driver_unregister(&udc_driver);
printk(KERN_WARNING "%s unregistered\n", driver_desc);
}
module_exit(udc_exit);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR);

View File

@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
if (reg & FUSB300_EPSET0_STL) { if (reg & FUSB300_EPSET0_STL) {
printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
reg &= ~FUSB300_EPSET0_STL; reg |= FUSB300_EPSET0_STL_CLR;
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
} }
} }
@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
return;
IDMA_RESET: IDMA_RESET:
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0, reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
} }
static void fusb300_set_idma(struct fusb300_ep *ep, static void fusb300_set_idma(struct fusb300_ep *ep,
struct fusb300_request *req) struct fusb300_request *req)
{ {
dma_addr_t d; int ret;
d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE); ret = usb_gadget_map_request(&ep->fusb300->gadget,
&req->req, DMA_TO_DEVICE);
if (dma_mapping_error(NULL, d)) { if (ret)
printk(KERN_DEBUG "dma_mapping_error\n");
return; return;
}
dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
fusb300_fill_idma_prdtbl(ep, d, req->req.length); fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
/* check idma is done */ /* check idma is done */
fusb300_wait_idma_finished(ep); fusb300_wait_idma_finished(ep);
dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); usb_gadget_unmap_request(&ep->fusb300->gadget,
&req->req, DMA_TO_DEVICE);
} }
static void in_ep_fifo_handler(struct fusb300_ep *ep) static void in_ep_fifo_handler(struct fusb300_ep *ep)
@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
/* hook up the driver */ /* hook up the driver */
driver->driver.bus = NULL; driver->driver.bus = NULL;
fusb300->driver = driver; fusb300->driver = driver;
fusb300->gadget.dev.driver = &driver->driver;
return 0; return 0;
} }
@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g,
struct fusb300 *fusb300 = to_fusb300(g); struct fusb300 *fusb300 = to_fusb300(g);
driver->unbind(&fusb300->gadget); driver->unbind(&fusb300->gadget);
fusb300->gadget.dev.driver = NULL;
init_controller(fusb300); init_controller(fusb300);
fusb300->driver = NULL; fusb300->driver = NULL;
@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->gadget.ops = &fusb300_gadget_ops; fusb300->gadget.ops = &fusb300_gadget_ops;
device_initialize(&fusb300->gadget.dev);
dev_set_name(&fusb300->gadget.dev, "gadget");
fusb300->gadget.max_speed = USB_SPEED_HIGH; fusb300->gadget.max_speed = USB_SPEED_HIGH;
fusb300->gadget.dev.parent = &pdev->dev;
fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
fusb300->gadget.dev.release = pdev->dev.release;
fusb300->gadget.name = udc_name; fusb300->gadget.name = udc_name;
fusb300->reg = reg; fusb300->reg = reg;
@ -1478,19 +1469,10 @@ static int __init fusb300_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_add_udc; goto err_add_udc;
ret = device_add(&fusb300->gadget.dev);
if (ret) {
pr_err("device_add error (%d)\n", ret);
goto err_add_device;
}
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0; return 0;
err_add_device:
usb_del_gadget_udc(&fusb300->gadget);
err_add_udc: err_add_udc:
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);

View File

@ -111,8 +111,8 @@
/* /*
* * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 ) * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
* */ * */
#define FUSB300_EPSET0_STL_CLR (1 << 3)
#define FUSB300_EPSET0_CLRSEQNUM (1 << 2) #define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1)
#define FUSB300_EPSET0_STL (1 << 0) #define FUSB300_EPSET0_STL (1 << 0)
/* /*

View File

@ -13,7 +13,6 @@
#define pr_fmt(fmt) "g_ffs: " fmt #define pr_fmt(fmt) "g_ffs: " fmt
#include <linux/module.h> #include <linux/module.h>
/* /*
* kbuild is not very cooperative with respect to linking separately * kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use * compiled library objects into one module. So for now we won't use
@ -38,13 +37,16 @@
# include "u_ether.c" # include "u_ether.c"
static u8 gfs_hostaddr[ETH_ALEN]; static u8 gfs_hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
# ifdef CONFIG_USB_FUNCTIONFS_ETH # ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev);
# endif # endif
#else #else
# define gether_cleanup() do { } while (0) # define the_dev NULL
# define gether_setup(gadget, hostaddr) ((int)0) # define gether_cleanup(dev) do { } while (0)
# define gfs_hostaddr NULL # define gfs_hostaddr NULL
struct eth_dev;
#endif #endif
#include "f_fs.c" #include "f_fs.c"
@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
struct gfs_configuration { struct gfs_configuration {
struct usb_configuration c; struct usb_configuration c;
int (*eth)(struct usb_configuration *c, u8 *ethaddr); int (*eth)(struct usb_configuration *c, u8 *ethaddr,
struct eth_dev *dev);
} gfs_configurations[] = { } gfs_configurations[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{ {
@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev)
if (missing_funcs) if (missing_funcs)
return -ENODEV; return -ENODEV;
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
ret = gether_setup(cdev->gadget, gfs_hostaddr); the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
if (unlikely(ret < 0)) #endif
if (IS_ERR(the_dev)) {
ret = PTR_ERR(the_dev);
goto error_quick; goto error_quick;
}
gfs_ether_setup = true; gfs_ether_setup = true;
ret = usb_string_ids_tab(cdev, gfs_strings); ret = usb_string_ids_tab(cdev, gfs_strings);
@ -386,7 +392,7 @@ static int gfs_bind(struct usb_composite_dev *cdev)
for (i = 0; i < func_num; i++) for (i = 0; i < func_num; i++)
functionfs_unbind(ffs_tab[i].ffs_data); functionfs_unbind(ffs_tab[i].ffs_data);
error: error:
gether_cleanup(); gether_cleanup(the_dev);
error_quick: error_quick:
gfs_ether_setup = false; gfs_ether_setup = false;
return ret; return ret;
@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
* do...? * do...?
*/ */
if (gfs_ether_setup) if (gfs_ether_setup)
gether_cleanup(); gether_cleanup(the_dev);
gfs_ether_setup = false; gfs_ether_setup = false;
for (i = func_num; i--; ) for (i = func_num; i--; )
@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c)
} }
if (gc->eth) { if (gc->eth) {
ret = gc->eth(c, gfs_hostaddr); ret = gc->eth(c, gfs_hostaddr, the_dev);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
} }
@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c)
#ifdef CONFIG_USB_FUNCTIONFS_ETH #ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev)
{ {
return can_support_ecm(c->cdev->gadget) return can_support_ecm(c->cdev->gadget)
? ecm_bind_config(c, ethaddr) ? ecm_bind_config(c, ethaddr, dev)
: geth_bind_config(c, ethaddr); : geth_bind_config(c, ethaddr, dev);
} }
#endif #endif

View File

@ -51,8 +51,6 @@
#define DRIVER_DESC "TC86C001 USB Device Controller" #define DRIVER_DESC "TC86C001 USB Device Controller"
#define DRIVER_VERSION "30-Oct 2003" #define DRIVER_VERSION "30-Oct 2003"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
static const char driver_name [] = "goku_udc"; static const char driver_name [] = "goku_udc";
static const char driver_desc [] = DRIVER_DESC; static const char driver_desc [] = DRIVER_DESC;
@ -275,7 +273,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req) if (!req)
return NULL; return NULL;
req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue); INIT_LIST_HEAD(&req->queue);
return &req->req; return &req->req;
} }
@ -1354,7 +1351,6 @@ static int goku_udc_start(struct usb_gadget *g,
/* hook up the driver */ /* hook up the driver */
driver->driver.bus = NULL; driver->driver.bus = NULL;
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
/* /*
* then enable host detection and ep0; and we're ready * then enable host detection and ep0; and we're ready
@ -1394,7 +1390,6 @@ static int goku_udc_stop(struct usb_gadget *g,
dev->driver = NULL; dev->driver = NULL;
stop_activity(dev, driver); stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
return 0; return 0;
} }
@ -1716,8 +1711,6 @@ static void goku_remove(struct pci_dev *pdev)
pci_resource_len (pdev, 0)); pci_resource_len (pdev, 0));
if (dev->enabled) if (dev->enabled)
pci_disable_device(pdev); pci_disable_device(pdev);
if (dev->registered)
device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
dev->regs = NULL; dev->regs = NULL;
@ -1756,10 +1749,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_FULL; dev->gadget.max_speed = USB_SPEED_FULL;
/* the "gadget" abstracts/virtualizes the controller */ /* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name; dev->gadget.name = driver_name;
/* now all the pci goodies ... */ /* now all the pci goodies ... */
@ -1810,13 +1799,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev); create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
#endif #endif
retval = device_register(&dev->gadget.dev); retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
if (retval) { gadget_release);
put_device(&dev->gadget.dev);
goto err;
}
dev->registered = 1;
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
if (retval) if (retval)
goto err; goto err;

View File

@ -250,8 +250,7 @@ struct goku_udc {
got_region:1, got_region:1,
req_config:1, req_config:1,
configured:1, configured:1,
enabled:1, enabled:1;
registered:1;
/* pci state used to access those endpoints */ /* pci state used to access those endpoints */
struct pci_dev *pdev; struct pci_dev *pdev;

View File

@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget,
imx_usb = container_of(gadget, struct imx_udc_struct, gadget); imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
/* first hook up the driver ... */ /* first hook up the driver ... */
imx_usb->driver = driver; imx_usb->driver = driver;
imx_usb->gadget.dev.driver = &driver->driver;
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
__func__, driver->driver.name); __func__, driver->driver.name);
@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
imx_udc_disable(imx_usb); imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer); del_timer(&imx_usb->timer);
imx_usb->gadget.dev.driver = NULL;
imx_usb->driver = NULL; imx_usb->driver = NULL;
D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev)
imx_usb->clk = clk; imx_usb->clk = clk;
imx_usb->dev = &pdev->dev; imx_usb->dev = &pdev->dev;
device_initialize(&imx_usb->gadget.dev);
imx_usb->gadget.dev.parent = &pdev->dev;
imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
ret = device_add(&imx_usb->gadget.dev);
if (retval)
goto fail4;
platform_set_drvdata(pdev, imx_usb); platform_set_drvdata(pdev, imx_usb);
usb_init_data(imx_usb); usb_init_data(imx_usb);
@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
if (ret) if (ret)
goto fail5; goto fail4;
return 0; return 0;
fail5:
device_unregister(&imx_usb->gadget.dev);
fail4: fail4:
for (i = 0; i < IMX_USB_NB_EP + 1; i++) for (i = 0; i < IMX_USB_NB_EP + 1; i++)
free_irq(imx_usb->usbd_int[i], imx_usb); free_irq(imx_usb->usbd_int[i], imx_usb);
@ -1509,7 +1496,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
int i; int i;
usb_del_gadget_udc(&imx_usb->gadget); usb_del_gadget_udc(&imx_usb->gadget);
device_unregister(&imx_usb->gadget.dev);
imx_udc_disable(imx_usb); imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer); del_timer(&imx_usb->timer);

View File

@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
status = req->req.status; status = req->req.status;
if (ep->lep) { if (ep->lep) {
enum dma_data_direction direction; usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
if (ep->is_in)
direction = DMA_TO_DEVICE;
else
direction = DMA_FROM_DEVICE;
if (req->mapped) {
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
direction);
req->req.dma = 0;
req->mapped = 0;
} else
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
direction);
/* Free DDs */ /* Free DDs */
udc_dd_free(udc, req->dd_desc_ptr); udc_dd_free(udc, req->dd_desc_ptr);
@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
} }
if (ep->lep) { if (ep->lep) {
enum dma_data_direction direction;
struct lpc32xx_usbd_dd_gad *dd; struct lpc32xx_usbd_dd_gad *dd;
/* Map DMA pointer */ status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in);
if (ep->is_in) if (status)
direction = DMA_TO_DEVICE; return status;
else
direction = DMA_FROM_DEVICE;
if (req->req.dma == 0) {
req->req.dma = dma_map_single(
ep->udc->gadget.dev.parent,
req->req.buf, req->req.length, direction);
req->mapped = 1;
} else {
dma_sync_single_for_device(
ep->udc->gadget.dev.parent, req->req.dma,
req->req.length, direction);
req->mapped = 0;
}
/* For the request, build a list of DDs */ /* For the request, build a list of DDs */
dd = udc_dd_alloc(udc); dd = udc_dd_alloc(udc);
@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget,
} }
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node; udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1; udc->enabled = 1;
udc->selfpowered = 1; udc->selfpowered = 1;
@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget,
} }
udc->enabled = 0; udc->enabled = 0;
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
return 0; return 0;
@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
udc_disable(udc); udc_disable(udc);
udc_reinit(udc); udc_reinit(udc);
retval = device_register(&udc->gadget.dev);
if (retval < 0) {
dev_err(udc->dev, "Device registration failure\n");
goto dev_register_fail;
}
/* Request IRQs - low and high priority USB device IRQs are routed to /* Request IRQs - low and high priority USB device IRQs are routed to
* the same handler, while the DMA interrupt is routed elsewhere */ * the same handler, while the DMA interrupt is routed elsewhere */
retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
@ -3320,8 +3281,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
irq_hp_fail: irq_hp_fail:
free_irq(udc->udp_irq[IRQ_USB_LP], udc); free_irq(udc->udp_irq[IRQ_USB_LP], udc);
irq_lp_fail: irq_lp_fail:
device_unregister(&udc->gadget.dev);
dev_register_fail:
dma_pool_destroy(udc->dd_cache); dma_pool_destroy(udc->dd_cache);
dma_alloc_fail: dma_alloc_fail:
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
free_irq(udc->udp_irq[IRQ_USB_HP], udc); free_irq(udc->udp_irq[IRQ_USB_HP], udc);
free_irq(udc->udp_irq[IRQ_USB_LP], udc); free_irq(udc->udp_irq[IRQ_USB_LP], udc);
device_unregister(&udc->gadget.dev);
clk_disable(udc->usb_otg_clk); clk_disable(udc->usb_otg_clk);
clk_put(udc->usb_otg_clk); clk_put(udc->usb_otg_clk);
clk_disable(udc->usb_slv_clk); clk_disable(udc->usb_slv_clk);

View File

@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g,
/* hook up the driver */ /* hook up the driver */
driver->driver.bus = NULL; driver->driver.bus = NULL;
m66592->driver = driver; m66592->driver = driver;
m66592->gadget.dev.driver = &driver->driver;
m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g,
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
driver->unbind(&m66592->gadget); driver->unbind(&m66592->gadget);
m66592->gadget.dev.driver = NULL;
init_controller(m66592); init_controller(m66592);
disable_controller(m66592); disable_controller(m66592);
@ -1538,7 +1536,6 @@ static int __exit m66592_remove(struct platform_device *pdev)
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
usb_del_gadget_udc(&m66592->gadget); usb_del_gadget_udc(&m66592->gadget);
device_del(&m66592->gadget.dev);
del_timer_sync(&m66592->timer); del_timer_sync(&m66592->timer);
iounmap(m66592->reg); iounmap(m66592->reg);
@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, m66592); dev_set_drvdata(&pdev->dev, m66592);
m66592->gadget.ops = &m66592_gadget_ops; m66592->gadget.ops = &m66592_gadget_ops;
device_initialize(&m66592->gadget.dev);
dev_set_name(&m66592->gadget.dev, "gadget");
m66592->gadget.max_speed = USB_SPEED_HIGH; m66592->gadget.max_speed = USB_SPEED_HIGH;
m66592->gadget.dev.parent = &pdev->dev;
m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
m66592->gadget.dev.release = pdev->dev.release;
m66592->gadget.name = udc_name; m66592->gadget.name = udc_name;
init_timer(&m66592->timer); init_timer(&m66592->timer);
@ -1674,12 +1666,6 @@ static int __init m66592_probe(struct platform_device *pdev)
init_controller(m66592); init_controller(m66592);
ret = device_add(&m66592->gadget.dev);
if (ret) {
pr_err("device_add error (%d)\n", ret);
goto err_device_add;
}
ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
if (ret) if (ret)
goto err_add_udc; goto err_add_udc;
@ -1688,9 +1674,6 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0; return 0;
err_add_udc: err_add_udc:
device_del(&m66592->gadget.dev);
err_device_add:
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
clean_up3: clean_up3:

View File

@ -135,8 +135,8 @@ static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN]; static u8 hostaddr[ETH_ALEN];
static unsigned char tty_line;
static struct usb_function_instance *fi_acm; static struct usb_function_instance *fi_acm;
static struct eth_dev *the_dev;
/********** RNDIS **********/ /********** RNDIS **********/
@ -152,7 +152,7 @@ static __init int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
ret = rndis_bind_config(c, hostaddr); ret = rndis_bind_config(c, hostaddr, the_dev);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -214,7 +214,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
ret = ecm_bind_config(c, hostaddr); ret = ecm_bind_config(c, hostaddr, the_dev);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -269,7 +269,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
static int __ref multi_bind(struct usb_composite_dev *cdev) static int __ref multi_bind(struct usb_composite_dev *cdev)
{ {
struct usb_gadget *gadget = cdev->gadget; struct usb_gadget *gadget = cdev->gadget;
struct f_serial_opts *opts;
int status; int status;
if (!can_support_ecm(cdev->gadget)) { if (!can_support_ecm(cdev->gadget)) {
@ -279,24 +278,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
} }
/* set up network link layer */ /* set up network link layer */
status = gether_setup(cdev->gadget, hostaddr); the_dev = gether_setup(cdev->gadget, hostaddr);
if (status < 0) if (IS_ERR(the_dev))
return status; return PTR_ERR(the_dev);
/* set up serial link layer */ /* set up serial link layer */
status = gserial_alloc_line(&tty_line);
if (status < 0)
goto fail0;
fi_acm = usb_get_function_instance("acm"); fi_acm = usb_get_function_instance("acm");
if (IS_ERR(fi_acm)) { if (IS_ERR(fi_acm)) {
status = PTR_ERR(fi_acm); status = PTR_ERR(fi_acm);
goto fail0dot5; goto fail0;
} }
opts = container_of(fi_acm, struct f_serial_opts, func_inst);
opts->port_num = tty_line;
/* set up mass storage function */ /* set up mass storage function */
{ {
void *retp; void *retp;
@ -334,10 +326,8 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
fsg_common_put(&fsg_common); fsg_common_put(&fsg_common);
fail1: fail1:
usb_put_function_instance(fi_acm); usb_put_function_instance(fi_acm);
fail0dot5:
gserial_free_line(tty_line);
fail0: fail0:
gether_cleanup(); gether_cleanup(the_dev);
return status; return status;
} }
@ -350,8 +340,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
usb_put_function(f_acm_rndis); usb_put_function(f_acm_rndis);
#endif #endif
usb_put_function_instance(fi_acm); usb_put_function_instance(fi_acm);
gserial_free_line(tty_line); gether_cleanup(the_dev);
gether_cleanup();
return 0; return 0;
} }

View File

@ -30,9 +30,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/mv_usb.h> #include <linux/platform_data/mv_usb.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include "mv_u3d.h" #include "mv_u3d.h"
@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
struct mv_u3d_trb *curr_trb; struct mv_u3d_trb *curr_trb;
dma_addr_t cur_deq_lo; dma_addr_t cur_deq_lo;
struct mv_u3d_ep_context *curr_ep_context; struct mv_u3d_ep_context *curr_ep_context;
int trb_complete, actual, remaining_length; int trb_complete, actual, remaining_length = 0;
int direction, ep_num; int direction, ep_num;
int retval = 0; int retval = 0;
u32 tmp, status, length; u32 tmp, status, length;
@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
*/ */
static static
void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status) void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
__releases(&ep->udc->lock)
__acquires(&ep->udc->lock)
{ {
struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d; struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0; return 0;
} }
dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n", dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
__func__, _ep->name, (u32)req); __func__, _ep->name, req);
/* catch various bogus parameters */ /* catch various bogus parameters */
if (!req->req.complete || !req->req.buf if (!req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) { || !list_empty(&req->queue)) {
dev_err(u3d->dev, dev_err(u3d->dev,
"%s, bad params, _req: 0x%x," "%s, bad params, _req: 0x%p,"
"req->req.complete: 0x%x, req->req.buf: 0x%x," "req->req.complete: 0x%p, req->req.buf: 0x%p,"
"list_empty: 0x%x\n", "list_empty: 0x%x\n",
__func__, (u32)_req, __func__, _req,
(u32)req->req.complete, (u32)req->req.buf, req->req.complete, req->req.buf,
(u32)list_empty(&req->queue)); list_empty(&req->queue));
return -EINVAL; return -EINVAL;
} }
if (unlikely(!ep->ep.desc)) { if (unlikely(!ep->ep.desc)) {
@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct mv_u3d_req, queue); struct mv_u3d_req, queue);
/* Point first TRB of next request to the EP context. */ /* Point first TRB of next request to the EP context. */
iowrite32((u32) next_req->trb_head, iowrite32((unsigned long) next_req->trb_head,
&ep_context->trb_addr_lo); &ep_context->trb_addr_lo);
} else { } else {
struct mv_u3d_ep_context *ep_context; struct mv_u3d_ep_context *ep_context;
@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g,
/* hook up the driver ... */ /* hook up the driver ... */
driver->driver.bus = NULL; driver->driver.bus = NULL;
u3d->driver = driver; u3d->driver = driver;
u3d->gadget.dev.driver = &driver->driver;
u3d->ep0_dir = USB_DIR_OUT; u3d->ep0_dir = USB_DIR_OUT;
@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g,
spin_unlock_irqrestore(&u3d->lock, flags); spin_unlock_irqrestore(&u3d->lock, flags);
u3d->gadget.dev.driver = NULL;
u3d->driver = NULL; u3d->driver = NULL;
return 0; return 0;
@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num, static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
struct usb_ctrlrequest *setup) struct usb_ctrlrequest *setup)
__releases(&u3c->lock)
__acquires(&u3c->lock)
{ {
bool delegate = false; bool delegate = false;
@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void mv_u3d_gadget_release(struct device *dev)
{
dev_dbg(dev, "%s\n", __func__);
}
static int mv_u3d_remove(struct platform_device *dev) static int mv_u3d_remove(struct platform_device *dev)
{ {
struct mv_u3d *u3d = platform_get_drvdata(dev); struct mv_u3d *u3d = platform_get_drvdata(dev);
@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
clk_put(u3d->clk); clk_put(u3d->clk);
device_unregister(&u3d->gadget.dev);
platform_set_drvdata(dev, NULL); platform_set_drvdata(dev, NULL);
kfree(u3d); kfree(u3d);
@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->dev = &dev->dev; u3d->dev = &dev->dev;
u3d->vbus = pdata->vbus; u3d->vbus = pdata->vbus;
u3d->clk = clk_get(&dev->dev, pdata->clkname[0]); u3d->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(u3d->clk)) { if (IS_ERR(u3d->clk)) {
retval = PTR_ERR(u3d->clk); retval = PTR_ERR(u3d->clk);
goto err_get_clk; goto err_get_clk;
@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev)
retval = -EBUSY; retval = -EBUSY;
goto err_map_cap_regs; goto err_map_cap_regs;
} else { } else {
dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n", dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
(unsigned int)r->start, (unsigned int)u3d->cap_regs); (unsigned long) r->start,
(unsigned long) u3d->cap_regs);
} }
/* we will access controller register, so enable the u3d controller */ /* we will access controller register, so enable the u3d controller */
@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev)
} }
} }
u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
+ MV_U3D_USB3_OP_REGS_OFFSET); + MV_U3D_USB3_OP_REGS_OFFSET);
u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
+ ioread32(&u3d->cap_regs->vuoff)); + ioread32(&u3d->cap_regs->vuoff));
u3d->max_eps = 16; u3d->max_eps = 16;
@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
/* the "gadget" abstracts/virtualizes the controller */ /* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&u3d->gadget.dev, "gadget");
u3d->gadget.dev.parent = &dev->dev;
u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
u3d->gadget.dev.release = mv_u3d_gadget_release;
u3d->gadget.name = driver_name; /* gadget name */ u3d->gadget.name = driver_name; /* gadget name */
retval = device_register(&u3d->gadget.dev);
if (retval)
goto err_register_gadget_device;
mv_u3d_eps_init(u3d); mv_u3d_eps_init(u3d);
/* external vbus detection */ /* external vbus detection */
@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev)
return 0; return 0;
err_unregister: err_unregister:
device_unregister(&u3d->gadget.dev);
err_register_gadget_device:
free_irq(u3d->irq, &dev->dev); free_irq(u3d->irq, &dev->dev);
err_request_irq: err_request_irq:
err_get_irq: err_get_irq:
@ -2021,7 +2004,7 @@ static int mv_u3d_probe(struct platform_device *dev)
return retval; return retval;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int mv_u3d_suspend(struct device *dev) static int mv_u3d_suspend(struct device *dev)
{ {
struct mv_u3d *u3d = dev_get_drvdata(dev); struct mv_u3d *u3d = dev_get_drvdata(dev);
@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev)
return 0; return 0;
} }
SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
#endif #endif
static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
static void mv_u3d_shutdown(struct platform_device *dev) static void mv_u3d_shutdown(struct platform_device *dev)
{ {
struct mv_u3d *u3d = dev_get_drvdata(&dev->dev); struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev)
static struct platform_driver mv_u3d_driver = { static struct platform_driver mv_u3d_driver = {
.probe = mv_u3d_probe, .probe = mv_u3d_probe,
.remove = __exit_p(mv_u3d_remove), .remove = mv_u3d_remove,
.shutdown = mv_u3d_shutdown, .shutdown = mv_u3d_shutdown,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "mv-u3d", .name = "mv-u3d",
#ifdef CONFIG_PM
.pm = &mv_u3d_pm_ops, .pm = &mv_u3d_pm_ops,
#endif
}, },
}; };

View File

@ -222,8 +222,7 @@ struct mv_udc {
struct mv_usb_platform_data *pdata; struct mv_usb_platform_data *pdata;
/* some SOC has mutiple clock sources for USB*/ /* some SOC has mutiple clock sources for USB*/
unsigned int clknum; struct clk *clk;
struct clk *clk[0];
}; };
/* endpoint data structure */ /* endpoint data structure */

View File

@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index,
* request is still in progress. * request is still in progress.
*/ */
static void done(struct mv_ep *ep, struct mv_req *req, int status) static void done(struct mv_ep *ep, struct mv_req *req, int status)
__releases(&ep->udc->lock)
__acquires(&ep->udc->lock)
{ {
struct mv_udc *udc = NULL; struct mv_udc *udc = NULL;
unsigned char stopped = ep->stopped; unsigned char stopped = ep->stopped;
@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma); dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
} }
if (req->mapped) { usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
((ep_dir(ep) == EP_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE));
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
} else
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
((ep_dir(ep) == EP_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE));
if (status && (status != -ESHUTDOWN)) if (status && (status != -ESHUTDOWN))
dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u", dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep; req->ep = ep;
/* map virtual address to hardware */ /* map virtual address to hardware */
if (req->req.dma == DMA_ADDR_INVALID) { retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, if (retval)
req->req.buf, return retval;
req->req.length, ep_dir(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->mapped = 1;
} else {
dma_sync_single_for_device(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
ep_dir(ep)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->mapped = 0;
}
req->req.status = -EINPROGRESS; req->req.status = -EINPROGRESS;
req->req.actual = 0; req->req.actual = 0;
@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0; return 0;
err_unmap_dma: err_unmap_dma:
if (req->mapped) { usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
((ep_dir(ep) == EP_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE));
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
} else
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
((ep_dir(ep) == EP_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE));
return retval; return retval;
} }
@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = {
static void udc_clock_enable(struct mv_udc *udc) static void udc_clock_enable(struct mv_udc *udc)
{ {
unsigned int i; clk_prepare_enable(udc->clk);
for (i = 0; i < udc->clknum; i++)
clk_prepare_enable(udc->clk[i]);
} }
static void udc_clock_disable(struct mv_udc *udc) static void udc_clock_disable(struct mv_udc *udc)
{ {
unsigned int i; clk_disable_unprepare(udc->clk);
for (i = 0; i < udc->clknum; i++)
clk_disable_unprepare(udc->clk[i]);
} }
static void udc_stop(struct mv_udc *udc) static void udc_stop(struct mv_udc *udc)
@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
/* hook up the driver ... */ /* hook up the driver ... */
driver->driver.bus = NULL; driver->driver.bus = NULL;
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
udc->usb_state = USB_STATE_ATTACHED; udc->usb_state = USB_STATE_ATTACHED;
udc->ep0_state = WAIT_FOR_SETUP; udc->ep0_state = WAIT_FOR_SETUP;
@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
dev_err(&udc->dev->dev, dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n"); "unable to register peripheral to otg\n");
udc->driver = NULL; udc->driver = NULL;
udc->gadget.dev.driver = NULL;
return retval; return retval;
} }
} }
@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget,
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
/* unbind gadget driver */ /* unbind gadget driver */
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
return 0; return 0;
@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
return 0; return 0;
out: out:
if (req->mapped) { usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
((ep_dir(ep) == EP_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE));
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
}
return retval; return retval;
} }
@ -1695,6 +1647,8 @@ static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
static void handle_setup_packet(struct mv_udc *udc, u8 ep_num, static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
struct usb_ctrlrequest *setup) struct usb_ctrlrequest *setup)
__releases(&ep->udc->lock)
__acquires(&ep->udc->lock)
{ {
bool delegate = false; bool delegate = false;
@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc)
} }
} }
void irq_process_reset(struct mv_udc *udc) static void irq_process_reset(struct mv_udc *udc)
{ {
u32 tmp; u32 tmp;
unsigned int loops; unsigned int loops;
@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev)
mv_udc_disable(udc); mv_udc_disable(udc);
device_unregister(&udc->gadget.dev);
/* free dev, wait for the release() finished */ /* free dev, wait for the release() finished */
wait_for_completion(udc->done); wait_for_completion(udc->done);
@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev)
struct mv_usb_platform_data *pdata = pdev->dev.platform_data; struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
struct mv_udc *udc; struct mv_udc *udc;
int retval = 0; int retval = 0;
int clk_i = 0;
struct resource *r; struct resource *r;
size_t size; size_t size;
@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (udc == NULL) { if (udc == NULL) {
dev_err(&pdev->dev, "failed to allocate memory for udc\n"); dev_err(&pdev->dev, "failed to allocate memory for udc\n");
return -ENOMEM; return -ENOMEM;
@ -2173,27 +2123,25 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->dev = pdev; udc->dev = pdev;
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG) { if (pdata->mode == MV_USB_MODE_OTG) {
udc->transceiver = devm_usb_get_phy(&pdev->dev, udc->transceiver = devm_usb_get_phy(&pdev->dev,
USB_PHY_TYPE_USB2); USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(udc->transceiver)) { if (IS_ERR(udc->transceiver)) {
udc->transceiver = NULL; retval = PTR_ERR(udc->transceiver);
return -ENODEV;
}
}
#endif
udc->clknum = pdata->clknum; if (retval == -ENXIO)
for (clk_i = 0; clk_i < udc->clknum; clk_i++) { return retval;
udc->clk[clk_i] = devm_clk_get(&pdev->dev,
pdata->clkname[clk_i]); udc->transceiver = NULL;
if (IS_ERR(udc->clk[clk_i])) { return -EPROBE_DEFER;
retval = PTR_ERR(udc->clk[clk_i]);
return retval;
} }
} }
/* udc only have one sysclk. */
udc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(udc->clk))
return PTR_ERR(udc->clk);
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
if (r == NULL) { if (r == NULL) {
dev_err(&pdev->dev, "no I/O memory resource defined\n"); dev_err(&pdev->dev, "no I/O memory resource defined\n");
@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
/* the "gadget" abstracts/virtualizes the controller */ /* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&udc->gadget.dev, "gadget");
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 */ udc->gadget.name = driver_name; /* gadget name */
retval = device_register(&udc->gadget.dev);
if (retval)
goto err_destroy_dma;
eps_init(udc); eps_init(udc);
/* VBUS detect: we can disable/enable clock on demand.*/ /* VBUS detect: we can disable/enable clock on demand.*/
@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev)
if (!udc->qwork) { if (!udc->qwork) {
dev_err(&pdev->dev, "cannot create workqueue\n"); dev_err(&pdev->dev, "cannot create workqueue\n");
retval = -ENOMEM; retval = -ENOMEM;
goto err_unregister; goto err_destroy_dma;
} }
INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev)
else else
udc->vbus_active = 1; udc->vbus_active = 1;
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
gadget_release);
if (retval) if (retval)
goto err_create_workqueue; goto err_create_workqueue;
@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev)
err_create_workqueue: err_create_workqueue:
destroy_workqueue(udc->qwork); destroy_workqueue(udc->qwork);
err_unregister:
device_unregister(&udc->gadget.dev);
err_destroy_dma: err_destroy_dma:
dma_pool_destroy(udc->dtd_pool); dma_pool_destroy(udc->dtd_pool);
err_free_dma: err_free_dma:

View File

@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL, NULL,
}; };
struct eth_dev *the_dev;
static u8 hostaddr[ETH_ALEN]; static u8 hostaddr[ETH_ALEN];
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
return ncm_bind_config(c, hostaddr); return ncm_bind_config(c, hostaddr, the_dev);
} }
static struct usb_configuration ncm_config_driver = { static struct usb_configuration ncm_config_driver = {
@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
int status; int status;
/* set up network link layer */ /* set up network link layer */
status = gether_setup(cdev->gadget, hostaddr); the_dev = gether_setup(cdev->gadget, hostaddr);
if (status < 0) if (IS_ERR(the_dev))
return status; return PTR_ERR(the_dev);
/* Allocate string descriptor numbers ... note that string /* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue. * contents can be overridden by the composite_dev glue.
@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
return 0; return 0;
fail: fail:
gether_cleanup(); gether_cleanup(the_dev);
return status; return status;
} }
static int __exit gncm_unbind(struct usb_composite_dev *cdev) static int __exit gncm_unbind(struct usb_composite_dev *cdev)
{ {
gether_cleanup(); gether_cleanup(the_dev);
return 0; return 0;
} }

View File

@ -58,7 +58,6 @@ static const char * const ep_name[] = {
"ep-a", "ep-b", "ep-c", "ep-a", "ep-b", "ep-c",
}; };
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#ifdef CONFIG_USB_NET2272_DMA #ifdef CONFIG_USB_NET2272_DMA
/* /*
* use_dma: the NET2272 can use an external DMA controller. * use_dma: the NET2272 can use an external DMA controller.
@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req) if (!req)
return NULL; return NULL;
req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue); INIT_LIST_HEAD(&req->queue);
return &req->req; return &req->req;
@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
} }
} }
} }
if (likely(req != 0)) if (likely(req))
list_add_tail(&req->queue, &ep->queue); list_add_tail(&req->queue, &ep->queue);
if (likely(!list_empty(&ep->queue))) if (likely(!list_empty(&ep->queue)))
@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget,
dev->softconnect = 1; dev->softconnect = 1;
driver->driver.bus = NULL; driver->driver.bus = NULL;
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
/* ... then enable host detection and ep0; and we're ready /* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect. * for set_configuration as well as eventual disconnect.
@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget,
stop_activity(dev, driver); stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep)
| (ep->dev->dma_eot_polarity << EOT_POLARITY) | (ep->dev->dma_eot_polarity << EOT_POLARITY)
| (ep->dev->dma_dack_polarity << DACK_POLARITY) | (ep->dev->dma_dack_polarity << DACK_POLARITY)
| (ep->dev->dma_dreq_polarity << DREQ_POLARITY) | (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
| ((ep->dma >> 1) << DMA_ENDPOINT_SELECT)); | (ep->dma << DMA_ENDPOINT_SELECT));
ep->dev->dma_busy = 0; ep->dev->dma_busy = 0;
@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep)
ep->irqs++; ep->irqs++;
dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
ep->ep.name, stat0, stat1, req ? &req->req : 0); ep->ep.name, stat0, stat1, req ? &req->req : NULL);
net2272_ep_write(ep, EP_STAT0, stat0 & net2272_ep_write(ep, EP_STAT0, stat0 &
~((1 << NAK_OUT_PACKETS) ~((1 << NAK_OUT_PACKETS)
@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev)
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
iounmap(dev->base_addr); iounmap(dev->base_addr);
device_unregister(&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_registers); device_remove_file(dev->dev, &dev_attr_registers);
dev_info(dev->dev, "unbind\n"); dev_info(dev->dev, "unbind\n");
@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
ret->gadget.max_speed = USB_SPEED_HIGH; ret->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */ /* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&ret->gadget.dev, "gadget");
ret->gadget.dev.parent = dev;
ret->gadget.dev.dma_mask = dev->dma_mask;
ret->gadget.dev.release = net2272_gadget_release;
ret->gadget.name = driver_name; ret->gadget.name = driver_name;
return ret; return ret;
@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
dma_mode_string()); dma_mode_string());
dev_info(dev->dev, "version: %s\n", driver_vers); dev_info(dev->dev, "version: %s\n", driver_vers);
ret = device_register(&dev->gadget.dev);
if (ret)
goto err_irq;
ret = device_create_file(dev->dev, &dev_attr_registers); ret = device_create_file(dev->dev, &dev_attr_registers);
if (ret) if (ret)
goto err_dev_reg; goto err_irq;
ret = usb_add_gadget_udc(dev->dev, &dev->gadget); ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget,
net2272_gadget_release);
if (ret) if (ret)
goto err_add_udc; goto err_add_udc;
@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
err_add_udc: err_add_udc:
device_remove_file(dev->dev, &dev_attr_registers); device_remove_file(dev->dev, &dev_attr_registers);
err_dev_reg:
device_unregister(&dev->gadget.dev);
err_irq: err_irq:
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
err: err:

View File

@ -65,7 +65,6 @@
#define DRIVER_DESC "PLX NET228x USB Peripheral Controller" #define DRIVER_DESC "PLX NET228x USB Peripheral Controller"
#define DRIVER_VERSION "2005 Sept 27" #define DRIVER_VERSION "2005 Sept 27"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */ #define EP_DONTUSE 13 /* nonzero */
#define USE_RDK_LEDS /* GPIO pins control three LEDs */ #define USE_RDK_LEDS /* GPIO pins control three LEDs */
@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
if (!req) if (!req)
return NULL; return NULL;
req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD (&req->queue); INIT_LIST_HEAD (&req->queue);
/* this dma descriptor may be swapped with the previous dummy */ /* this dma descriptor may be swapped with the previous dummy */
@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
return NULL; return NULL;
} }
td->dmacount = 0; /* not VALID */ td->dmacount = 0; /* not VALID */
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr; td->dmadesc = td->dmaaddr;
req->td = td; req->td = td;
} }
@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget,
dev->softconnect = 1; dev->softconnect = 1;
driver->driver.bus = NULL; driver->driver.bus = NULL;
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
retval = device_create_file (&dev->pdev->dev, &dev_attr_function); retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
if (retval) goto err_unbind; if (retval) goto err_unbind;
@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,
err_func: err_func:
device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_function);
err_unbind: err_unbind:
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
return retval; return retval;
} }
@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget,
stop_activity (dev, driver); stop_activity (dev, driver);
spin_unlock_irqrestore (&dev->lock, flags); spin_unlock_irqrestore (&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
net2280_led_active (dev, 0); net2280_led_active (dev, 0);
@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep)
return; return;
/* manual DMA queue advance after short OUT */ /* manual DMA queue advance after short OUT */
if (likely (ep->dma != 0)) { if (likely (ep->dma)) {
if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
u32 count; u32 count;
int stopped = ep->stopped; int stopped = ep->stopped;
@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device and interface status */ /* hw handles device and interface status */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto delegate; goto delegate;
if ((e = get_ep_by_addr (dev, w_index)) == 0 if ((e = get_ep_by_addr (dev, w_index)) == NULL
|| w_length > 2) || w_length > 2)
goto do_stall; goto do_stall;
@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT if (w_value != USB_ENDPOINT_HALT
|| w_length != 0) || w_length != 0)
goto do_stall; goto do_stall;
if ((e = get_ep_by_addr (dev, w_index)) == 0) if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall; goto do_stall;
if (e->wedged) { if (e->wedged) {
VDEBUG(dev, "%s wedged, halt not cleared\n", VDEBUG(dev, "%s wedged, halt not cleared\n",
@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT if (w_value != USB_ENDPOINT_HALT
|| w_length != 0) || w_length != 0)
goto do_stall; goto do_stall;
if ((e = get_ep_by_addr (dev, w_index)) == 0) if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall; goto do_stall;
if (e->ep.name == ep0name) if (e->ep.name == ep0name)
goto do_stall; goto do_stall;
@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev)
pci_resource_len (pdev, 0)); pci_resource_len (pdev, 0));
if (dev->enabled) if (dev->enabled)
pci_disable_device (pdev); pci_disable_device (pdev);
device_unregister (&dev->gadget.dev);
device_remove_file (&pdev->dev, &dev_attr_registers); device_remove_file (&pdev->dev, &dev_attr_registers);
pci_set_drvdata (pdev, NULL); pci_set_drvdata (pdev, NULL);
@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_HIGH; dev->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */ /* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name; dev->gadget.name = driver_name;
/* now all the pci goodies ... */ /* now all the pci goodies ... */
@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
goto done; goto done;
} }
td->dmacount = 0; /* not VALID */ td->dmacount = 0; /* not VALID */
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr; td->dmadesc = td->dmaaddr;
dev->ep [i].dummy = td; dev->ep [i].dummy = td;
} }
@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
use_dma use_dma
? (use_dma_chaining ? "chaining" : "enabled") ? (use_dma_chaining ? "chaining" : "enabled")
: "disabled"); : "disabled");
retval = device_register (&dev->gadget.dev);
if (retval) goto done;
retval = device_create_file (&pdev->dev, &dev_attr_registers); retval = device_create_file (&pdev->dev, &dev_attr_registers);
if (retval) goto done; if (retval) goto done;
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
gadget_release);
if (retval) if (retval)
goto done; goto done;
return 0; return 0;

View File

@ -37,11 +37,9 @@
* the runtime footprint, and giving us at least some parts of what * the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would. * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/ */
#define USB_FACM_INCLUDED #define USBF_OBEX_INCLUDED
#include "f_acm.c"
#include "f_ecm.c" #include "f_ecm.c"
#include "f_obex.c" #include "f_obex.c"
#include "f_serial.c"
#include "f_phonet.c" #include "f_phonet.c"
#include "u_ether.c" #include "u_ether.c"
@ -98,45 +96,19 @@ MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_function *f_acm_cfg1;
static struct usb_function *f_acm_cfg2;
static u8 hostaddr[ETH_ALEN]; static u8 hostaddr[ETH_ALEN];
static struct eth_dev *the_dev;
enum { enum {
TTY_PORT_OBEX0, TTY_PORT_OBEX0,
TTY_PORT_OBEX1, TTY_PORT_OBEX1,
TTY_PORT_ACM,
TTY_PORTS_MAX, TTY_PORTS_MAX,
}; };
static unsigned char tty_lines[TTY_PORTS_MAX]; static unsigned char tty_lines[TTY_PORTS_MAX];
static int __init nokia_bind_config(struct usb_configuration *c)
{
int status = 0;
status = phonet_bind_config(c);
if (status)
printk(KERN_DEBUG "could not bind phonet config\n");
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, tty_lines[TTY_PORT_OBEX1]);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
if (status)
printk(KERN_DEBUG "could not bind acm config\n");
status = ecm_bind_config(c, hostaddr);
if (status)
printk(KERN_DEBUG "could not bind ecm config\n");
return status;
}
static struct usb_configuration nokia_config_500ma_driver = { static struct usb_configuration nokia_config_500ma_driver = {
.label = "Bus Powered", .label = "Bus Powered",
.bConfigurationValue = 1, .bConfigurationValue = 1,
@ -153,6 +125,51 @@ static struct usb_configuration nokia_config_100ma_driver = {
.MaxPower = 100, .MaxPower = 100,
}; };
static struct usb_function_instance *fi_acm;
static int __init nokia_bind_config(struct usb_configuration *c)
{
struct usb_function *f_acm;
int status = 0;
status = phonet_bind_config(c);
if (status)
printk(KERN_DEBUG "could not bind phonet config\n");
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, tty_lines[TTY_PORT_OBEX1]);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
f_acm = usb_get_function(fi_acm);
if (IS_ERR(f_acm))
return PTR_ERR(f_acm);
status = usb_add_function(c, f_acm);
if (status)
goto err_conf;
status = ecm_bind_config(c, hostaddr, the_dev);
if (status) {
pr_debug("could not bind ecm config %d\n", status);
goto err_ecm;
}
if (c == &nokia_config_500ma_driver)
f_acm_cfg1 = f_acm;
else
f_acm_cfg2 = f_acm;
return status;
err_ecm:
usb_remove_function(c, f_acm);
err_conf:
usb_put_function(f_acm);
return status;
}
static int __init nokia_bind(struct usb_composite_dev *cdev) static int __init nokia_bind(struct usb_composite_dev *cdev)
{ {
struct usb_gadget *gadget = cdev->gadget; struct usb_gadget *gadget = cdev->gadget;
@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
goto err_ether; goto err_ether;
} }
status = gether_setup(cdev->gadget, hostaddr); the_dev = gether_setup(cdev->gadget, hostaddr);
if (status < 0) if (IS_ERR(the_dev)) {
status = PTR_ERR(the_dev);
goto err_ether; goto err_ether;
}
status = usb_string_ids_tab(cdev, strings_dev); status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0) if (status < 0)
@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
if (!gadget_supports_altsettings(gadget)) if (!gadget_supports_altsettings(gadget))
goto err_usb; goto err_usb;
fi_acm = usb_get_function_instance("acm");
if (IS_ERR(fi_acm))
goto err_usb;
/* finally register the configuration */ /* finally register the configuration */
status = usb_add_config(cdev, &nokia_config_500ma_driver, status = usb_add_config(cdev, &nokia_config_500ma_driver,
nokia_bind_config); nokia_bind_config);
if (status < 0) if (status < 0)
goto err_usb; goto err_acm_inst;
status = usb_add_config(cdev, &nokia_config_100ma_driver, status = usb_add_config(cdev, &nokia_config_100ma_driver,
nokia_bind_config); nokia_bind_config);
if (status < 0) if (status < 0)
goto err_usb; goto err_put_cfg1;
usb_composite_overwrite_options(cdev, &coverwrite); usb_composite_overwrite_options(cdev, &coverwrite);
dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
return 0; return 0;
err_put_cfg1:
usb_put_function(f_acm_cfg1);
err_acm_inst:
usb_put_function_instance(fi_acm);
err_usb: err_usb:
gether_cleanup(); gether_cleanup(the_dev);
err_ether: err_ether:
cur_line--; cur_line--;
while (cur_line >= 0) while (cur_line >= 0)
@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{ {
int i; int i;
usb_put_function(f_acm_cfg1);
usb_put_function(f_acm_cfg2);
usb_put_function_instance(fi_acm);
gphonet_cleanup(); gphonet_cleanup();
for (i = 0; i < TTY_PORTS_MAX; i++) for (i = 0; i < TTY_PORTS_MAX; i++)
gserial_free_line(tty_lines[i]); gserial_free_line(tty_lines[i]);
gether_cleanup(); gether_cleanup(the_dev);
return 0; return 0;
} }
@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void)
usb_composite_unregister(&nokia_driver); usb_composite_unregister(&nokia_driver);
} }
module_exit(nokia_cleanup); module_exit(nokia_cleanup);

View File

@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g,
/* hook up the driver */ /* hook up the driver */
driver->driver.bus = NULL; driver->driver.bus = NULL;
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
if (udc->dc_clk != NULL) if (udc->dc_clk != NULL)
@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g,
ERR("can't bind to transceiver\n"); ERR("can't bind to transceiver\n");
if (driver->unbind) { if (driver->unbind) {
driver->unbind(&udc->gadget); driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
} }
goto done; goto done;
@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g,
udc_quiesce(udc); udc_quiesce(udc);
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
udc->gadget.dev.driver = NULL;
udc->driver = NULL; udc->driver = NULL;
if (udc->dc_clk != NULL) if (udc->dc_clk != NULL)
@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
udc->gadget.speed = USB_SPEED_UNKNOWN; udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_FULL; udc->gadget.max_speed = USB_SPEED_FULL;
udc->gadget.name = driver_name; udc->gadget.name = driver_name;
device_initialize(&udc->gadget.dev);
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.dev.release = omap_udc_release;
udc->gadget.dev.parent = &odev->dev;
if (use_dma)
udc->gadget.dev.dma_mask = odev->dev.dma_mask;
udc->transceiver = xceiv; udc->transceiver = xceiv;
/* ep0 is special; put it right after the SETUP buffer */ /* ep0 is special; put it right after the SETUP buffer */
@ -2912,14 +2901,13 @@ static int omap_udc_probe(struct platform_device *pdev)
} }
create_proc_file(); create_proc_file();
status = device_add(&udc->gadget.dev); status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
omap_udc_release);
if (status) if (status)
goto cleanup4; goto cleanup4;
status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); return 0;
if (!status)
return status;
/* If fail, fall through */
cleanup4: cleanup4:
remove_proc_file(); remove_proc_file();
@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev)
release_mem_region(pdev->resource[0].start, release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1); pdev->resource[0].end - pdev->resource[0].start + 1);
device_unregister(&udc->gadget.dev);
wait_for_completion(&done); wait_for_completion(&done);
return 0; return 0;

View File

@ -358,7 +358,6 @@ struct pch_udc_dev {
prot_stall:1, prot_stall:1,
irq_registered:1, irq_registered:1,
mem_region:1, mem_region:1,
registered:1,
suspended:1, suspended:1,
connected:1, connected:1,
vbus_session:1, vbus_session:1,
@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
*/ */
static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
int status) int status)
__releases(&dev->lock)
__acquires(&dev->lock)
{ {
struct pch_udc_dev *dev; struct pch_udc_dev *dev;
unsigned halted = ep->halted; unsigned halted = ep->halted;
@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
* @dev: Reference to the device structure * @dev: Reference to the device structure
*/ */
static void pch_udc_svc_control_out(struct pch_udc_dev *dev) static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
__releases(&dev->lock)
__acquires(&dev->lock)
{ {
u32 stat; u32 stat;
int setup_supported; int setup_supported;
@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL; driver->driver.bus = NULL;
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
/* get ready for ep0 traffic */ /* get ready for ep0 traffic */
pch_udc_setup_ep0(dev); pch_udc_setup_ep0(dev);
@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g,
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
/* Assures that there are no pending requests with this driver */ /* Assures that there are no pending requests with this driver */
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
dev->connected = 0; dev->connected = 0;
@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev)
pci_resource_len(pdev, PCH_UDC_PCI_BAR)); pci_resource_len(pdev, PCH_UDC_PCI_BAR));
if (dev->active) if (dev->active)
pci_disable_device(pdev); pci_disable_device(pdev);
if (dev->registered)
device_unregister(&dev->gadget.dev);
kfree(dev); kfree(dev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
} }
@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev,
if (retval) if (retval)
goto finished; goto finished;
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
dev->gadget.dev.release = gadget_release;
dev->gadget.name = KBUILD_MODNAME; dev->gadget.name = KBUILD_MODNAME;
dev->gadget.max_speed = USB_SPEED_HIGH; dev->gadget.max_speed = USB_SPEED_HIGH;
retval = device_register(&dev->gadget.dev);
if (retval)
goto finished;
dev->registered = 1;
/* Put the device in disconnected state till a driver is bound */ /* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev); pch_udc_set_disconnect(dev);
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
gadget_release);
if (retval) if (retval)
goto finished; goto finished;
return 0; return 0;

View File

@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */ /* first hook up the driver ... */
dev->driver = driver; dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1; dev->pullup = 1;
/* ... then enable host detection and ep0; and we're ready /* ... then enable host detection and ep0; and we're ready
@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g,
if (!IS_ERR_OR_NULL(dev->transceiver)) if (!IS_ERR_OR_NULL(dev->transceiver))
(void) otg_set_peripheral(dev->transceiver->otg, NULL); (void) otg_set_peripheral(dev->transceiver->otg, NULL);
dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
dump_state(dev); dump_state(dev);
@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->timer.function = udc_watchdog; dev->timer.function = udc_watchdog;
dev->timer.data = (unsigned long) dev; dev->timer.data = (unsigned long) dev;
device_initialize(&dev->gadget.dev);
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
retval = device_add(&dev->gadget.dev);
if (retval) {
dev->driver = NULL;
dev->gadget.dev.driver = NULL;
goto err_device_add;
}
the_controller = dev; the_controller = dev;
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
@ -2199,8 +2186,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
free_irq(irq, dev); free_irq(irq, dev);
#endif #endif
err_irq1: err_irq1:
device_unregister(&dev->gadget.dev);
err_device_add:
if (gpio_is_valid(dev->mach->gpio_pullup)) if (gpio_is_valid(dev->mach->gpio_pullup))
gpio_free(dev->mach->gpio_pullup); gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup: err_gpio_pullup:
@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
return -EBUSY; return -EBUSY;
usb_del_gadget_udc(&dev->gadget); usb_del_gadget_udc(&dev->gadget);
device_unregister(&dev->gadget.dev);
dev->pullup = 0; dev->pullup = 0;
pullup(dev); pullup(dev);

View File

@ -24,14 +24,12 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/byteorder/generic.h>
#include <asm/byteorder.h> #include <linux/platform_data/pxa2xx_udc.h>
#include <mach/hardware.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <mach/udc.h>
#include "pxa27x_udc.h" #include "pxa27x_udc.h"
@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
* *
* Find the physical pxa27x ep, and setup its UDCCR * Find the physical pxa27x ep, and setup its UDCCR
*/ */
static __init void pxa_ep_setup(struct pxa_ep *ep) static void pxa_ep_setup(struct pxa_ep *ep)
{ {
u32 new_udccr; u32 new_udccr;
@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep)
* *
* Setup all pxa physical endpoints, except ep0 * Setup all pxa physical endpoints, except ep0
*/ */
static __init void pxa_eps_setup(struct pxa_udc *dev) static void pxa_eps_setup(struct pxa_udc *dev)
{ {
unsigned int i; unsigned int i;
@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc)
* Initializes gadget endpoint list, endpoints locks. No action is taken * Initializes gadget endpoint list, endpoints locks. No action is taken
* on the hardware. * on the hardware.
*/ */
static __init void udc_init_data(struct pxa_udc *dev) static void udc_init_data(struct pxa_udc *dev)
{ {
int i; int i;
struct pxa_ep *ep; struct pxa_ep *ep;
@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */ /* first hook up the driver ... */
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
dplus_pullup(udc, 1); dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) { if (!IS_ERR_OR_NULL(udc->transceiver)) {
@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
fail: fail:
udc->driver = NULL; udc->driver = NULL;
udc->gadget.dev.driver = NULL;
return retval; return retval;
} }
@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g,
udc->driver = NULL; udc->driver = NULL;
if (!IS_ERR_OR_NULL(udc->transceiver)) if (!IS_ERR_OR_NULL(udc->transceiver))
return otg_set_peripheral(udc->transceiver->otg, NULL); return otg_set_peripheral(udc->transceiver->otg, NULL);
return 0; return 0;
@ -2413,7 +2408,7 @@ static struct pxa_udc memory = {
* Perform basic init : allocates udc clock, creates sysfs files, requests * Perform basic init : allocates udc clock, creates sysfs files, requests
* irq. * irq.
*/ */
static int __init pxa_udc_probe(struct platform_device *pdev) static int pxa_udc_probe(struct platform_device *pdev)
{ {
struct resource *regs; struct resource *regs;
struct pxa_udc *udc = &memory; struct pxa_udc *udc = &memory;
@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_map; goto err_map;
} }
device_initialize(&udc->gadget.dev);
udc->gadget.dev.parent = &pdev->dev;
udc->gadget.dev.dma_mask = NULL;
udc->vbus_sensed = 0; udc->vbus_sensed = 0;
the_controller = udc; the_controller = udc;
@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_irq; goto err_irq;
} }
retval = device_add(&udc->gadget.dev);
if (retval) {
dev_err(udc->dev, "device_add error %d\n", retval);
goto err_dev_add;
}
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval) if (retval)
goto err_add_udc; goto err_add_udc;
@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
return 0; return 0;
err_add_udc: err_add_udc:
device_unregister(&udc->gadget.dev);
err_dev_add:
free_irq(udc->irq, udc); free_irq(udc->irq, udc);
err_irq: err_irq:
iounmap(udc->regs); iounmap(udc->regs);
@ -2506,13 +2490,12 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
* pxa_udc_remove - removes the udc device driver * pxa_udc_remove - removes the udc device driver
* @_dev: platform device * @_dev: platform device
*/ */
static int __exit pxa_udc_remove(struct platform_device *_dev) static int pxa_udc_remove(struct platform_device *_dev)
{ {
struct pxa_udc *udc = platform_get_drvdata(_dev); struct pxa_udc *udc = platform_get_drvdata(_dev);
int gpio = udc->mach->gpio_pullup; int gpio = udc->mach->gpio_pullup;
usb_del_gadget_udc(&udc->gadget); usb_del_gadget_udc(&udc->gadget);
device_del(&udc->gadget.dev);
usb_gadget_unregister_driver(udc->driver); usb_gadget_unregister_driver(udc->driver);
free_irq(udc->irq, udc); free_irq(udc->irq, udc);
pxa_cleanup_debugfs(udc); pxa_cleanup_debugfs(udc);
@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = {
.name = "pxa27x-udc", .name = "pxa27x-udc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.remove = __exit_p(pxa_udc_remove), .probe = pxa_udc_probe,
.remove = pxa_udc_remove,
.shutdown = pxa_udc_shutdown, .shutdown = pxa_udc_shutdown,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = pxa_udc_suspend, .suspend = pxa_udc_suspend,
@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = {
#endif #endif
}; };
static int __init udc_init(void) module_platform_driver(udc_driver);
{
if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
return -ENODEV;
printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
return platform_driver_probe(&udc_driver, pxa_udc_probe);
}
module_init(udc_init);
static void __exit udc_exit(void)
{
platform_driver_unregister(&udc_driver);
}
module_exit(udc_exit);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Robert Jarzmik"); MODULE_AUTHOR("Robert Jarzmik");

View File

@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
clk_put(r8a66597->clk); clk_put(r8a66597->clk);
} }
device_unregister(&r8a66597->gadget.dev);
kfree(r8a66597); kfree(r8a66597);
return 0; return 0;
} }
@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
r8a66597->gadget.ops = &r8a66597_gadget_ops; r8a66597->gadget.ops = &r8a66597_gadget_ops;
dev_set_name(&r8a66597->gadget.dev, "gadget");
r8a66597->gadget.max_speed = USB_SPEED_HIGH; r8a66597->gadget.max_speed = USB_SPEED_HIGH;
r8a66597->gadget.dev.parent = &pdev->dev;
r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
r8a66597->gadget.dev.release = pdev->dev.release;
r8a66597->gadget.name = udc_name; r8a66597->gadget.name = udc_name;
ret = device_register(&r8a66597->gadget.dev);
if (ret < 0) {
dev_err(&pdev->dev, "device_register failed\n");
goto clean_up;
}
init_timer(&r8a66597->timer); init_timer(&r8a66597->timer);
r8a66597->timer.function = r8a66597_timer; r8a66597->timer.function = r8a66597_timer;
@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
clk_name); clk_name);
ret = PTR_ERR(r8a66597->clk); ret = PTR_ERR(r8a66597->clk);
goto clean_up_dev; goto clean_up;
} }
clk_enable(r8a66597->clk); clk_enable(r8a66597->clk);
} }
@ -2007,8 +1997,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
clk_disable(r8a66597->clk); clk_disable(r8a66597->clk);
clk_put(r8a66597->clk); clk_put(r8a66597->clk);
} }
clean_up_dev:
device_unregister(&r8a66597->gadget.dev);
clean_up: clean_up:
if (r8a66597) { if (r8a66597) {
if (r8a66597->sudmac_reg) if (r8a66597->sudmac_reg)

View File

@ -39,8 +39,6 @@
#include "s3c-hsotg.h" #include "s3c-hsotg.h"
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
static const char * const s3c_hsotg_supply_names[] = { static const char * const s3c_hsotg_supply_names[] = {
"vusb_d", /* digital USB supply, 1.2V */ "vusb_d", /* digital USB supply, 1.2V */
"vusb_a", /* analog USB supply, 1.1V */ "vusb_a", /* analog USB supply, 1.1V */
@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
INIT_LIST_HEAD(&req->queue); INIT_LIST_HEAD(&req->queue);
req->req.dma = DMA_ADDR_INVALID;
return &req->req; return &req->req;
} }
@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_req *hs_req) struct s3c_hsotg_req *hs_req)
{ {
struct usb_request *req = &hs_req->req; struct usb_request *req = &hs_req->req;
enum dma_data_direction dir;
dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
/* ignore this if we're not moving any data */ /* ignore this if we're not moving any data */
if (hs_req->req.length == 0) if (hs_req->req.length == 0)
return; return;
if (hs_req->mapped) { usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
/* we mapped this, so unmap and remove the dma */
dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
req->dma = DMA_ADDR_INVALID;
hs_req->mapped = 0;
} else {
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
}
} }
/** /**
@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_ep *hs_ep,
struct usb_request *req) struct usb_request *req)
{ {
enum dma_data_direction dir;
struct s3c_hsotg_req *hs_req = our_req(req); struct s3c_hsotg_req *hs_req = our_req(req);
int ret;
dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
/* if the length is zero, ignore the DMA data */ /* if the length is zero, ignore the DMA data */
if (hs_req->req.length == 0) if (hs_req->req.length == 0)
return 0; return 0;
if (req->dma == DMA_ADDR_INVALID) { ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
dma_addr_t dma; if (ret)
goto dma_error;
dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
if (unlikely(dma_mapping_error(hsotg->dev, dma)))
goto dma_error;
if (dma & 3) {
dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
__func__);
dma_unmap_single(hsotg->dev, dma, req->length, dir);
return -EINVAL;
}
hs_req->mapped = 1;
req->dma = dma;
} else {
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
hs_req->mapped = 0;
}
return 0; return 0;
@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
driver->driver.bus = NULL; driver->driver.bus = NULL;
hsotg->driver = driver; hsotg->driver = driver;
hsotg->gadget.dev.driver = &driver->driver;
hsotg->gadget.dev.of_node = hsotg->dev->of_node; hsotg->gadget.dev.of_node = hsotg->dev->of_node;
hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
hsotg->gadget.speed = USB_SPEED_UNKNOWN; hsotg->gadget.speed = USB_SPEED_UNKNOWN;
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
err: err:
hsotg->driver = NULL; hsotg->driver = NULL;
hsotg->gadget.dev.driver = NULL;
return ret; return ret;
} }
@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
hsotg->driver = NULL; hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN; hsotg->gadget.speed = USB_SPEED_UNKNOWN;
hsotg->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
@ -3483,16 +3443,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
debugfs_remove(hsotg->debug_root); debugfs_remove(hsotg->debug_root);
} }
/**
* s3c_hsotg_release - release callback for hsotg device
* @dev: Device to for which release is called
*
* Nothing to do as the resource is allocated using devm_ API.
*/
static void s3c_hsotg_release(struct device *dev)
{
}
/** /**
* s3c_hsotg_probe - probe function for hsotg driver * s3c_hsotg_probe - probe function for hsotg driver
* @pdev: The platform information for the driver * @pdev: The platform information for the driver
@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
} }
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(phy)) { if (IS_ERR(phy)) {
/* Fallback for pdata */ /* Fallback for pdata */
plat = pdev->dev.platform_data; plat = pdev->dev.platform_data;
if (!plat) { if (!plat) {
@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
device_initialize(&hsotg->gadget.dev);
dev_set_name(&hsotg->gadget.dev, "gadget");
hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev); hsotg->gadget.name = dev_name(dev);
hsotg->gadget.dev.parent = dev;
hsotg->gadget.dev.dma_mask = dev->dma_mask;
hsotg->gadget.dev.release = s3c_hsotg_release;
/* reset the system */ /* reset the system */
clk_prepare_enable(hsotg->clk); clk_prepare_enable(hsotg->clk);
@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
s3c_hsotg_phy_disable(hsotg); s3c_hsotg_phy_disable(hsotg);
ret = device_add(&hsotg->gadget.dev);
if (ret) {
put_device(&hsotg->gadget.dev);
goto err_ep_mem;
}
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret) if (ret)
goto err_ep_mem; goto err_ep_mem;
@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
} }
s3c_hsotg_phy_disable(hsotg); s3c_hsotg_phy_disable(hsotg);
clk_disable_unprepare(hsotg->clk); clk_disable_unprepare(hsotg->clk);
device_unregister(&hsotg->gadget.dev);
return 0; return 0;
} }

View File

@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
/** /**
* s3c_hsudc_stop_activity - Stop activity on all endpoints. * s3c_hsudc_stop_activity - Stop activity on all endpoints.
* @hsudc: Device controller for which EP activity is to be stopped. * @hsudc: Device controller for which EP activity is to be stopped.
* @driver: Reference to the gadget driver which is currently active.
* *
* All the endpoints are stopped and any pending transfer requests if any on * All the endpoints are stopped and any pending transfer requests if any on
* the endpoint are terminated. * the endpoint are terminated.
@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
return -EBUSY; return -EBUSY;
hsudc->driver = driver; hsudc->driver = driver;
hsudc->gadget.dev.driver = &driver->driver;
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
hsudc->supplies); hsudc->supplies);
@ -1190,7 +1188,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies: err_supplies:
hsudc->driver = NULL; hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
return ret; return ret;
} }
@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&hsudc->lock, flags); spin_lock_irqsave(&hsudc->lock, flags);
hsudc->driver = NULL; hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN; hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy(); s3c_hsudc_uninit_phy();
@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
spin_lock_init(&hsudc->lock); spin_lock_init(&hsudc->lock);
dev_set_name(&hsudc->gadget.dev, "gadget");
hsudc->gadget.max_speed = USB_SPEED_HIGH; hsudc->gadget.max_speed = USB_SPEED_HIGH;
hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
hsudc->gadget.name = dev_name(dev); hsudc->gadget.name = dev_name(dev);
hsudc->gadget.dev.parent = dev;
hsudc->gadget.dev.dma_mask = dev->dma_mask;
hsudc->gadget.ep0 = &hsudc->ep[0].ep; hsudc->gadget.ep0 = &hsudc->ep[0].ep;
hsudc->gadget.is_otg = 0; hsudc->gadget.is_otg = 0;
hsudc->gadget.is_a_peripheral = 0; hsudc->gadget.is_a_peripheral = 0;
hsudc->gadget.speed = USB_SPEED_UNKNOWN; hsudc->gadget.speed = USB_SPEED_UNKNOWN;
@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
disable_irq(hsudc->irq); disable_irq(hsudc->irq);
local_irq_enable(); local_irq_enable();
ret = device_register(&hsudc->gadget.dev);
if (ret) {
put_device(&hsudc->gadget.dev);
goto err_add_device;
}
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
if (ret) if (ret)
goto err_add_udc; goto err_add_udc;
@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
return 0; return 0;
err_add_udc: err_add_udc:
device_unregister(&hsudc->gadget.dev);
err_add_device: err_add_device:
clk_disable(hsudc->uclk); clk_disable(hsudc->uclk);
err_res: err_res:

View File

@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g,
/* Hook the driver */ /* Hook the driver */
udc->driver = driver; udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
/* Enable udc */ /* Enable udc */
s3c2410_udc_enable(udc); s3c2410_udc_enable(udc);
@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
goto err_mem; goto err_mem;
} }
device_initialize(&udc->gadget.dev);
udc->gadget.dev.parent = &pdev->dev;
udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
/* Bind the driver */
retval = device_add(&udc->gadget.dev);
if (retval) {
dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
goto err_device_add;
}
the_controller = udc; the_controller = udc;
platform_set_drvdata(pdev, udc); platform_set_drvdata(pdev, udc);
@ -1923,8 +1911,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
err_int: err_int:
free_irq(IRQ_USBD, udc); free_irq(IRQ_USBD, udc);
err_map: err_map:
device_unregister(&udc->gadget.dev);
err_device_add:
iounmap(base_addr); iounmap(base_addr);
err_mem: err_mem:
release_mem_region(rsrc_start, rsrc_len); release_mem_region(rsrc_start, rsrc_len);
@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
return -EBUSY; return -EBUSY;
usb_del_gadget_udc(&udc->gadget); usb_del_gadget_udc(&udc->gadget);
device_unregister(&udc->gadget.dev);
debugfs_remove(udc->regs_info); debugfs_remove(udc->regs_info);
if (udc_info && !udc_info->udc_command && if (udc_info && !udc_info->udc_command &&

View File

@ -12,6 +12,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
@ -27,18 +28,6 @@
#define GS_LONG_NAME "Gadget Serial" #define GS_LONG_NAME "Gadget Serial"
#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR #define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
/*-------------------------------------------------------------------------*/
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
* separate compilation ... ensuring init/exit sections work to shrink
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "f_obex.c"
#include "f_serial.c"
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS(); USB_GADGET_COMPOSITE_OPTIONS();
@ -126,27 +115,6 @@ module_param(n_ports, uint, 0);
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
static int __init serial_bind_obex_config(struct usb_configuration *c)
{
unsigned i;
int status = 0;
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;
}
static struct usb_configuration serial_config_driver = { static struct usb_configuration serial_config_driver = {
/* .label = f(use_acm) */ /* .label = f(use_acm) */
@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
goto out; goto out;
for (i = 0; i < n_ports; i++) { for (i = 0; i < n_ports; i++) {
struct f_serial_opts *opts;
fi_serial[i] = usb_get_function_instance(f_name); fi_serial[i] = usb_get_function_instance(f_name);
if (IS_ERR(fi_serial[i])) { if (IS_ERR(fi_serial[i])) {
ret = PTR_ERR(fi_serial[i]); ret = PTR_ERR(fi_serial[i]);
goto fail; 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]); f_serial[i] = usb_get_function(fi_serial[i]);
if (IS_ERR(f_serial[i])) { if (IS_ERR(f_serial[i])) {
@ -212,13 +177,6 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
static int __init gs_bind(struct usb_composite_dev *cdev) static int __init gs_bind(struct usb_composite_dev *cdev)
{ {
int status; int status;
int cur_line;
for (cur_line = 0; cur_line < n_ports; cur_line++) {
status = gserial_alloc_line(&tty_lines[cur_line]);
if (status)
goto fail;
}
/* Allocate string descriptor numbers ... note that string /* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue. * contents can be overridden by the composite_dev glue.
@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
"acm"); "acm");
usb_ep_autoconfig_reset(cdev->gadget); usb_ep_autoconfig_reset(cdev->gadget);
} else if (use_obex) } else if (use_obex)
status = usb_add_config(cdev, &serial_config_driver, status = serial_register_ports(cdev, &serial_config_driver,
serial_bind_obex_config); "obex");
else else {
status = usb_add_config(cdev, &serial_config_driver, status = serial_register_ports(cdev, &serial_config_driver,
serial_bind_gser_config); "gser");
}
if (status < 0) if (status < 0)
goto fail; goto fail;
@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
return 0; return 0;
fail: fail:
cur_line--;
while (cur_line >= 0)
gserial_free_line(tty_lines[cur_line--]);
return status; return status;
} }
@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev)
for (i = 0; i < n_ports; i++) { for (i = 0; i < n_ports; i++) {
usb_put_function(f_serial[i]); usb_put_function(f_serial[i]);
usb_put_function_instance(fi_serial[i]); usb_put_function_instance(fi_serial[i]);
gserial_free_line(tty_lines[i]);
} }
return 0; return 0;
} }

View File

@ -50,7 +50,6 @@
struct eth_dev { struct eth_dev {
/* lock is held while accessing port_usb /* lock is held while accessing port_usb
* or updating its backlink port_usb->ioport
*/ */
spinlock_t lock; spinlock_t lock;
struct gether *port_usb; struct gether *port_usb;
@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
return 1; return 1;
} }
static struct eth_dev *the_dev;
static const struct net_device_ops eth_netdev_ops = { static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open, .ndo_open = eth_open,
.ndo_stop = eth_stop, .ndo_stop = eth_stop,
@ -758,19 +755,16 @@ static struct device_type gadget_type = {
* *
* Returns negative errno, or zero on success * Returns negative errno, or zero on success
*/ */
int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname) const char *netname)
{ {
struct eth_dev *dev; struct eth_dev *dev;
struct net_device *net; struct net_device *net;
int status; int status;
if (the_dev)
return -EBUSY;
net = alloc_etherdev(sizeof *dev); net = alloc_etherdev(sizeof *dev);
if (!net) if (!net)
return -ENOMEM; return ERR_PTR(-ENOMEM);
dev = netdev_priv(net); dev = netdev_priv(net);
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
if (status < 0) { if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status); dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
free_netdev(net); free_netdev(net);
dev = ERR_PTR(status);
} else { } else {
INFO(dev, "MAC %pM\n", net->dev_addr); INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac); INFO(dev, "HOST MAC %pM\n", dev->host_mac);
the_dev = dev;
/* two kinds of host-initiated state changes: /* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on" * - iff DATA transfer is active, carrier is "on"
* - tx queueing enabled if open *and* carrier is "on" * - tx queueing enabled if open *and* carrier is "on"
@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
netif_carrier_off(net); netif_carrier_off(net);
} }
return status; return dev;
} }
/** /**
@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
* *
* This is called to free all resources allocated by @gether_setup(). * This is called to free all resources allocated by @gether_setup().
*/ */
void gether_cleanup(void) void gether_cleanup(struct eth_dev *dev)
{ {
if (!the_dev) if (!dev)
return; return;
unregister_netdev(the_dev->net); unregister_netdev(dev->net);
flush_work(&the_dev->work); flush_work(&dev->work);
free_netdev(the_dev->net); free_netdev(dev->net);
the_dev = NULL;
} }
/** /**
* gether_connect - notify network layer that USB link is active * gether_connect - notify network layer that USB link is active
* @link: the USB link, set up with endpoints, descriptors matching * @link: the USB link, set up with endpoints, descriptors matching
@ -860,7 +850,7 @@ void gether_cleanup(void)
*/ */
struct net_device *gether_connect(struct gether *link) struct net_device *gether_connect(struct gether *link)
{ {
struct eth_dev *dev = the_dev; struct eth_dev *dev = link->ioport;
int result = 0; int result = 0;
if (!dev) if (!dev)
@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link)
spin_lock(&dev->lock); spin_lock(&dev->lock);
dev->port_usb = link; dev->port_usb = link;
link->ioport = dev;
if (netif_running(dev->net)) { if (netif_running(dev->net)) {
if (link->open) if (link->open)
link->open(link); link->open(link);
@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->lock); spin_lock(&dev->lock);
dev->port_usb = NULL; dev->port_usb = NULL;
link->ioport = NULL;
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
} }

View File

@ -21,6 +21,7 @@
#include "gadget_chips.h" #include "gadget_chips.h"
struct eth_dev;
/* /*
* This represents the USB side of an "ethernet" link, managed by a USB * This represents the USB side of an "ethernet" link, managed by a USB
@ -70,7 +71,7 @@ struct gether {
|USB_CDC_PACKET_TYPE_DIRECTED) |USB_CDC_PACKET_TYPE_DIRECTED)
/* variant of gether_setup that allows customizing network device name */ /* variant of gether_setup that allows customizing network device name */
int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname); const char *netname);
/* netdev setup/teardown as directed by the gadget driver */ /* netdev setup/teardown as directed by the gadget driver */
@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
* *
* Returns negative errno, or zero on success * Returns negative errno, or zero on success
*/ */
static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) static inline struct eth_dev *gether_setup(struct usb_gadget *g,
u8 ethaddr[ETH_ALEN])
{ {
return gether_setup_name(g, ethaddr, "usb"); return gether_setup_name(g, ethaddr, "usb");
} }
void gether_cleanup(void); void gether_cleanup(struct eth_dev *dev);
/* connect/disconnect is handled by individual functions */ /* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *); struct net_device *gether_connect(struct gether *);
@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
} }
/* each configuration may bind one instance of an ethernet link */ /* each configuration may bind one instance of an ethernet link */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); struct eth_dev *dev);
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
int eem_bind_config(struct usb_configuration *c); struct eth_dev *dev);
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
struct eth_dev *dev);
int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
#ifdef USB_ETH_RNDIS #ifdef USB_ETH_RNDIS
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer); u32 vendorID, const char *manufacturer, struct eth_dev *dev);
#else #else
static inline int static inline int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer) u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{ {
return 0; return 0;
} }
@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
* for calling @gether_cleanup() before module unload. * for calling @gether_cleanup() before module unload.
*/ */
static inline int rndis_bind_config(struct usb_configuration *c, static inline int rndis_bind_config(struct usb_configuration *c,
u8 ethaddr[ETH_ALEN]) u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
{ {
return rndis_bind_config_vendor(c, ethaddr, 0, NULL); return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
} }

View File

@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num);
void gserial_disconnect(struct gserial *); void gserial_disconnect(struct gserial *);
/* functions are bound to configurations by a config or gadget driver */ /* functions are bound to configurations by a config or gadget driver */
int acm_bind_config(struct usb_configuration *c, u8 port_num);
int gser_bind_config(struct usb_configuration *c, u8 port_num); int gser_bind_config(struct usb_configuration *c, u8 port_num);
int obex_bind_config(struct usb_configuration *c, u8 port_num); int obex_bind_config(struct usb_configuration *c, u8 port_num);

View File

@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
void usb_gadget_set_state(struct usb_gadget *gadget,
enum usb_device_state state)
{
gadget->state = state;
sysfs_notify(&gadget->dev.kobj, NULL, "status");
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
/* ------------------------------------------------------------------------- */
/** /**
* usb_gadget_udc_start - tells usb device controller to start up * usb_gadget_udc_start - tells usb device controller to start up
* @gadget: The gadget we want to get started * @gadget: The gadget we want to get started
@ -156,6 +166,87 @@ static void usb_udc_release(struct device *dev)
} }
static const struct attribute_group *usb_udc_attr_groups[]; static const struct attribute_group *usb_udc_attr_groups[];
static void usb_udc_nop_release(struct device *dev)
{
dev_vdbg(dev, "%s\n", __func__);
}
/**
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be added to the list.
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM;
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
if (!udc)
goto err1;
dev_set_name(&gadget->dev, "gadget");
gadget->dev.parent = parent;
dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
gadget->dev.dma_parms = parent->dma_parms;
gadget->dev.dma_mask = parent->dma_mask;
if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release;
ret = device_register(&gadget->dev);
if (ret)
goto err2;
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err3;
udc->gadget = gadget;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
ret = device_add(&udc->dev);
if (ret)
goto err4;
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
mutex_unlock(&udc_lock);
return 0;
err4:
list_del(&udc->list);
mutex_unlock(&udc_lock);
err3:
put_device(&udc->dev);
err2:
put_device(&gadget->dev);
kfree(udc);
err1:
return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
/** /**
* usb_add_gadget_udc - adds a new gadget to the udc class driver list * usb_add_gadget_udc - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller * @parent: the parent device to this udc. Usually the controller
@ -166,43 +257,7 @@ static const struct attribute_group *usb_udc_attr_groups[];
*/ */
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{ {
struct usb_udc *udc; return usb_add_gadget_udc_release(parent, gadget, NULL);
int ret = -ENOMEM;
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
if (!udc)
goto err1;
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err2;
udc->gadget = gadget;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
ret = device_add(&udc->dev);
if (ret)
goto err3;
mutex_unlock(&udc_lock);
return 0;
err3:
list_del(&udc->list);
mutex_unlock(&udc_lock);
err2:
put_device(&udc->dev);
err1:
return ret;
} }
EXPORT_SYMBOL_GPL(usb_add_gadget_udc); EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
udc->driver = NULL; udc->driver = NULL;
udc->dev.driver = NULL; udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
} }
/** /**
@ -254,6 +310,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
device_unregister(&udc->dev); device_unregister(&udc->dev);
device_unregister(&gadget->dev);
} }
EXPORT_SYMBOL_GPL(usb_del_gadget_udc); EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->driver = driver; udc->driver = driver;
udc->dev.driver = &driver->driver; udc->dev.driver = &driver->driver;
udc->gadget->dev.driver = &driver->driver;
ret = driver->bind(udc->gadget, driver); ret = driver->bind(udc->gadget, driver);
if (ret) if (ret)
@ -286,6 +344,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->driver->function, ret); udc->driver->function, ret);
udc->driver = NULL; udc->driver = NULL;
udc->dev.driver = NULL; udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
return ret; return ret;
} }
@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
} }
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
static ssize_t usb_gadget_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
struct usb_gadget *gadget = udc->gadget;
return sprintf(buf, "%s\n", usb_state_string(gadget->state));
}
static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
#define USB_UDC_SPEED_ATTR(name, param) \ #define USB_UDC_SPEED_ATTR(name, param) \
ssize_t usb_udc_##param##_show(struct device *dev, \ ssize_t usb_udc_##param##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev, \
return snprintf(buf, PAGE_SIZE, "%s\n", \ return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \ usb_speed_string(udc->gadget->param)); \
} \ } \
static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
static USB_UDC_SPEED_ATTR(current_speed, speed); static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support);
static struct attribute *usb_udc_attrs[] = { static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr, &dev_attr_srp.attr,
&dev_attr_soft_connect.attr, &dev_attr_soft_connect.attr,
&dev_attr_state.attr,
&dev_attr_current_speed.attr, &dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr, &dev_attr_maximum_speed.attr,

View File

@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param;
#define DRIVER_VERSION "0.1.0" #define DRIVER_VERSION "0.1.0"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0) #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define UVC_NUM_REQUESTS 4 #define UVC_NUM_REQUESTS 4
#define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4 #define UVC_MAX_EVENTS 4
@ -190,6 +188,7 @@ struct uvc_file_handle
* Functions * Functions
*/ */
extern void uvc_function_setup_continue(struct uvc_device *uvc);
extern void uvc_endpoint_stream(struct uvc_device *dev); extern void uvc_endpoint_stream(struct uvc_device *dev);
extern void uvc_function_connect(struct uvc_device *uvc); extern void uvc_function_connect(struct uvc_device *uvc);

View File

@ -10,6 +10,7 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/atomic.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/list.h> #include <linux/list.h>
@ -18,7 +19,8 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/atomic.h>
#include <media/videobuf2-vmalloc.h>
#include "uvc.h" #include "uvc.h"
@ -28,330 +30,175 @@
* Video queues is initialized by uvc_queue_init(). The function performs * Video queues is initialized by uvc_queue_init(). The function performs
* basic initialization of the uvc_video_queue struct and never fails. * basic initialization of the uvc_video_queue struct and never fails.
* *
* Video buffer allocation and freeing are performed by uvc_alloc_buffers and * Video buffers are managed by videobuf2. The driver uses a mutex to protect
* uvc_free_buffers respectively. The former acquires the video queue lock, * the videobuf2 queue operations by serializing calls to videobuf2 and a
* while the later must be called with the lock held (so that allocation can * spinlock to protect the IRQ queue that holds the buffers to be processed by
* free previously allocated buffers). Trying to free buffers that are mapped * the driver.
* to user space will return -EBUSY.
*
* Video buffers are managed using two queues. However, unlike most USB video
* drivers that use an in queue and an out queue, we use a main queue to hold
* all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
* hold empty buffers. This design (copied from video-buf) minimizes locking
* in interrupt, as only one queue is shared between interrupt and user
* contexts.
*
* Use cases
* ---------
*
* Unless stated otherwise, all operations that modify the irq buffers queue
* are protected by the irq spinlock.
*
* 1. The user queues the buffers, starts streaming and dequeues a buffer.
*
* The buffers are added to the main and irq queues. Both operations are
* protected by the queue lock, and the later is protected by the irq
* spinlock as well.
*
* The completion handler fetches a buffer from the irq queue and fills it
* with video data. If no buffer is available (irq queue empty), the handler
* returns immediately.
*
* When the buffer is full, the completion handler removes it from the irq
* queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
* At that point, any process waiting on the buffer will be woken up. If a
* process tries to dequeue a buffer after it has been marked ready, the
* dequeing will succeed immediately.
*
* 2. Buffers are queued, user is waiting on a buffer and the device gets
* disconnected.
*
* When the device is disconnected, the kernel calls the completion handler
* with an appropriate status code. The handler marks all buffers in the
* irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
* that any process waiting on a buffer gets woken up.
*
* Waking up up the first buffer on the irq list is not enough, as the
* process waiting on the buffer might restart the dequeue operation
* immediately.
*
*/ */
static void /* -----------------------------------------------------------------------------
uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) * videobuf2 queue operations
*/
static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{ {
mutex_init(&queue->mutex); struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
spin_lock_init(&queue->irqlock); struct uvc_video *video = container_of(queue, struct uvc_video, queue);
INIT_LIST_HEAD(&queue->mainqueue);
INIT_LIST_HEAD(&queue->irqqueue); if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
queue->type = type; *nbuffers = UVC_MAX_VIDEO_BUFFERS;
*nplanes = 1;
sizes[0] = video->imagesize;
return 0;
} }
/* static int uvc_buffer_prepare(struct vb2_buffer *vb)
* Free the video buffers.
*
* This function must be called with the queue lock held.
*/
static int uvc_free_buffers(struct uvc_video_queue *queue)
{ {
unsigned int i; struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
for (i = 0; i < queue->count; ++i) { if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
if (queue->buffer[i].vma_use_count != 0) vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
return -EBUSY; uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
return -EINVAL;
} }
if (queue->count) { if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
vfree(queue->mem); return -ENODEV;
queue->count = 0;
buf->state = UVC_BUF_STATE_QUEUED;
buf->mem = vb2_plane_vaddr(vb, 0);
buf->length = vb2_plane_size(vb, 0);
if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
buf->bytesused = 0;
else
buf->bytesused = vb2_get_plane_payload(vb, 0);
return 0;
}
static void uvc_buffer_queue(struct vb2_buffer *vb)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
unsigned long flags;
spin_lock_irqsave(&queue->irqlock, flags);
if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
list_add_tail(&buf->queue, &queue->irqqueue);
} else {
/* If the device is disconnected return the buffer to userspace
* directly. The next QBUF call will fail with -ENODEV.
*/
buf->state = UVC_BUF_STATE_ERROR;
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
} }
spin_unlock_irqrestore(&queue->irqlock, flags);
}
static struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
};
static int uvc_queue_init(struct uvc_video_queue *queue,
enum v4l2_buf_type type)
{
int ret;
queue->queue.type = type;
queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
queue->queue.drv_priv = queue;
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.ops = &uvc_queue_qops;
queue->queue.mem_ops = &vb2_vmalloc_memops;
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->irqqueue);
queue->flags = 0;
return 0; return 0;
} }
/* /*
* Allocate the video buffers. * Free the video buffers.
*
* Pages are reserved to make sure they will not be swapped, as they will be
* filled in the URB completion handler.
*
* Buffers will be individually mapped, so they must all be page aligned.
*/ */
static int static void uvc_free_buffers(struct uvc_video_queue *queue)
uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
unsigned int buflength)
{ {
unsigned int bufsize = PAGE_ALIGN(buflength);
unsigned int i;
void *mem = NULL;
int ret;
if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
nbuffers = UVC_MAX_VIDEO_BUFFERS;
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
vb2_queue_release(&queue->queue);
if ((ret = uvc_free_buffers(queue)) < 0)
goto done;
/* Bail out if no buffers should be allocated. */
if (nbuffers == 0)
goto done;
/* Decrement the number of buffers until allocation succeeds. */
for (; nbuffers > 0; --nbuffers) {
mem = vmalloc_32(nbuffers * bufsize);
if (mem != NULL)
break;
}
if (mem == NULL) {
ret = -ENOMEM;
goto done;
}
for (i = 0; i < nbuffers; ++i) {
memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
queue->buffer[i].buf.index = i;
queue->buffer[i].buf.m.offset = i * bufsize;
queue->buffer[i].buf.length = buflength;
queue->buffer[i].buf.type = queue->type;
queue->buffer[i].buf.sequence = 0;
queue->buffer[i].buf.field = V4L2_FIELD_NONE;
queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
queue->buffer[i].buf.flags = 0;
init_waitqueue_head(&queue->buffer[i].wait);
}
queue->mem = mem;
queue->count = nbuffers;
queue->buf_size = bufsize;
ret = nbuffers;
done:
mutex_unlock(&queue->mutex); mutex_unlock(&queue->mutex);
return ret;
}
static void __uvc_query_buffer(struct uvc_buffer *buf,
struct v4l2_buffer *v4l2_buf)
{
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
if (buf->vma_use_count)
v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
switch (buf->state) {
case UVC_BUF_STATE_ERROR:
case UVC_BUF_STATE_DONE:
v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
break;
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
break;
case UVC_BUF_STATE_IDLE:
default:
break;
}
}
static int
uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
{
int ret = 0;
mutex_lock(&queue->mutex);
if (v4l2_buf->index >= queue->count) {
ret = -EINVAL;
goto done;
}
__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
done:
mutex_unlock(&queue->mutex);
return ret;
} }
/* /*
* Queue a video buffer. Attempting to queue a buffer that has already been * Allocate the video buffers.
* queued will return -EINVAL.
*/ */
static int static int uvc_alloc_buffers(struct uvc_video_queue *queue,
uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) struct v4l2_requestbuffers *rb)
{ {
struct uvc_buffer *buf; int ret;
unsigned long flags;
int ret = 0;
uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
v4l2_buf->memory);
return -EINVAL;
}
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
if (v4l2_buf->index >= queue->count) { ret = vb2_reqbufs(&queue->queue, rb);
uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
ret = -EINVAL;
goto done;
}
buf = &queue->buffer[v4l2_buf->index];
if (buf->state != UVC_BUF_STATE_IDLE) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
"(%u).\n", buf->state);
ret = -EINVAL;
goto done;
}
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
v4l2_buf->bytesused > buf->buf.length) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
ret = -EINVAL;
goto done;
}
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
buf->buf.bytesused = 0;
else
buf->buf.bytesused = v4l2_buf->bytesused;
spin_lock_irqsave(&queue->irqlock, flags);
if (queue->flags & UVC_QUEUE_DISCONNECTED) {
spin_unlock_irqrestore(&queue->irqlock, flags);
ret = -ENODEV;
goto done;
}
buf->state = UVC_BUF_STATE_QUEUED;
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED;
list_add_tail(&buf->stream, &queue->mainqueue);
list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
done:
mutex_unlock(&queue->mutex); mutex_unlock(&queue->mutex);
return ret ? ret : rb->count;
}
static int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *buf)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_querybuf(&queue->queue, buf);
mutex_unlock(&queue->mutex);
return ret; return ret;
} }
static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) static int uvc_queue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *buf)
{ {
if (nonblocking) { unsigned long flags;
return (buf->state != UVC_BUF_STATE_QUEUED && int ret;
buf->state != UVC_BUF_STATE_ACTIVE)
? 0 : -EAGAIN;
}
return wait_event_interruptible(buf->wait, mutex_lock(&queue->mutex);
buf->state != UVC_BUF_STATE_QUEUED && ret = vb2_qbuf(&queue->queue, buf);
buf->state != UVC_BUF_STATE_ACTIVE); spin_lock_irqsave(&queue->irqlock, flags);
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED;
spin_unlock_irqrestore(&queue->irqlock, flags);
mutex_unlock(&queue->mutex);
return ret;
} }
/* /*
* Dequeue a video buffer. If nonblocking is false, block until a buffer is * Dequeue a video buffer. If nonblocking is false, block until a buffer is
* available. * available.
*/ */
static int static int uvc_dequeue_buffer(struct uvc_video_queue *queue,
uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf, struct v4l2_buffer *buf, int nonblocking)
int nonblocking)
{ {
struct uvc_buffer *buf; int ret;
int ret = 0;
if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
v4l2_buf->memory);
return -EINVAL;
}
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
if (list_empty(&queue->mainqueue)) { ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
ret = -EINVAL;
goto done;
}
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
goto done;
uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
buf->buf.index, buf->state, buf->buf.bytesused);
switch (buf->state) {
case UVC_BUF_STATE_ERROR:
uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
"(transmission error).\n");
ret = -EIO;
case UVC_BUF_STATE_DONE:
buf->state = UVC_BUF_STATE_IDLE;
break;
case UVC_BUF_STATE_IDLE:
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
default:
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
"(driver bug?).\n", buf->state);
ret = -EINVAL;
goto done;
}
list_del(&buf->stream);
__uvc_query_buffer(buf, v4l2_buf);
done:
mutex_unlock(&queue->mutex); mutex_unlock(&queue->mutex);
return ret; return ret;
} }
@ -361,105 +208,47 @@ uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf,
* This function implements video queue polling and is intended to be used by * This function implements video queue polling and is intended to be used by
* the device poll handler. * the device poll handler.
*/ */
static unsigned int static unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, struct file *file, poll_table *wait)
poll_table *wait)
{ {
struct uvc_buffer *buf; unsigned int ret;
unsigned int mask = 0;
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
if (list_empty(&queue->mainqueue)) ret = vb2_poll(&queue->queue, file, wait);
goto done;
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
poll_wait(file, &buf->wait, wait);
if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR)
mask |= POLLOUT | POLLWRNORM;
done:
mutex_unlock(&queue->mutex); mutex_unlock(&queue->mutex);
return mask;
return ret;
} }
/* static int uvc_queue_mmap(struct uvc_video_queue *queue,
* VMA operations. struct vm_area_struct *vma)
*/
static void uvc_vm_open(struct vm_area_struct *vma)
{ {
struct uvc_buffer *buffer = vma->vm_private_data; int ret;
buffer->vma_use_count++;
}
static void uvc_vm_close(struct vm_area_struct *vma)
{
struct uvc_buffer *buffer = vma->vm_private_data;
buffer->vma_use_count--;
}
static struct vm_operations_struct uvc_vm_ops = {
.open = uvc_vm_open,
.close = uvc_vm_close,
};
/*
* Memory-map a buffer.
*
* This function implements video buffer memory mapping and is intended to be
* used by the device mmap handler.
*/
static int
uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
struct uvc_buffer *uninitialized_var(buffer);
struct page *page;
unsigned long addr, start, size;
unsigned int i;
int ret = 0;
start = vma->vm_start;
size = vma->vm_end - vma->vm_start;
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
ret = vb2_mmap(&queue->queue, vma);
mutex_unlock(&queue->mutex);
for (i = 0; i < queue->count; ++i) { return ret;
buffer = &queue->buffer[i]; }
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
if (i == queue->count || size != queue->buf_size) { #ifndef CONFIG_MMU
ret = -EINVAL; /*
goto done; * Get unmapped area.
} *
* NO-MMU arch need this function to make mmap() work correctly.
*/
static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
unsigned long pgoff)
{
unsigned long ret;
/* mutex_lock(&queue->mutex);
* VM_IO marks the area as being an mmaped region for I/O to a ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
* device. It also prevents the region from being core dumped.
*/
vma->vm_flags |= VM_IO;
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
goto done;
start += PAGE_SIZE;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
uvc_vm_open(vma);
done:
mutex_unlock(&queue->mutex); mutex_unlock(&queue->mutex);
return ret; return ret;
} }
#endif
/* /*
* Cancel the video buffers queue. * Cancel the video buffers queue.
@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
queue); queue);
list_del(&buf->queue); list_del(&buf->queue);
buf->state = UVC_BUF_STATE_ERROR; buf->state = UVC_BUF_STATE_ERROR;
wake_up(&buf->wait); vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
} }
/* This must be protected by the irqlock spinlock to avoid race /* This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_queue_buffer and the disconnection event that * conditions between uvc_queue_buffer and the disconnection event that
@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
*/ */
static int uvc_queue_enable(struct uvc_video_queue *queue, int enable) static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
{ {
unsigned int i; unsigned long flags;
int ret = 0; int ret = 0;
mutex_lock(&queue->mutex); mutex_lock(&queue->mutex);
if (enable) { if (enable) {
if (uvc_queue_streaming(queue)) { ret = vb2_streamon(&queue->queue, queue->queue.type);
ret = -EBUSY; if (ret < 0)
goto done; goto done;
}
queue->sequence = 0; queue->sequence = 0;
queue->flags |= UVC_QUEUE_STREAMING;
queue->buf_used = 0; queue->buf_used = 0;
} else { } else {
uvc_queue_cancel(queue, 0); ret = vb2_streamoff(&queue->queue, queue->queue.type);
INIT_LIST_HEAD(&queue->mainqueue); if (ret < 0)
goto done;
for (i = 0; i < queue->count; ++i) spin_lock_irqsave(&queue->irqlock, flags);
queue->buffer[i].state = UVC_BUF_STATE_IDLE; INIT_LIST_HEAD(&queue->irqqueue);
queue->flags &= ~UVC_QUEUE_STREAMING; /*
* FIXME: We need to clear the DISCONNECTED flag to ensure that
* applications will be able to queue buffers for the next
* streaming run. However, clearing it here doesn't guarantee
* that the device will be reconnected in the meantime.
*/
queue->flags &= ~UVC_QUEUE_DISCONNECTED;
spin_unlock_irqrestore(&queue->irqlock, flags);
} }
done: done:
@ -544,15 +340,15 @@ static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
} }
/* called with &queue_irqlock held.. */ /* called with &queue_irqlock held.. */
static struct uvc_buffer * static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) struct uvc_buffer *buf)
{ {
struct uvc_buffer *nextbuf; struct uvc_buffer *nextbuf;
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) && if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
buf->buf.length != buf->buf.bytesused) { buf->length != buf->bytesused) {
buf->state = UVC_BUF_STATE_QUEUED; buf->state = UVC_BUF_STATE_QUEUED;
buf->buf.bytesused = 0; vb2_set_plane_payload(&buf->buf, 0, 0);
return buf; return buf;
} }
@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
else else
nextbuf = NULL; nextbuf = NULL;
buf->buf.sequence = queue->sequence++; /*
do_gettimeofday(&buf->buf.timestamp); * FIXME: with videobuf2, the sequence number or timestamp fields
* are valid only for video capture devices and the UVC gadget usually
* is a video output device. Keeping these until the specs are clear on
* this aspect.
*/
buf->buf.v4l2_buf.sequence = queue->sequence++;
do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
wake_up(&buf->wait);
return nextbuf; return nextbuf;
} }

View File

@ -6,6 +6,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/videobuf2-core.h>
/* Maximum frame size in bytes, for sanity checking. */ /* Maximum frame size in bytes, for sanity checking. */
#define UVC_MAX_FRAME_SIZE (16*1024*1024) #define UVC_MAX_FRAME_SIZE (16*1024*1024)
@ -25,42 +26,35 @@ enum uvc_buffer_state {
}; };
struct uvc_buffer { struct uvc_buffer {
unsigned long vma_use_count; struct vb2_buffer buf;
struct list_head stream;
/* Touched by interrupt handler. */
struct v4l2_buffer buf;
struct list_head queue; struct list_head queue;
wait_queue_head_t wait;
enum uvc_buffer_state state; enum uvc_buffer_state state;
void *mem;
unsigned int length;
unsigned int bytesused;
}; };
#define UVC_QUEUE_STREAMING (1 << 0) #define UVC_QUEUE_DISCONNECTED (1 << 0)
#define UVC_QUEUE_DISCONNECTED (1 << 1) #define UVC_QUEUE_DROP_INCOMPLETE (1 << 1)
#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) #define UVC_QUEUE_PAUSED (1 << 2)
#define UVC_QUEUE_PAUSED (1 << 3)
struct uvc_video_queue { struct uvc_video_queue {
enum v4l2_buf_type type; struct vb2_queue queue;
struct mutex mutex; /* Protects queue */
void *mem;
unsigned int flags; unsigned int flags;
__u32 sequence; __u32 sequence;
unsigned int count;
unsigned int buf_size;
unsigned int buf_used; unsigned int buf_used;
struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
struct mutex mutex; /* protects buffers and mainqueue */
spinlock_t irqlock; /* protects irqqueue */
struct list_head mainqueue; spinlock_t irqlock; /* Protects flags and irqqueue */
struct list_head irqqueue; struct list_head irqqueue;
}; };
static inline int uvc_queue_streaming(struct uvc_video_queue *queue) static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{ {
return queue->flags & UVC_QUEUE_STREAMING; return vb2_is_streaming(&queue->queue);
} }
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */

View File

@ -41,9 +41,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
req->length = min_t(unsigned int, uvc->event_length, data->length); req->length = min_t(unsigned int, uvc->event_length, data->length);
req->zero = data->length < uvc->event_length; req->zero = data->length < uvc->event_length;
req->dma = DMA_ADDR_INVALID;
memcpy(req->buf, data->data, data->length); memcpy(req->buf, data->data, req->length);
return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL); return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
} }
@ -148,16 +147,13 @@ uvc_v4l2_release(struct file *file)
uvc_function_disconnect(uvc); uvc_function_disconnect(uvc);
uvc_video_enable(video, 0); uvc_video_enable(video, 0);
mutex_lock(&video->queue.mutex); uvc_free_buffers(&video->queue);
if (uvc_free_buffers(&video->queue) < 0)
printk(KERN_ERR "uvc_v4l2_release: Unable to free "
"buffers.\n");
mutex_unlock(&video->queue.mutex);
file->private_data = NULL; file->private_data = NULL;
v4l2_fh_del(&handle->vfh); v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh); v4l2_fh_exit(&handle->vfh);
kfree(handle); kfree(handle);
return 0; return 0;
} }
@ -178,9 +174,9 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_capability *cap = arg; struct v4l2_capability *cap = arg;
memset(cap, 0, sizeof *cap); memset(cap, 0, sizeof *cap);
strncpy(cap->driver, "g_uvc", sizeof(cap->driver)); strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
strncpy(cap->card, cdev->gadget->name, sizeof(cap->card)); strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
strncpy(cap->bus_info, dev_name(&cdev->gadget->dev), strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof cap->bus_info); sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER; cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@ -192,7 +188,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_format *fmt = arg; struct v4l2_format *fmt = arg;
if (fmt->type != video->queue.type) if (fmt->type != video->queue.queue.type)
return -EINVAL; return -EINVAL;
return uvc_v4l2_get_format(video, fmt); return uvc_v4l2_get_format(video, fmt);
@ -202,7 +198,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_format *fmt = arg; struct v4l2_format *fmt = arg;
if (fmt->type != video->queue.type) if (fmt->type != video->queue.queue.type)
return -EINVAL; return -EINVAL;
return uvc_v4l2_set_format(video, fmt); return uvc_v4l2_set_format(video, fmt);
@ -213,16 +209,13 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_requestbuffers *rb = arg; struct v4l2_requestbuffers *rb = arg;
if (rb->type != video->queue.type || if (rb->type != video->queue.queue.type)
rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL; return -EINVAL;
ret = uvc_alloc_buffers(&video->queue, rb->count, ret = uvc_alloc_buffers(&video->queue, rb);
video->imagesize);
if (ret < 0) if (ret < 0)
return ret; return ret;
rb->count = ret;
ret = 0; ret = 0;
break; break;
} }
@ -231,9 +224,6 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_buffer *buf = arg; struct v4l2_buffer *buf = arg;
if (buf->type != video->queue.type)
return -EINVAL;
return uvc_query_buffer(&video->queue, buf); return uvc_query_buffer(&video->queue, buf);
} }
@ -251,24 +241,36 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
int *type = arg; int *type = arg;
if (*type != video->queue.type) if (*type != video->queue.queue.type)
return -EINVAL; return -EINVAL;
return uvc_video_enable(video, 1); /* Enable UVC video. */
ret = uvc_video_enable(video, 1);
if (ret < 0)
return ret;
/*
* Complete the alternate setting selection setup phase now that
* userspace is ready to provide video frames.
*/
uvc_function_setup_continue(uvc);
uvc->state = UVC_STATE_STREAMING;
return 0;
} }
case VIDIOC_STREAMOFF: case VIDIOC_STREAMOFF:
{ {
int *type = arg; int *type = arg;
if (*type != video->queue.type) if (*type != video->queue.queue.type)
return -EINVAL; return -EINVAL;
return uvc_video_enable(video, 0); return uvc_video_enable(video, 0);
} }
/* Events */ /* Events */
case VIDIOC_DQEVENT: case VIDIOC_DQEVENT:
{ {
struct v4l2_event *event = arg; struct v4l2_event *event = arg;
@ -333,18 +335,22 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev); struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
unsigned int mask = 0;
poll_wait(file, &handle->vfh.wait, wait); return uvc_queue_poll(&uvc->video.queue, file, wait);
if (v4l2_event_pending(&handle->vfh))
mask |= POLLPRI;
mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
return mask;
} }
#ifndef CONFIG_MMU
static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
unsigned long addr, unsigned long len, unsigned long pgoff,
unsigned long flags)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
return uvc_queue_get_unmapped_area(&uvc->video.queue, pgoff);
}
#endif
static struct v4l2_file_operations uvc_v4l2_fops = { static struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = uvc_v4l2_open, .open = uvc_v4l2_open,
@ -352,5 +358,8 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
.ioctl = uvc_v4l2_ioctl, .ioctl = uvc_v4l2_ioctl,
.mmap = uvc_v4l2_mmap, .mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll, .poll = uvc_v4l2_poll,
#ifndef CONFIG_MMU
.get_unmapped_area = uvc_v4l2_get_unmapped_area,
#endif
}; };

View File

@ -32,7 +32,7 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
data[0] = 2; data[0] = 2;
data[1] = UVC_STREAM_EOH | video->fid; data[1] = UVC_STREAM_EOH | video->fid;
if (buf->buf.bytesused - video->queue.buf_used <= len - 2) if (buf->bytesused - video->queue.buf_used <= len - 2)
data[1] |= UVC_STREAM_EOF; data[1] |= UVC_STREAM_EOF;
return 2; return 2;
@ -47,8 +47,8 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
void *mem; void *mem;
/* Copy video data to the USB buffer. */ /* Copy video data to the USB buffer. */
mem = queue->mem + buf->buf.m.offset + queue->buf_used; mem = buf->mem + queue->buf_used;
nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
memcpy(data, mem, nbytes); memcpy(data, mem, nbytes);
queue->buf_used += nbytes; queue->buf_used += nbytes;
@ -82,7 +82,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len; req->length = video->req_size - len;
req->zero = video->payload_size == video->max_payload_size; req->zero = video->payload_size == video->max_payload_size;
if (buf->buf.bytesused == video->queue.buf_used) { if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0; video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE; buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf); uvc_queue_next_buffer(&video->queue, buf);
@ -92,7 +92,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
} }
if (video->payload_size == video->max_payload_size || if (video->payload_size == video->max_payload_size ||
buf->buf.bytesused == video->queue.buf_used) buf->bytesused == video->queue.buf_used)
video->payload_size = 0; video->payload_size = 0;
} }
@ -115,7 +115,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len; req->length = video->req_size - len;
if (buf->buf.bytesused == video->queue.buf_used) { if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0; video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE; buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf); uvc_queue_next_buffer(&video->queue, buf);
@ -161,6 +161,7 @@ static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req) uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{ {
struct uvc_video *video = req->context; struct uvc_video *video = req->context;
struct uvc_video_queue *queue = &video->queue;
struct uvc_buffer *buf; struct uvc_buffer *buf;
unsigned long flags; unsigned long flags;
int ret; int ret;
@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
case 0: case 0:
break; break;
case -ESHUTDOWN: case -ESHUTDOWN: /* disconnect from host. */
printk(KERN_INFO "VS request cancelled.\n"); printk(KERN_INFO "VS request cancelled.\n");
uvc_queue_cancel(queue, 1);
goto requeue; goto requeue;
default: default:
printk(KERN_INFO "VS request completed with status %d.\n", printk(KERN_INFO "VS request completed with status %d.\n",
req->status); req->status);
uvc_queue_cancel(queue, 0);
goto requeue; goto requeue;
} }
@ -229,13 +232,18 @@ uvc_video_free_requests(struct uvc_video *video)
static int static int
uvc_video_alloc_requests(struct uvc_video *video) uvc_video_alloc_requests(struct uvc_video *video)
{ {
unsigned int req_size;
unsigned int i; unsigned int i;
int ret = -ENOMEM; int ret = -ENOMEM;
BUG_ON(video->req_size); BUG_ON(video->req_size);
req_size = video->ep->maxpacket
* max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult + 1);
for (i = 0; i < UVC_NUM_REQUESTS; ++i) { for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL); video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
if (video->req_buffer[i] == NULL) if (video->req_buffer[i] == NULL)
goto error; goto error;
@ -245,14 +253,14 @@ uvc_video_alloc_requests(struct uvc_video *video)
video->req[i]->buf = video->req_buffer[i]; video->req[i]->buf = video->req_buffer[i];
video->req[i]->length = 0; video->req[i]->length = 0;
video->req[i]->dma = DMA_ADDR_INVALID;
video->req[i]->complete = uvc_video_complete; video->req[i]->complete = uvc_video_complete;
video->req[i]->context = video; video->req[i]->context = video;
list_add_tail(&video->req[i]->list, &video->req_free); list_add_tail(&video->req[i]->list, &video->req_free);
} }
video->req_size = video->ep->maxpacket; video->req_size = req_size;
return 0; return 0;
error: error:
@ -309,7 +317,8 @@ uvc_video_pump(struct uvc_video *video)
video->encode(req, video, buf); video->encode(req, video, buf);
/* Queue the USB request */ /* Queue the USB request */
if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) { ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
if (ret < 0) {
printk(KERN_INFO "Failed to queue request (%d)\n", ret); printk(KERN_INFO "Failed to queue request (%d)\n", ret);
usb_ep_set_halt(video->ep); usb_ep_set_halt(video->ep);
spin_unlock_irqrestore(&video->queue.irqlock, flags); spin_unlock_irqrestore(&video->queue.irqlock, flags);

View File

@ -180,6 +180,7 @@ config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support" boolean "NVIDIA Tegra HCD support"
depends on USB_EHCI_HCD && ARCH_TEGRA depends on USB_EHCI_HCD && ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT select USB_EHCI_ROOT_HUB_TT
select USB_PHY
help help
This driver enables support for the internal USB Host Controllers This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
@ -301,7 +302,6 @@ config USB_OHCI_HCD
tristate "OHCI HCD support" tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
select USB_OTG_UTILS if ARCH_OMAP
depends on USB_ISP1301 || !ARCH_LPC32XX depends on USB_ISP1301 || !ARCH_LPC32XX
---help--- ---help---
The Open Host Controller Interface (OHCI) is a standard for accessing The Open Host Controller Interface (OHCI) is a standard for accessing

View File

@ -145,7 +145,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
* management. * management.
*/ */
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(phy)) { if (IS_ERR(phy)) {
dev_err(&pdev->dev, "unable to find transceiver\n"); dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV; ret = -ENODEV;
goto put_hcd; goto put_hcd;

View File

@ -33,25 +33,17 @@ struct ehci_hcd_mv {
struct mv_usb_platform_data *pdata; struct mv_usb_platform_data *pdata;
/* clock source and total clock number */ struct clk *clk;
unsigned int clknum;
struct clk *clk[0];
}; };
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
{ {
unsigned int i; clk_prepare_enable(ehci_mv->clk);
for (i = 0; i < ehci_mv->clknum; i++)
clk_prepare_enable(ehci_mv->clk[i]);
} }
static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
{ {
unsigned int i; clk_disable_unprepare(ehci_mv->clk);
for (i = 0; i < ehci_mv->clknum; i++)
clk_disable_unprepare(ehci_mv->clk[i]);
} }
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
@ -144,9 +136,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
struct ehci_hcd *ehci; struct ehci_hcd *ehci;
struct ehci_hcd_mv *ehci_mv; struct ehci_hcd_mv *ehci_mv;
struct resource *r; struct resource *r;
int clk_i, retval = -ENODEV; int retval = -ENODEV;
u32 offset; u32 offset;
size_t size;
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "missing platform_data\n"); dev_err(&pdev->dev, "missing platform_data\n");
@ -160,8 +151,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
if (!hcd) if (!hcd)
return -ENOMEM; return -ENOMEM;
size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (ehci_mv == NULL) { if (ehci_mv == NULL) {
dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
retval = -ENOMEM; retval = -ENOMEM;
@ -172,16 +162,11 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->pdata = pdata; ehci_mv->pdata = pdata;
ehci_mv->hcd = hcd; ehci_mv->hcd = hcd;
ehci_mv->clknum = pdata->clknum; ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { if (IS_ERR(ehci_mv->clk)) {
ehci_mv->clk[clk_i] = dev_err(&pdev->dev, "error getting clock\n");
devm_clk_get(&pdev->dev, pdata->clkname[clk_i]); retval = PTR_ERR(ehci_mv->clk);
if (IS_ERR(ehci_mv->clk[clk_i])) { goto err_clear_drvdata;
dev_err(&pdev->dev, "error get clck \"%s\"\n",
pdata->clkname[clk_i]);
retval = PTR_ERR(ehci_mv->clk[clk_i]);
goto err_clear_drvdata;
}
} }
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
@ -240,12 +225,16 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->mode = pdata->mode; ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) { if (ehci_mv->mode == MV_USB_MODE_OTG) {
#ifdef CONFIG_USB_OTG_UTILS
ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(ehci_mv->otg)) { if (IS_ERR(ehci_mv->otg)) {
dev_err(&pdev->dev, retval = PTR_ERR(ehci_mv->otg);
"unable to find transceiver\n");
retval = -ENODEV; if (retval == -ENXIO)
dev_info(&pdev->dev, "MV_USB_MODE_OTG "
"must have CONFIG_USB_PHY enabled\n");
else
dev_err(&pdev->dev,
"unable to find transceiver\n");
goto err_disable_clk; goto err_disable_clk;
} }
@ -258,11 +247,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
} }
/* otg will enable clock before use as host */ /* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv); mv_ehci_disable(ehci_mv);
#else
dev_info(&pdev->dev, "MV_USB_MODE_OTG "
"must have CONFIG_USB_OTG_UTILS enabled\n");
goto err_disable_clk;
#endif
} else { } else {
if (pdata->set_vbus) if (pdata->set_vbus)
pdata->set_vbus(1); pdata->set_vbus(1);

View File

@ -140,7 +140,7 @@ static int s5p_ehci_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(phy)) { if (IS_ERR(phy)) {
/* Fallback to pdata */ /* Fallback to pdata */
if (!pdata) { if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); dev_warn(&pdev->dev, "no platform data or transceiver defined\n");

View File

@ -773,16 +773,14 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto fail_phy; goto fail_phy;
} }
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) { if (pdata->operating_mode == TEGRA_USB_OTG) {
tegra->transceiver = tegra->transceiver =
devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(tegra->transceiver)) if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, &hcd->self); otg_set_host(tegra->transceiver->otg, &hcd->self);
} else { } else {
tegra->transceiver = ERR_PTR(-ENODEV); tegra->transceiver = ERR_PTR(-ENODEV);
} }
#endif
err = usb_add_hcd(hcd, irq, IRQF_SHARED); err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) { if (err) {
@ -801,10 +799,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
return err; return err;
fail: fail:
#ifdef CONFIG_USB_OTG_UTILS if (!IS_ERR(tegra->transceiver))
if (!IS_ERR_OR_NULL(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL); otg_set_host(tegra->transceiver->otg, NULL);
#endif
fail_phy: fail_phy:
usb_phy_shutdown(hcd->phy); usb_phy_shutdown(hcd->phy);
fail_io: fail_io:
@ -823,10 +819,8 @@ static int tegra_ehci_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
#ifdef CONFIG_USB_OTG_UTILS if (!IS_ERR(tegra->transceiver))
if (!IS_ERR_OR_NULL(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL); otg_set_host(tegra->transceiver->otg, NULL);
#endif
usb_phy_shutdown(hcd->phy); usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);

View File

@ -128,7 +128,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(phy)) { if (IS_ERR(phy)) {
/* Fallback to pdata */ /* Fallback to pdata */
if (!pdata) { if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); dev_warn(&pdev->dev, "no platform data or transceiver defined\n");

View File

@ -7,7 +7,6 @@
config USB_MUSB_HDRC config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
depends on USB && USB_GADGET depends on USB && USB_GADGET
select USB_OTG_UTILS
help help
Say Y here if your system has a dual role high speed USB Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then controller based on the Mentor Graphics silicon IP. Then
@ -34,10 +33,12 @@ choice
config USB_MUSB_DAVINCI config USB_MUSB_DAVINCI
tristate "DaVinci" tristate "DaVinci"
depends on ARCH_DAVINCI_DMx depends on ARCH_DAVINCI_DMx
depends on BROKEN
config USB_MUSB_DA8XX config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x" tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX depends on ARCH_DAVINCI_DA8XX
depends on BROKEN
config USB_MUSB_TUSB6010 config USB_MUSB_TUSB6010
tristate "TUSB6010" tristate "TUSB6010"
@ -53,7 +54,6 @@ config USB_MUSB_AM35X
config USB_MUSB_DSPS config USB_MUSB_DSPS
tristate "TI DSPS platforms" tristate "TI DSPS platforms"
depends on SOC_TI81XX || SOC_AM33XX
config USB_MUSB_BLACKFIN config USB_MUSB_BLACKFIN
tristate "Blackfin" tristate "Blackfin"
@ -61,12 +61,12 @@ config USB_MUSB_BLACKFIN
config USB_MUSB_UX500 config USB_MUSB_UX500
tristate "U8500 and U5500" tristate "U8500 and U5500"
depends on (ARCH_U8500 && AB8500_USB)
endchoice endchoice
choice choice
prompt 'MUSB DMA mode' prompt 'MUSB DMA mode'
default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
default USB_UX500_DMA if USB_MUSB_UX500 default USB_UX500_DMA if USB_MUSB_UX500
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI

View File

@ -149,7 +149,7 @@ static void otg_timer(unsigned long _musb)
*/ */
devctl = musb_readb(mregs, MUSB_DEVCTL); devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -195,7 +195,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 && if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n", dev_dbg(musb->controller, "%s active, deleting timer\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround); del_timer(&otg_workaround);
last_timer = jiffies; last_timer = jiffies;
return; return;
@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout; last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies)); jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout); mod_timer(&otg_workaround, timeout);
} }
@ -298,7 +298,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */ /* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off", drvvbus ? "on" : "off",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "", err ? " ERROR" : "",
devctl); devctl);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;

View File

@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
break; break;
default: default:
dev_dbg(musb->controller, "%s state not handled\n", dev_dbg(musb->controller, "%s state not handled\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
break; break;
} }
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
dev_dbg(musb->controller, "state is %s\n", dev_dbg(musb->controller, "state is %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
static void bfin_musb_enable(struct musb *musb) static void bfin_musb_enable(struct musb *musb)
@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x " dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n", /* otg %3x conf %08x prcm %08x */ "\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL)); musb_readb(musb->mregs, MUSB_DEVCTL));
} }

View File

@ -435,7 +435,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,
} }
} }
#ifdef CONFIG_USB_MUSB_DEBUG
static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
{ {
pr_debug("RXBD/%s %08x: " pr_debug("RXBD/%s %08x: "
@ -444,21 +443,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_next, bd->hw_bufp, bd->hw_off_len,
bd->hw_options); bd->hw_options);
} }
#endif
static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx) static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
{ {
#ifdef CONFIG_USB_MUSB_DEBUG
struct cppi_descriptor *bd; struct cppi_descriptor *bd;
if (!_dbg_level(level))
return;
cppi_dump_rx(level, rx, tag); cppi_dump_rx(level, rx, tag);
if (rx->last_processed) if (rx->last_processed)
cppi_dump_rxbd("last", rx->last_processed); cppi_dump_rxbd("last", rx->last_processed);
for (bd = rx->head; bd; bd = bd->next) for (bd = rx->head; bd; bd = bd->next)
cppi_dump_rxbd("active", bd); cppi_dump_rxbd("active", bd);
#endif
} }
@ -784,6 +778,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
void __iomem *tibase = musb->ctrl_base; void __iomem *tibase = musb->ctrl_base;
int is_rndis = 0; int is_rndis = 0;
struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram; struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
struct cppi_descriptor *d;
if (onepacket) { if (onepacket) {
/* almost every USB driver, host or peripheral side */ /* almost every USB driver, host or peripheral side */
@ -897,14 +892,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
bd->hw_options |= CPPI_SOP_SET; bd->hw_options |= CPPI_SOP_SET;
tail->hw_options |= CPPI_EOP_SET; tail->hw_options |= CPPI_EOP_SET;
#ifdef CONFIG_USB_MUSB_DEBUG for (d = rx->head; d; d = d->next)
if (_dbg_level(5)) { cppi_dump_rxbd("S", d);
struct cppi_descriptor *d;
for (d = rx->head; d; d = d->next)
cppi_dump_rxbd("S", d);
}
#endif
/* in case the preceding transfer left some state... */ /* in case the preceding transfer left some state... */
tail = rx->last_processed; tail = rx->last_processed;

View File

@ -198,7 +198,7 @@ static void otg_timer(unsigned long _musb)
*/ */
devctl = musb_readb(mregs, MUSB_DEVCTL); devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -267,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 && if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n", dev_dbg(musb->controller, "%s active, deleting timer\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround); del_timer(&otg_workaround);
last_timer = jiffies; last_timer = jiffies;
return; return;
@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout; last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies)); jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout); mod_timer(&otg_workaround, timeout);
} }
@ -360,7 +360,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off", drvvbus ? "on" : "off",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "", err ? " ERROR" : "",
devctl); devctl);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;

View File

@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
*/ */
devctl = musb_readb(mregs, MUSB_DEVCTL); devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -349,7 +349,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
davinci_musb_source_power(musb, drvvbus, 0); davinci_musb_source_power(musb, drvvbus, 0);
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off", drvvbus ? "on" : "off",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "", err ? " ERROR" : "",
devctl); devctl);
retval = IRQ_HANDLED; retval = IRQ_HANDLED;

View File

@ -372,13 +372,13 @@ static void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND: case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON: case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n", dev_dbg(musb->controller, "HNP: %s timeout\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
musb_platform_set_vbus(musb, 0); musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break; break;
default: default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
musb->ignore_disconnect = 0; musb->ignore_disconnect = 0;
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -393,13 +393,14 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
u8 reg; u8 reg;
dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state)); dev_dbg(musb->controller, "HNP: stop from %s\n",
usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL: case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb); musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n", dev_dbg(musb->controller, "HNP: back to %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
break; break;
case OTG_STATE_B_HOST: case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n"); dev_dbg(musb->controller, "HNP: Disabling HR\n");
@ -413,7 +414,7 @@ void musb_hnp_stop(struct musb *musb)
break; break;
default: default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
/* /*
@ -451,7 +452,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/ */
if (int_usb & MUSB_INTR_RESUME) { if (int_usb & MUSB_INTR_RESUME) {
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state)); dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
if (devctl & MUSB_DEVCTL_HM) { if (devctl & MUSB_DEVCTL_HM) {
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
@ -493,7 +494,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default: default:
WARNING("bogus %s RESUME (%s)\n", WARNING("bogus %s RESUME (%s)\n",
"host", "host",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
} else { } else {
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -522,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default: default:
WARNING("bogus %s RESUME (%s)\n", WARNING("bogus %s RESUME (%s)\n",
"peripheral", "peripheral",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
} }
} }
@ -538,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
} }
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power /* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical: * is removed) SRP. responses are time critical:
@ -602,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
} }
dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
otg_state_string(musb->xceiv->state), "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
usb_otg_state_string(musb->xceiv->state),
devctl, devctl,
({ char *s; ({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) { switch (devctl & MUSB_DEVCTL_VBUS) {
@ -628,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (int_usb & MUSB_INTR_SUSPEND) { if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
otg_state_string(musb->xceiv->state), devctl); usb_otg_state_string(musb->xceiv->state), devctl);
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -745,12 +747,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
otg_state_string(musb->xceiv->state), devctl); usb_otg_state_string(musb->xceiv->state), devctl);
} }
if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
MUSB_MODE(musb), devctl); MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
@ -787,7 +789,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
default: default:
WARNING("unhandled DISCONNECT transition (%s)\n", WARNING("unhandled DISCONNECT transition (%s)\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
break; break;
} }
} }
@ -813,7 +815,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
} }
} else { } else {
dev_dbg(musb->controller, "BUS RESET as %s\n", dev_dbg(musb->controller, "BUS RESET as %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND: case OTG_STATE_A_SUSPEND:
/* We need to ignore disconnect on suspend /* We need to ignore disconnect on suspend
@ -826,7 +828,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */ /* never use invalid T(a_wait_bcon) */
dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
TA_WAIT_BCON(musb)); TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb))); + msecs_to_jiffies(TA_WAIT_BCON(musb)));
@ -838,7 +840,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb); musb_g_reset(musb);
break; break;
@ -850,7 +852,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
default: default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
} }
} }
@ -1632,7 +1634,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
int ret = -EINVAL; int ret = -EINVAL;
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state)); ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
return ret; return ret;
@ -1951,9 +1953,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_write_ulpi_buscontrol(musb->mregs, busctl); musb_write_ulpi_buscontrol(musb->mregs, busctl);
} }
MUSB_DEV_MODE(musb); if (musb->xceiv->otg->default_a) {
musb->xceiv->otg->default_a = 0; MUSB_HST_MODE(musb);
musb->xceiv->state = OTG_STATE_B_IDLE; musb->xceiv->state = OTG_STATE_A_IDLE;
} else {
MUSB_DEV_MODE(musb);
musb->xceiv->state = OTG_STATE_B_IDLE;
}
status = musb_gadget_setup(musb); status = musb_gadget_setup(musb);
@ -2008,7 +2014,6 @@ static int musb_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int irq = platform_get_irq_byname(pdev, "mc"); int irq = platform_get_irq_byname(pdev, "mc");
int status;
struct resource *iomem; struct resource *iomem;
void __iomem *base; void __iomem *base;
@ -2016,24 +2021,17 @@ static int musb_probe(struct platform_device *pdev)
if (!iomem || irq <= 0) if (!iomem || irq <= 0)
return -ENODEV; return -ENODEV;
base = ioremap(iomem->start, resource_size(iomem)); base = devm_ioremap_resource(dev, iomem);
if (!base) { if (IS_ERR(base))
dev_err(dev, "ioremap failed\n"); return PTR_ERR(base);
return -ENOMEM;
}
status = musb_init_controller(dev, irq, base); return musb_init_controller(dev, irq, base);
if (status < 0)
iounmap(base);
return status;
} }
static int musb_remove(struct platform_device *pdev) static int musb_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev); struct musb *musb = dev_to_musb(dev);
void __iomem *ctrl_base = musb->ctrl_base;
/* this gets called on rmmod. /* this gets called on rmmod.
* - Host mode: host may still be active * - Host mode: host may still be active
@ -2044,7 +2042,6 @@ static int musb_remove(struct platform_device *pdev)
musb_shutdown(pdev); musb_shutdown(pdev);
musb_free(musb); musb_free(musb);
iounmap(ctrl_base);
device_init_wakeup(dev, 0); device_init_wakeup(dev, 0);
#ifndef CONFIG_MUSB_PIO_ONLY #ifndef CONFIG_MUSB_PIO_ONLY
dma_set_mask(dev, *dev->parent->dma_mask); dma_set_mask(dev, *dev->parent->dma_mask);
@ -2293,8 +2290,6 @@ static int __init musb_init(void)
if (usb_disabled()) if (usb_disabled())
return 0; return 0;
pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n",
musb_driver_name);
return platform_driver_register(&musb_driver); return platform_driver_register(&musb_driver);
} }
module_init(musb_init); module_init(musb_init);

View File

@ -38,6 +38,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb/nop-usb-xceiv.h> #include <linux/usb/nop-usb-xceiv.h>
#include <linux/platform_data/usb-omap.h> #include <linux/platform_data/usb-omap.h>
#include <linux/sizes.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
@ -224,7 +225,7 @@ static void otg_timer(unsigned long _musb)
*/ */
devctl = dsps_readb(mregs, MUSB_DEVCTL); devctl = dsps_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -273,7 +274,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 && if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n", dev_dbg(musb->controller, "%s active, deleting timer\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
del_timer(&glue->timer[pdev->id]); del_timer(&glue->timer[pdev->id]);
glue->last_timer[pdev->id] = jiffies; glue->last_timer[pdev->id] = jiffies;
return; return;
@ -288,7 +289,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
glue->last_timer[pdev->id] = timeout; glue->last_timer[pdev->id] = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies)); jiffies_to_msecs(timeout - jiffies));
mod_timer(&glue->timer[pdev->id], timeout); mod_timer(&glue->timer[pdev->id], timeout);
} }
@ -334,7 +335,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
* value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
* Also, DRVVBUS pulses for SRP (but not at 5V) ... * Also, DRVVBUS pulses for SRP (but not at 5V) ...
*/ */
if (usbintr & MUSB_INTR_BABBLE) if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE)
pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@ -377,7 +378,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */ /* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off", drvvbus ? "on" : "off",
otg_state_string(musb->xceiv->state), usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "", err ? " ERROR" : "",
devctl); devctl);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
@ -596,14 +597,13 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
static int dsps_probe(struct platform_device *pdev) static int dsps_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match; const struct of_device_id *match;
const struct dsps_musb_wrapper *wrp; const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue; struct dsps_glue *glue;
struct resource *iomem; struct resource *iomem;
int ret, i; int ret, i;
match = of_match_node(musb_dsps_of_match, np); match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
if (!match) { if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n"); dev_err(&pdev->dev, "fail to get matching of_match struct\n");
ret = -EINVAL; ret = -EINVAL;

View File

@ -46,48 +46,6 @@
#include "musb_core.h" #include "musb_core.h"
/* MUSB PERIPHERAL status 3-mar-2006:
*
* - EP0 seems solid. It passes both USBCV and usbtest control cases.
* Minor glitches:
*
* + remote wakeup to Linux hosts work, but saw USBCV failures;
* in one test run (operator error?)
* + endpoint halt tests -- in both usbtest and usbcv -- seem
* to break when dma is enabled ... is something wrongly
* clearing SENDSTALL?
*
* - Mass storage behaved ok when last tested. Network traffic patterns
* (with lots of short transfers etc) need retesting; they turn up the
* worst cases of the DMA, since short packets are typical but are not
* required.
*
* - TX/IN
* + both pio and dma behave in with network and g_zero tests
* + no cppi throughput issues other than no-hw-queueing
* + failed with FLAT_REG (DaVinci)
* + seems to behave with double buffering, PIO -and- CPPI
* + with gadgetfs + AIO, requests got lost?
*
* - RX/OUT
* + both pio and dma behave in with network and g_zero tests
* + dma is slow in typical case (short_not_ok is clear)
* + double buffering ok with PIO
* + double buffering *FAILS* with CPPI, wrong data bytes sometimes
* + request lossage observed with gadgetfs
*
* - ISO not tested ... might work, but only weakly isochronous
*
* - Gadget driver disabling of softconnect during bind() is ignored; so
* drivers can't hold off host requests until userspace is ready.
* (Workaround: they can turn it off later.)
*
* - PORTABILITY (assumes PIO works):
* + DaVinci, basically works with cppi dma
* + OMAP 2430, ditto with mentor dma
* + TUSB 6010, platform-specific dma in the works
*/
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
#define is_buffer_mapped(req) (is_dma_capable() && \ #define is_buffer_mapped(req) (is_dma_capable() && \
@ -280,41 +238,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
return ep->packet_sz; return ep->packet_sz;
} }
#ifdef CONFIG_USB_INVENTRA_DMA
/* Peripheral tx (IN) using Mentor DMA works as follows:
Only mode 0 is used for transfers <= wPktSize,
mode 1 is used for larger transfers,
One of the following happens:
- Host sends IN token which causes an endpoint interrupt
-> TxAvail
-> if DMA is currently busy, exit.
-> if queue is non-empty, txstate().
- Request is queued by the gadget driver.
-> if queue was previously empty, txstate()
txstate()
-> start
/\ -> setup DMA
| (data is transferred to the FIFO, then sent out when
| IN token(s) are recd from Host.
| -> DMA interrupt on completion
| calls TxAvail.
| -> stop DMA, ~DMAENAB,
| -> set TxPktRdy for last short pkt or zlp
| -> Complete Request
| -> Continue next request (call txstate)
|___________________________________|
* Non-Mentor DMA engines can of course work differently, such as by
* upleveling from irq-per-packet to irq-per-buffer.
*/
#endif
/* /*
* An endpoint is transmitting data. This can be called either from * An endpoint is transmitting data. This can be called either from
* the IRQ routine or from ep.queue() to kickstart a request on an * the IRQ routine or from ep.queue() to kickstart a request on an
@ -621,37 +544,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
#ifdef CONFIG_USB_INVENTRA_DMA
/* Peripheral rx (OUT) using Mentor DMA works as follows:
- Only mode 0 is used.
- Request is queued by the gadget class driver.
-> if queue was previously empty, rxstate()
- Host sends OUT token which causes an endpoint interrupt
/\ -> RxReady
| -> if request queued, call rxstate
| /\ -> setup DMA
| | -> DMA interrupt on completion
| | -> RxReady
| | -> stop DMA
| | -> ack the read
| | -> if data recd = max expected
| | by the request, or host
| | sent a short packet,
| | complete the request,
| | and start the next one.
| |_____________________________________|
| else just wait for the host
| to send the next OUT token.
|__________________________________________________|
* Non-Mentor DMA engines can of course work differently.
*/
#endif
/* /*
* Context: controller locked, IRQs blocked, endpoint selected * Context: controller locked, IRQs blocked, endpoint selected
*/ */
@ -740,7 +632,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c; struct dma_controller *c;
struct dma_channel *channel; struct dma_channel *channel;
int use_dma = 0; int use_dma = 0;
int transfer_size; unsigned int transfer_size;
c = musb->dma_controller; c = musb->dma_controller;
channel = musb_ep->dma; channel = musb_ep->dma;
@ -782,10 +674,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
csr | MUSB_RXCSR_DMAMODE); csr | MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR, csr); musb_writew(epio, MUSB_RXCSR, csr);
transfer_size = min(request->length - request->actual, transfer_size = min_t(unsigned int,
request->length -
request->actual,
channel->max_len); channel->max_len);
musb_ep->dma->desired_mode = 1; musb_ep->dma->desired_mode = 1;
} else { } else {
if (!musb_ep->hb_mult && if (!musb_ep->hb_mult &&
musb_ep->hw_ep->rx_double_buffered) musb_ep->hw_ep->rx_double_buffered)
@ -815,7 +708,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c; struct dma_controller *c;
struct dma_channel *channel; struct dma_channel *channel;
int transfer_size = 0; unsigned int transfer_size = 0;
c = musb->dma_controller; c = musb->dma_controller;
channel = musb_ep->dma; channel = musb_ep->dma;
@ -824,11 +717,13 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (fifo_count < musb_ep->packet_sz) if (fifo_count < musb_ep->packet_sz)
transfer_size = fifo_count; transfer_size = fifo_count;
else if (request->short_not_ok) else if (request->short_not_ok)
transfer_size = min(request->length - transfer_size = min_t(unsigned int,
request->length -
request->actual, request->actual,
channel->max_len); channel->max_len);
else else
transfer_size = min(request->length - transfer_size = min_t(unsigned int,
request->length -
request->actual, request->actual,
(unsigned)fifo_count); (unsigned)fifo_count);
@ -1681,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done; goto done;
default: default:
dev_dbg(musb->controller, "Unhandled wake: %s\n", dev_dbg(musb->controller, "Unhandled wake: %s\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
goto done; goto done;
} }
@ -1801,13 +1696,6 @@ static const struct usb_gadget_ops musb_gadget_operations = {
* all peripheral ports are external... * all peripheral ports are external...
*/ */
static void musb_gadget_release(struct device *dev)
{
/* kref_put(WHAT) */
dev_dbg(dev, "%s\n", __func__);
}
static void static void
init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
{ {
@ -1892,12 +1780,7 @@ int musb_gadget_setup(struct musb *musb)
musb->g.speed = USB_SPEED_UNKNOWN; musb->g.speed = USB_SPEED_UNKNOWN;
/* this "gadget" abstracts/virtualizes the controller */ /* this "gadget" abstracts/virtualizes the controller */
dev_set_name(&musb->g.dev, "gadget");
musb->g.dev.parent = musb->controller;
musb->g.dev.dma_mask = musb->controller->dma_mask;
musb->g.dev.release = musb_gadget_release;
musb->g.name = musb_driver_name; musb->g.name = musb_driver_name;
musb->g.is_otg = 1; musb->g.is_otg = 1;
musb_g_init_endpoints(musb); musb_g_init_endpoints(musb);
@ -1905,11 +1788,6 @@ int musb_gadget_setup(struct musb *musb)
musb->is_active = 0; musb->is_active = 0;
musb_platform_try_idle(musb, 0); musb_platform_try_idle(musb, 0);
status = device_register(&musb->g.dev);
if (status != 0) {
put_device(&musb->g.dev);
return status;
}
status = usb_add_gadget_udc(musb->controller, &musb->g); status = usb_add_gadget_udc(musb->controller, &musb->g);
if (status) if (status)
goto err; goto err;
@ -1924,8 +1802,6 @@ int musb_gadget_setup(struct musb *musb)
void musb_gadget_cleanup(struct musb *musb) void musb_gadget_cleanup(struct musb *musb)
{ {
usb_del_gadget_udc(&musb->g); usb_del_gadget_udc(&musb->g);
if (musb->g.dev.parent)
device_unregister(&musb->g.dev);
} }
/* /*
@ -1977,9 +1853,8 @@ static int musb_gadget_start(struct usb_gadget *g,
goto err; goto err;
} }
if ((musb->xceiv->last_event == USB_EVENT_ID) if (musb->xceiv->last_event == USB_EVENT_ID)
&& otg->set_vbus) musb_platform_set_vbus(musb, 1);
otg_set_vbus(otg, 1);
hcd->self.uses_pio_for_control = 1; hcd->self.uses_pio_for_control = 1;
@ -2063,6 +1938,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
dev_dbg(musb->controller, "unregistering driver %s\n", driver->function); dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
musb->is_active = 0; musb->is_active = 0;
musb->gadget_driver = NULL;
musb_platform_try_idle(musb, 0); musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -2099,7 +1975,7 @@ void musb_g_resume(struct musb *musb)
break; break;
default: default:
WARNING("unhandled RESUME transition (%s)\n", WARNING("unhandled RESUME transition (%s)\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
} }
@ -2129,7 +2005,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too * A_PERIPHERAL may need care too
*/ */
WARNING("unhandled SUSPEND transition (%s)\n", WARNING("unhandled SUSPEND transition (%s)\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
} }
} }
@ -2163,7 +2039,7 @@ void musb_g_disconnect(struct musb *musb)
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
default: default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
otg_state_string(musb->xceiv->state)); usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_A_IDLE; musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb); MUSB_HST_MODE(musb);
break; break;

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