mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 19:00:53 +07:00
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:
commit
64dc9e2e73
@ -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:
|
||||||
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
34
Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
Normal file
34
Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
Normal 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.
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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[] = {
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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 = {
|
||||||
|
@ -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/
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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/
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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>");
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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())
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1003
drivers/usb/gadget/configfs.c
Normal file
1003
drivers/usb/gadget/configfs.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 = {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
@ -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";
|
||||||
|
@ -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";
|
||||||
|
@ -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";
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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_ */
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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 &&
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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__ */
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user