1
0
Fork 0

USB patches for 3.10-rc1

Here's the big USB pull request for 3.10-rc1.
 
 Lots of USB patches here, the majority being USB gadget changes and
 USB-serial driver cleanups, the rest being ARM build fixes / cleanups,
 and individual driver updates.  We also finally got some chipidea fixes,
 which have been delayed for a number of kernel releases, as the
 maintainer has now reappeared.
 
 All of these have been in linux-next for a while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlF+md4ACgkQMUfUDdst+ymkSgCfZWIiCtiX/li0yJqSiRB4yYJx
 Ex0AoNemOOf6ywvSOHPbILTbJ1G+c/PX
 =JmvB
 -----END PGP SIGNATURE-----

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

Pull USB patches from Greg Kroah-Hartman:
 "Here's the big USB pull request for 3.10-rc1.

  Lots of USB patches here, the majority being USB gadget changes and
  USB-serial driver cleanups, the rest being ARM build fixes / cleanups,
  and individual driver updates.  We also finally got some chipidea
  fixes, which have been delayed for a number of kernel releases, as the
  maintainer has now reappeared.

  All of these have been in linux-next for a while"

* tag 'usb-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (568 commits)
  USB: ehci-msm: USB_MSM_OTG needs USB_PHY
  USB: OHCI: avoid conflicting platform drivers
  USB: OMAP: ISP1301 needs USB_PHY
  USB: lpc32xx: ISP1301 needs USB_PHY
  USB: ftdi_sio: enable two UART ports on ST Microconnect Lite
  usb: phy: tegra: don't call into tegra-ehci directly
  usb: phy: phy core cannot yet be a module
  USB: Fix initconst in ehci driver
  usb-storage: CY7C68300A chips do not support Cypress ATACB
  USB: serial: option: Added support Olivetti Olicard 145
  USB: ftdi_sio: correct ST Micro Connect Lite PIDs
  ARM: mxs_defconfig: add CONFIG_USB_PHY
  ARM: imx_v6_v7_defconfig: add CONFIG_USB_PHY
  usb: phy: remove exported function from __init section
  usb: gadget: zero: put function instances on unbind
  usb: gadget: f_sourcesink.c: correct a copy-paste misnomer
  usb: gadget: cdc2: fix error return code in cdc_do_config()
  usb: gadget: multi: fix error return code in rndis_do_config()
  usb: gadget: f_obex: fix error return code in obex_bind()
  USB: storage: convert to use module_usb_driver()
  ...
hifive-unleashed-5.1
Linus Torvalds 2013-04-29 12:19:23 -07:00
commit ec25e246b9
323 changed files with 10616 additions and 9970 deletions

View File

@ -32,7 +32,7 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
If CONFIG_PM_RUNTIME is enabled then this file
is present. When read, it returns the total time (in msec)
that the USB device has been connected to the machine. This
file is read-only.
@ -45,7 +45,7 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
If CONFIG_PM_RUNTIME is enabled then this file
is present. When read, it returns the total time (in msec)
that the USB device has been active, i.e. not in a suspended
state. This file is read-only.
@ -187,7 +187,7 @@ What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
Date: September 2011
Contact: Andiry Xu <andiry.xu@amd.com>
Description:
If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
If CONFIG_PM_RUNTIME is set and a USB 2.0 lpm-capable device
is plugged in to a xHCI host which support link PM, it will
perform a LPM test; if the test is passed and host supports
USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will

View File

@ -11,6 +11,7 @@ Optional properties:
that indicate usb controller index
- vbus-supply: regulator for vbus
- disable-over-current: disable over current detect
- external-vbus-divider: enables off-chip resistor divider for Vbus
Examples:
usb@02184000 { /* USB OTG */
@ -20,4 +21,5 @@ usb@02184000 { /* USB OTG */
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
disable-over-current;
external-vbus-divider;
};

View File

@ -0,0 +1,32 @@
OMAP HS USB EHCI controller
This device is usually the child of the omap-usb-host
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
Required properties:
- compatible: should be "ti,ehci-omap"
- reg: should contain one register range i.e. start and length
- interrupts: description of the interrupt line
Optional properties:
- phys: list of phandles to PHY nodes.
This property is required if at least one of the ports are in
PHY mode i.e. OMAP_EHCI_PORT_MODE_PHY
To specify the port mode, see
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
Example for OMAP4:
usbhsehci: ehci@4a064c00 {
compatible = "ti,ehci-omap", "usb-ehci";
reg = <0x4a064c00 0x400>;
interrupts = <0 77 0x4>;
};
&usbhsehci {
phys = <&hsusb1_phy 0 &hsusb3_phy>;
};

View File

@ -0,0 +1,15 @@
OMAP HS USB OHCI controller (OMAP3 and later)
Required properties:
- compatible: should be "ti,ohci-omap3"
- reg: should contain one register range i.e. start and length
- interrupts: description of the interrupt line
Example for OMAP4:
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3", "usb-ohci";
reg = <0x4a064800 0x400>;
interrupts = <0 76 0x4>;
};

View File

@ -8,10 +8,10 @@ OMAP MUSB GLUE
and disconnect.
- multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting.
- num_eps : Specifies the number of endpoints. This is also a
- num-eps : Specifies the number of endpoints. This is also a
MUSB configuration-specific setting. Should be set to "16"
- 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
- 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 between the controller and the phy. It should be "0" or "1"
specifying ULPI and UTMI respectively.
- 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,has-mailbox;
multipoint = <1>;
num_eps = <16>;
ram_bits = <12>;
num-eps = <16>;
ram-bits = <12>;
ctrl-module = <&omap_control_usb>;
};
Board specific device node entry
&usb_otg_hs {
interface_type = <1>;
interface-type = <1>;
mode = <3>;
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
Required properties:

View File

@ -1,20 +1,25 @@
* Samsung's usb phy transceiver
SAMSUNG USB-PHY controllers
The Samsung's phy transceiver is used for controlling usb phy for
s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
across Samsung SOCs.
** Samsung's usb 2.0 phy transceiver
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
developement generic PHY driver.
Required properties:
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
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:
- 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
region.
@ -44,12 +49,69 @@ Example:
usbphy@125B0000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "samsung,exynos4210-usbphy";
compatible = "samsung,exynos4210-usb2phy";
reg = <0x125B0000 0x100>;
ranges;
clocks = <&clock 2>, <&clock 305>;
clock-names = "xusbxti", "otg";
usbphy-sys {
/* USB device and host PHY_CONTROL registers */
reg = <0x10020704 0x8>;
};
};
** Samsung's usb 3.0 phy transceiver
Starting exynso5250, Samsung's SoC have usb 3.0 phy transceiver
which is used for controlling usb 3.0 phy for dwc3-exynos usb 3.0
controllers across Samsung SOCs.
Required properties:
Exynos5250:
- compatible : should be "samsung,exynos5250-usb3phy"
- reg : base physical address of the phy registers and length of memory mapped
region.
- clocks: Clock IDs array as required by the controller.
- clock-names: names of clocks correseponding to IDs in the clock property
as requested by the controller driver.
Optional properties:
- #address-cells: should be '1' when usbphy node has a child node with 'reg'
property.
- #size-cells: should be '1' when usbphy node has a child node with 'reg'
property.
- ranges: allows valid translation between child's address space and parent's
address space.
- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
interface for usb-phy. It should provide the following information required by
usb-phy controller to control phy.
- reg : base physical address of PHY_CONTROL registers.
The size of this register is the total sum of size of all PHY_CONTROL
registers that the SoC has. For example, the size will be
'0x4' in case we have only one PHY_CONTROL register (e.g.
OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
and, '0x8' in case we have two PHY_CONTROL registers (e.g.
USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
and so on.
Example:
usbphy@12100000 {
compatible = "samsung,exynos5250-usb3phy";
reg = <0x12100000 0x100>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&clock 1>, <&clock 286>;
clock-names = "ext_xtal", "usbdrd30";
usbphy-sys {
/* USB device and host PHY_CONTROL registers */
reg = <0x10040704 0x8>;
};
};

View File

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

View File

@ -131,6 +131,7 @@ Code Seq#(hex) Include File Comments
'H' 40-4F sound/hdspm.h conflict!
'H' 40-4F sound/hdsp.h conflict!
'H' 90 sound/usb/usx2y/usb_stream.h
'H' A0 uapi/linux/usb/cdc-wdm.h
'H' C0-F0 net/bluetooth/hci.h conflict!
'H' C0-DF net/bluetooth/hidp/hidp.h conflict!
'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict!

View File

@ -33,6 +33,10 @@ built with CONFIG_USB_SUSPEND enabled (which depends on
CONFIG_PM_RUNTIME). System PM support is present only if the kernel
was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
(Starting with the 3.10 kernel release, dynamic PM support for USB is
present whenever the kernel was built with CONFIG_PM_RUNTIME enabled.
The CONFIG_USB_SUSPEND option has been eliminated.)
What is Remote Wakeup?
----------------------
@ -206,10 +210,8 @@ initialized to 5. (The idle-delay values for already existing devices
will not be affected.)
Setting the initial default idle-delay to -1 will prevent any
autosuspend of any USB device. This is a simple alternative to
disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
added benefit of allowing you to enable autosuspend for selected
devices.
autosuspend of any USB device. This has the benefit of allowing you
then to enable autosuspend for selected devices.
Warnings

View File

@ -549,6 +549,8 @@ config ARCH_IXP4XX
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI
select NEED_MACH_IO_H
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
help
Support for Intel's IXP4XX (XScale) family of processors.

View File

@ -188,6 +188,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MXC=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_PHY=y
CONFIG_USB_MXS_PHY=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y

View File

@ -134,6 +134,7 @@ CONFIG_SND_DEBUG_VERBOSE=y
# CONFIG_SND_SPI is not set
CONFIG_SND_SOC=y
CONFIG_USB=y
CONFIG_USB_PHY=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_USB_GADGET=y

View File

@ -120,6 +120,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_STORAGE=y
CONFIG_USB_PHY=y
CONFIG_USB_MXS_PHY=y
CONFIG_MMC=y
CONFIG_MMC_MXS=y

View File

@ -195,6 +195,7 @@ CONFIG_SND_SOC=y
CONFIG_SND_OMAP_SOC=y
# CONFIG_USB_HID is not set
CONFIG_USB=y
CONFIG_USB_PHY=y
CONFIG_USB_DEBUG=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set

View File

@ -204,9 +204,9 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return exynos4210_usb_phy0_init(pdev);
else if (type == S5P_USB_PHY_HOST)
else if (type == USB_PHY_TYPE_HOST)
return exynos4210_usb_phy1_init(pdev);
return -EINVAL;
@ -214,9 +214,9 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return exynos4210_usb_phy0_exit(pdev);
else if (type == S5P_USB_PHY_HOST)
else if (type == USB_PHY_TYPE_HOST)
return exynos4210_usb_phy1_exit(pdev);
return -EINVAL;

View File

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

View File

@ -162,13 +162,7 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
#ifdef CONFIG_USB_SUPPORT
#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 = {
.clknum = 1,
.clkname = pxa910_usb_clock_name,
.vbus = NULL,
.mode = MV_USB_MODE_OTG,
.otg_force_a_bus_req = 1,

View File

@ -76,7 +76,7 @@ static int s3c_usb_otgphy_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return s3c_usb_otgphy_init(pdev);
return -EINVAL;
@ -84,7 +84,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return s3c_usb_otgphy_exit(pdev);
return -EINVAL;

View File

@ -80,7 +80,7 @@ static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return s5pv210_usb_otgphy_init(pdev);
return -EINVAL;
@ -88,7 +88,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
if (type == USB_PHY_TYPE_DEVICE)
return s5pv210_usb_otgphy_exit(pdev);
return -EINVAL;

View File

@ -169,7 +169,7 @@ static int usbhsf_get_id(struct platform_device *pdev)
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)
{
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->usb24); /* usb work around */
}
return 0;
}
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;
}
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);
@ -264,6 +266,8 @@ static void usbhsf_hardware_exit(struct platform_device *pdev)
priv->usbh_base = NULL;
free_irq(IRQ7, pdev);
return 0;
}
static int usbhsf_hardware_init(struct platform_device *pdev)

View File

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

View File

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

View File

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

View File

@ -11,10 +11,7 @@
#ifndef __PLAT_SAMSUNG_USB_PHY_H
#define __PLAT_SAMSUNG_USB_PHY_H __FILE__
enum s5p_usb_phy_type {
S5P_USB_PHY_DEVICE,
S5P_USB_PHY_HOST,
};
#include <linux/usb/samsung_usb_phy.h>
extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);

View File

@ -404,6 +404,8 @@ config PMC_MSP
select IRQ_CPU
select SERIAL_8250
select SERIAL_8250_CONSOLE
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
help
This adds support for the PMC-Sierra family of Multi-Service
Processor System-On-A-Chips. These parts include a number
@ -1433,6 +1435,7 @@ config CPU_CAVIUM_OCTEON
select CPU_SUPPORTS_HUGEPAGES
select LIBFDT
select USE_OF
select USB_EHCI_BIG_ENDIAN_MMIO
help
The Cavium Octeon processor is a highly integrated chip containing
many ethernet hardware widgets for networking tasks. The processor

View File

@ -274,6 +274,8 @@ config 440EPX
select IBM_EMAC_EMAC4
select IBM_EMAC_RGMII
select IBM_EMAC_ZMII
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
config 440GRX
bool

View File

@ -7,6 +7,8 @@ config PPC_MPC512x
select PPC_PCI_CHOICE
select FSL_PCI if PCI
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
config MPC5121_ADS
bool "Freescale MPC5121E ADS"

View File

@ -254,11 +254,13 @@ static int usbhs_get_id(struct platform_device *pdev)
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 */
if (!gpio_get_value(GPIO_PTB3))
gpio_set_value(GPIO_PTB5, 1);
return 0;
}
static struct renesas_usbhs_platform_info usbhs_info = {

View File

@ -407,6 +407,8 @@ config SERIAL_CONSOLE
config SPARC_LEON
bool "Sparc Leon processor family"
depends on SPARC32
select USB_EHCI_BIG_ENDIAN_MMIO
select USB_EHCI_BIG_ENDIAN_DESC
---help---
If you say Y here if you are running on a SPARC-LEON processor.
The LEON processor is a synthesizable VHDL model of the

View File

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

View File

@ -1493,7 +1493,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
int status;
int status = 0;
bool driver_suspended = false;
if (PMSG_IS_AUTO(message)) {
@ -1520,19 +1520,15 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
}
} else {
if (hid->driver && hid->driver->suspend) {
/* TODO: resume() might need to handle suspend failure */
if (hid->driver && hid->driver->suspend)
status = hid->driver->suspend(hid, message);
if (status < 0)
return status;
}
driver_suspended = true;
spin_lock_irq(&usbhid->lock);
set_bit(HID_SUSPENDED, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
if (usbhid_wait_io(hid) < 0) {
if (usbhid_wait_io(hid) < 0)
status = -EIO;
goto failed;
}
}
hid_cancel_delayed_stuff(usbhid);
@ -1544,7 +1540,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
goto failed;
}
dev_dbg(&intf->dev, "suspend\n");
return 0;
return status;
failed:
hid_resume_common(hid, driver_suspended);

View File

@ -323,6 +323,11 @@ static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)
goto error;
}
/*
* Both usbnet_suspend() and subdriver->suspend() MUST return 0
* in system sleep context, otherwise, the resume callback has
* to recover device from previous suspend failure.
*/
ret = usbnet_suspend(intf, message);
if (ret < 0)
goto error;

View File

@ -374,6 +374,11 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
struct qmi_wwan_state *info = (void *)&dev->data;
int ret;
/*
* Both usbnet_suspend() and subdriver->suspend() MUST return 0
* in system sleep context, otherwise, the resume callback has
* to recover device from previous suspend failure.
*/
ret = usbnet_suspend(intf, message);
if (ret < 0)
goto err;

View File

@ -2015,7 +2015,11 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc75xx_enter_suspend0(dev);
done:
if (ret)
/*
* TODO: resume() might need to handle the suspend failure
* in system sleep
*/
if (ret && PMSG_IS_AUTO(message))
usbnet_resume(intf);
return ret;
}

View File

@ -1660,7 +1660,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc95xx_enter_suspend0(dev);
done:
if (ret)
/*
* TODO: resume() might need to handle the suspend failure
* in system sleep
*/
if (ret && PMSG_IS_AUTO(message))
usbnet_resume(intf);
return ret;
}

View File

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

View File

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

View File

@ -122,9 +122,9 @@ config USB
To compile this driver as a module, choose M here: the
module will be called usbcore.
source "drivers/usb/core/Kconfig"
if USB
source "drivers/usb/dwc3/Kconfig"
source "drivers/usb/core/Kconfig"
source "drivers/usb/mon/Kconfig"
@ -134,8 +134,6 @@ source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
source "drivers/usb/chipidea/Kconfig"
source "drivers/usb/renesas_usbhs/Kconfig"
source "drivers/usb/class/Kconfig"
@ -144,12 +142,19 @@ source "drivers/usb/storage/Kconfig"
source "drivers/usb/image/Kconfig"
endif
source "drivers/usb/dwc3/Kconfig"
source "drivers/usb/chipidea/Kconfig"
comment "USB port drivers"
depends on USB
if USB
config USB_USS720
tristate "USS720 parport driver"
depends on USB && PARPORT
depends on PARPORT
select PARPORT_NOT_PC
---help---
This driver is for USB parallel port adapters that use the Lucent
@ -180,12 +185,12 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
source "drivers/usb/phy/Kconfig"
source "drivers/usb/atm/Kconfig"
endif # USB
source "drivers/usb/phy/Kconfig"
source "drivers/usb/gadget/Kconfig"
source "drivers/usb/otg/Kconfig"
endif # USB_SUPPORT

View File

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

View File

@ -4,7 +4,7 @@
menuconfig USB_ATM
tristate "USB DSL modem support"
depends on USB && ATM
depends on ATM
select CRC32
default n
help

View File

@ -672,9 +672,6 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
struct usbatm_control *ctrl = UDSL_SKB(skb);
int err;
vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
skb, skb->len);
/* racy disconnection check - fine */
if (!instance || instance->disconnected) {
#ifdef DEBUG
@ -684,6 +681,9 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
goto fail;
}
vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
skb, skb->len);
if (vcc->qos.aal != ATM_AAL5) {
atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
err = -EINVAL;

View File

@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)
endif
ifneq ($(CONFIG_OF_DEVICE),)
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
endif

View File

@ -21,6 +21,7 @@
/******************************************************************************
* DEFINE
*****************************************************************************/
#define TD_PAGE_COUNT 5
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
@ -129,6 +130,7 @@ struct hw_bank {
* @vbus_active: is VBUS active
* @transceiver: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
*/
struct ci13xxx {
struct device *dev;
@ -139,7 +141,6 @@ struct ci13xxx {
enum ci_role role;
bool is_otg;
struct work_struct work;
struct work_struct vbus_work;
struct workqueue_struct *wq;
struct dma_pool *qh_pool;
@ -165,6 +166,7 @@ struct ci13xxx {
bool global_phy;
struct usb_phy *transceiver;
struct usb_hcd *hcd;
struct dentry *debugfs;
};
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@ -233,19 +235,6 @@ enum ci13xxx_regs {
OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
};
/**
* ffs_nr: find first (least significant) bit set
* @x: the word to search
*
* This function returns bit number (instead of position)
*/
static inline int ffs_nr(u32 x)
{
int n = ffs(x);
return n ? n-1 : 32;
}
/**
* hw_read: reads from a hw register
* @reg: register index
@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
u32 val = hw_read(ci, reg, ~0);
hw_write(ci, reg, mask, data);
return (val & mask) >> ffs_nr(mask);
return (val & mask) >> __ffs(mask);
}
int hw_device_reset(struct ci13xxx *ci, u32 mode);

View File

@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
if (of_find_property(np, "disable-over-current", NULL))
usbdev->disable_oc = 1;
if (of_find_property(np, "external-vbus-divider", NULL))
usbdev->evdo = 1;
return 0;
}
EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
goto err;
}
if (usbmisc_ops && usbmisc_ops->post) {
ret = usbmisc_ops->post(&pdev->dev);
if (ret) {
dev_err(&pdev->dev,
"usbmisc post failed, ret=%d\n", ret);
goto put_np;
}
}
data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);

View File

@ -13,6 +13,8 @@
struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct device *dev);
/* It's called once after adding a usb device */
int (*post)(struct device *dev);
};
struct usbmisc_usb_device {
@ -20,6 +22,7 @@ struct usbmisc_usb_device {
int index;
unsigned int disable_oc:1; /* over current detect disabled */
unsigned int evdo:1; /* set external vbus divider option */
};
int usbmisc_set_ops(const struct usbmisc_ops *ops);

View File

@ -23,17 +23,17 @@
/******************************************************************************
* PCI block
*****************************************************************************/
struct ci13xxx_platform_data pci_platdata = {
static struct ci13xxx_platform_data pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = DEF_CAPOFFSET,
};
struct ci13xxx_platform_data langwell_pci_platdata = {
static struct ci13xxx_platform_data langwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
};
struct ci13xxx_platform_data penwell_pci_platdata = {
static struct ci13xxx_platform_data penwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
.power_budget = 200,

View File

@ -51,15 +51,12 @@
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
if (mode > TEST_MODE_MAX)
return -EINVAL;
hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));
return 0;
}
@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
*/
u8 hw_port_test_get(struct ci13xxx *ci)
{
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.cap = ci->hw_bank.abs;
ci->hw_bank.cap += ci->platdata->capoffset;
ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);
hw_alloc_regmap(ci, false);
reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
ffs_nr(HCCPARAMS_LEN);
__ffs(HCCPARAMS_LEN);
ci->hw_bank.lpm = reg;
hw_alloc_regmap(ci, !!reg);
ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.size /= sizeof(u32);
reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
ffs_nr(DCCPARAMS_DEN);
__ffs(DCCPARAMS_DEN);
ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
if (ci->hw_ep_max > ENDPT_MAX)
@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)
}
}
static ssize_t show_role(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci13xxx *ci = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", ci_role(ci)->name);
}
static ssize_t store_role(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci13xxx *ci = dev_get_drvdata(dev);
enum ci_role role;
int ret;
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
break;
if (role == CI_ROLE_END || role == ci->role)
return -EINVAL;
ci_role_stop(ci);
ret = ci_role_start(ci, role);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
static irqreturn_t ci_irq(int irq, void *data)
{
struct ci13xxx *ci = data;
@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
base = devm_request_and_ioremap(dev, res);
if (!base) {
dev_err(dev, "can't request and ioremap resource\n");
return -ENOMEM;
}
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
if (!ci) {
@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (ret)
goto stop;
ret = device_create_file(dev, &dev_attr_role);
if (ret)
goto rm_attr;
if (ci->is_otg)
hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
return ret;
ret = dbg_create_files(ci);
if (!ret)
return 0;
rm_attr:
device_remove_file(dev, &dev_attr_role);
free_irq(ci->irq, ci);
stop:
ci_role_stop(ci);
rm_wq:
@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
{
struct ci13xxx *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
flush_workqueue(ci->wq);
destroy_workqueue(ci->wq);
device_remove_file(ci->dev, &dev_attr_role);
free_irq(ci->irq, ci);
ci_role_stop(ci);

View File

@ -1,590 +1,126 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "debug.h"
/* Interrupt statistics */
#define ISR_MASK 0x1F
static struct isr_statistics {
u32 test;
u32 ui;
u32 uei;
u32 pci;
u32 uri;
u32 sli;
u32 none;
struct {
u32 cnt;
u32 buf[ISR_MASK+1];
u32 idx;
} hndl;
} isr_statistics;
void dbg_interrupt(u32 intmask)
{
if (!intmask) {
isr_statistics.none++;
return;
}
isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
isr_statistics.hndl.idx &= ISR_MASK;
isr_statistics.hndl.cnt++;
if (USBi_URI & intmask)
isr_statistics.uri++;
if (USBi_PCI & intmask)
isr_statistics.pci++;
if (USBi_UEI & intmask)
isr_statistics.uei++;
if (USBi_UI & intmask)
isr_statistics.ui++;
if (USBi_SLI & intmask)
isr_statistics.sli++;
}
/**
* hw_register_read: reads all device registers (execute without interruption)
* @buf: destination buffer
* @size: buffer size
*
* This function returns number of registers read
* ci_device_show: prints information about device capabilities and status
*/
static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
static int ci_device_show(struct seq_file *s, void *data)
{
unsigned i;
if (size > ci->hw_bank.size)
size = ci->hw_bank.size;
for (i = 0; i < size; i++)
buf[i] = hw_read(ci, i * sizeof(u32), ~0);
return size;
}
/**
* hw_register_write: writes to register
* @addr: register address
* @data: register value
*
* This function returns an error code
*/
static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
{
/* align */
addr /= sizeof(u32);
if (addr >= ci->hw_bank.size)
return -EINVAL;
/* align */
addr *= sizeof(u32);
hw_write(ci, addr, ~0, data);
return 0;
}
/**
* hw_intr_clear: disables interrupt & clears interrupt status (execute without
* interruption)
* @n: interrupt bit
*
* This function returns an error code
*/
static int hw_intr_clear(struct ci13xxx *ci, int n)
{
if (n >= REG_BITS)
return -EINVAL;
hw_write(ci, OP_USBINTR, BIT(n), 0);
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
return 0;
}
/**
* hw_intr_force: enables interrupt & forces interrupt status (execute without
* interruption)
* @n: interrupt bit
*
* This function returns an error code
*/
static int hw_intr_force(struct ci13xxx *ci, int n)
{
if (n >= REG_BITS)
return -EINVAL;
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
return 0;
}
/**
* show_device: prints information about device capabilities and status
*
* Check "device.h" for details
*/
static ssize_t show_device(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct ci13xxx *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
int n = 0;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
seq_printf(s, "speed = %d\n", gadget->speed);
seq_printf(s, "max_speed = %d\n", gadget->max_speed);
seq_printf(s, "is_otg = %d\n", gadget->is_otg);
seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral);
seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable);
seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support);
seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
seq_printf(s, "name = %s\n",
(gadget->name ? gadget->name : ""));
if (!ci->driver)
return 0;
}
n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
gadget->speed);
n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
gadget->max_speed);
n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
gadget->is_otg);
n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
gadget->is_a_peripheral);
n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
gadget->b_hnp_enable);
n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
gadget->a_hnp_support);
n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
gadget->a_alt_hnp_support);
n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
(gadget->name ? gadget->name : ""));
seq_printf(s, "gadget function = %s\n",
(ci->driver->function ? ci->driver->function : ""));
seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed);
return n;
return 0;
}
static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
/**
* show_driver: prints information about attached gadget (if any)
*
* Check "device.h" for details
*/
static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
char *buf)
static int ci_device_open(struct inode *inode, struct file *file)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct usb_gadget_driver *driver = ci->driver;
int n = 0;
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
return 0;
}
if (driver == NULL)
return scnprintf(buf, PAGE_SIZE,
"There is no gadget attached!\n");
n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
(driver->function ? driver->function : ""));
n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
driver->max_speed);
return n;
return single_open(file, ci_device_show, inode->i_private);
}
static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
/* Maximum event message length */
#define DBG_DATA_MSG 64UL
/* Maximum event messages */
#define DBG_DATA_MAX 128UL
/* Event buffer descriptor */
static struct {
char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
unsigned idx; /* index */
unsigned tty; /* print to console? */
rwlock_t lck; /* lock */
} dbg_data = {
.idx = 0,
.tty = 0,
.lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
static const struct file_operations ci_device_fops = {
.open = ci_device_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* dbg_dec: decrements debug event index
* @idx: buffer index
* ci_port_test_show: reads port test mode
*/
static void dbg_dec(unsigned *idx)
static int ci_port_test_show(struct seq_file *s, void *data)
{
*idx = (*idx - 1) & (DBG_DATA_MAX-1);
}
/**
* dbg_inc: increments debug event index
* @idx: buffer index
*/
static void dbg_inc(unsigned *idx)
{
*idx = (*idx + 1) & (DBG_DATA_MAX-1);
}
/**
* dbg_print: prints the common part of the event
* @addr: endpoint address
* @name: event name
* @status: status
* @extra: extra information
*/
static void dbg_print(u8 addr, const char *name, int status, const char *extra)
{
struct timeval tval;
unsigned int stamp;
unsigned long flags;
write_lock_irqsave(&dbg_data.lck, flags);
do_gettimeofday(&tval);
stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
stamp = stamp * 1000000 + tval.tv_usec;
scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
"%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra);
dbg_inc(&dbg_data.idx);
write_unlock_irqrestore(&dbg_data.lck, flags);
if (dbg_data.tty != 0)
pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra);
}
/**
* dbg_done: prints a DONE event
* @addr: endpoint address
* @td: transfer descriptor
* @status: status
*/
void dbg_done(u8 addr, const u32 token, int status)
{
char msg[DBG_DATA_MSG];
scnprintf(msg, sizeof(msg), "%d %02X",
(int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
(int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
dbg_print(addr, "DONE", status, msg);
}
/**
* dbg_event: prints a generic event
* @addr: endpoint address
* @name: event name
* @status: status
*/
void dbg_event(u8 addr, const char *name, int status)
{
if (name != NULL)
dbg_print(addr, name, status, "");
}
/*
* dbg_queue: prints a QUEUE event
* @addr: endpoint address
* @req: USB request
* @status: status
*/
void dbg_queue(u8 addr, const struct usb_request *req, int status)
{
char msg[DBG_DATA_MSG];
if (req != NULL) {
scnprintf(msg, sizeof(msg),
"%d %d", !req->no_interrupt, req->length);
dbg_print(addr, "QUEUE", status, msg);
}
}
/**
* dbg_setup: prints a SETUP event
* @addr: endpoint address
* @req: setup request
*/
void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
{
char msg[DBG_DATA_MSG];
if (req != NULL) {
scnprintf(msg, sizeof(msg),
"%02X %02X %04X %04X %d", req->bRequestType,
req->bRequest, le16_to_cpu(req->wValue),
le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
dbg_print(addr, "SETUP", 0, msg);
}
}
/**
* show_events: displays the event buffer
*
* Check "device.h" for details
*/
static ssize_t show_events(struct device *dev, struct device_attribute *attr,
char *buf)
{
unsigned long flags;
unsigned i, j, n = 0;
if (attr == NULL || buf == NULL) {
dev_err(dev->parent, "[%s] EINVAL\n", __func__);
return 0;
}
read_lock_irqsave(&dbg_data.lck, flags);
i = dbg_data.idx;
for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
n += strlen(dbg_data.buf[i]);
if (n >= PAGE_SIZE) {
n -= strlen(dbg_data.buf[i]);
break;
}
}
for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
j += scnprintf(buf + j, PAGE_SIZE - j,
"%s", dbg_data.buf[i]);
read_unlock_irqrestore(&dbg_data.lck, flags);
return n;
}
/**
* store_events: configure if events are going to be also printed to console
*
* Check "device.h" for details
*/
static ssize_t store_events(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned tty;
if (attr == NULL || buf == NULL) {
dev_err(dev, "[%s] EINVAL\n", __func__);
goto done;
}
if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
dev_err(dev, "<1|0>: enable|disable console log\n");
goto done;
}
dbg_data.tty = tty;
dev_info(dev, "tty = %u", dbg_data.tty);
done:
return count;
}
static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
/**
* show_inters: interrupt status, enable status and historic
*
* Check "device.h" for details
*/
static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
u32 intr;
unsigned i, j, n = 0;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
/*n += scnprintf(buf + n, PAGE_SIZE - n,
"status = %08x\n", hw_read_intr_status(ci));
n += scnprintf(buf + n, PAGE_SIZE - n,
"enable = %08x\n", hw_read_intr_enable(ci));*/
n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
isr_statistics.test);
n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
isr_statistics.ui);
n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
isr_statistics.uei);
n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
isr_statistics.pci);
n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
isr_statistics.uri);
n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
isr_statistics.sli);
n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
isr_statistics.none);
n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
isr_statistics.hndl.cnt);
for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
i &= ISR_MASK;
intr = isr_statistics.hndl.buf[i];
if (USBi_UI & intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
intr &= ~USBi_UI;
if (USBi_UEI & intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
intr &= ~USBi_UEI;
if (USBi_PCI & intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
intr &= ~USBi_PCI;
if (USBi_URI & intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
intr &= ~USBi_URI;
if (USBi_SLI & intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
intr &= ~USBi_SLI;
if (intr)
n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
if (isr_statistics.hndl.buf[i])
n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
}
spin_unlock_irqrestore(&ci->lock, flags);
return n;
}
/**
* store_inters: enable & force or disable an individual interrutps
* (to be used for test purposes only)
*
* Check "device.h" for details
*/
static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
unsigned en, bit;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "EINVAL\n");
goto done;
}
if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
goto done;
}
spin_lock_irqsave(&ci->lock, flags);
if (en) {
if (hw_intr_force(ci, bit))
dev_err(dev, "invalid bit number\n");
else
isr_statistics.test++;
} else {
if (hw_intr_clear(ci, bit))
dev_err(dev, "invalid bit number\n");
}
spin_unlock_irqrestore(&ci->lock, flags);
done:
return count;
}
static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
/**
* show_port_test: reads port test mode
*
* Check "device.h" for details
*/
static ssize_t show_port_test(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct ci13xxx *ci = s->private;
unsigned long flags;
unsigned mode;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "EINVAL\n");
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags);
return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
seq_printf(s, "mode = %u\n", mode);
return 0;
}
/**
* store_port_test: writes port test mode
*
* Check "device.h" for details
* ci_port_test_write: writes port test mode
*/
static ssize_t store_port_test(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct seq_file *s = file->private_data;
struct ci13xxx *ci = s->private;
unsigned long flags;
unsigned mode;
char buf[32];
int ret;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
goto done;
}
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (sscanf(buf, "%u", &mode) != 1) {
dev_err(ci->dev, "<mode>: set port test mode");
goto done;
}
if (sscanf(buf, "%u", &mode) != 1)
return -EINVAL;
spin_lock_irqsave(&ci->lock, flags);
if (hw_port_test_set(ci, mode))
dev_err(ci->dev, "invalid mode\n");
ret = hw_port_test_set(ci, mode);
spin_unlock_irqrestore(&ci->lock, flags);
done:
return count;
return ret ? ret : count;
}
static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
show_port_test, store_port_test);
static int ci_port_test_open(struct inode *inode, struct file *file)
{
return single_open(file, ci_port_test_show, inode->i_private);
}
static const struct file_operations ci_port_test_fops = {
.open = ci_port_test_open,
.write = ci_port_test_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* show_qheads: DMA contents of all queue heads
*
* Check "device.h" for details
* ci_qheads_show: DMA contents of all queue heads
*/
static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
char *buf)
static int ci_qheads_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct ci13xxx *ci = s->private;
unsigned long flags;
unsigned i, j, n = 0;
unsigned i, j;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
if (ci->role != CI_ROLE_GADGET) {
seq_printf(s, "not in gadget mode\n");
return 0;
}
@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx =
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
n += scnprintf(buf + n, PAGE_SIZE - n,
"EP=%02i: RX=%08X TX=%08X\n",
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
n += scnprintf(buf + n, PAGE_SIZE - n,
" %04X: %08X %08X\n", j,
*((u32 *)mEpRx->qh.ptr + j),
*((u32 *)mEpTx->qh.ptr + j));
}
seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
seq_printf(s, " %04X: %08X %08X\n", j,
*((u32 *)mEpRx->qh.ptr + j),
*((u32 *)mEpTx->qh.ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
return n;
}
static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
/**
* show_registers: dumps all registers
*
* Check "device.h" for details
*/
#define DUMP_ENTRIES 512
static ssize_t show_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
u32 *dump;
unsigned i, k, n = 0;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
return 0;
}
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
if (!dump) {
dev_err(ci->dev, "%s: out of memory\n", __func__);
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
k = hw_register_read(ci, dump, DUMP_ENTRIES);
spin_unlock_irqrestore(&ci->lock, flags);
for (i = 0; i < k; i++) {
n += scnprintf(buf + n, PAGE_SIZE - n,
"reg[0x%04X] = 0x%08X\n",
i * (unsigned)sizeof(u32), dump[i]);
}
kfree(dump);
return n;
return 0;
}
/**
* store_registers: writes value to register address
*
* Check "device.h" for details
*/
static ssize_t store_registers(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
static int ci_qheads_open(struct inode *inode, struct file *file)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long addr, data, flags;
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
goto done;
}
if (sscanf(buf, "%li %li", &addr, &data) != 2) {
dev_err(ci->dev,
"<addr> <data>: write data to register address\n");
goto done;
}
spin_lock_irqsave(&ci->lock, flags);
if (hw_register_write(ci, addr, data))
dev_err(ci->dev, "invalid address range\n");
spin_unlock_irqrestore(&ci->lock, flags);
done:
return count;
return single_open(file, ci_qheads_show, inode->i_private);
}
static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
show_registers, store_registers);
static const struct file_operations ci_qheads_fops = {
.open = ci_qheads_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* show_requests: DMA contents of all requests currently queued (all endpts)
*
* Check "device.h" for details
* ci_requests_show: DMA contents of all requests currently queued (all endpts)
*/
static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
char *buf)
static int ci_requests_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
struct ci13xxx *ci = s->private;
unsigned long flags;
struct list_head *ptr = NULL;
struct ci13xxx_req *req = NULL;
unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
if (attr == NULL || buf == NULL) {
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
if (ci->role != CI_ROLE_GADGET) {
seq_printf(s, "not in gadget mode\n");
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++)
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
{
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
n += scnprintf(buf + n, PAGE_SIZE - n,
"EP=%02i: TD=%08X %s\n",
i % ci->hw_ep_max/2, (u32)req->dma,
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
seq_printf(s, "EP=%02i: TD=%08X %s\n",
i % (ci->hw_ep_max / 2), (u32)req->dma,
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
for (j = 0; j < qSize; j++)
n += scnprintf(buf + n, PAGE_SIZE - n,
" %04X: %08X\n", j,
*((u32 *)req->ptr + j));
for (j = 0; j < qsize; j++)
seq_printf(s, " %04X: %08X\n", j,
*((u32 *)req->ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
return n;
return 0;
}
static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
static int ci_requests_open(struct inode *inode, struct file *file)
{
return single_open(file, ci_requests_show, inode->i_private);
}
static const struct file_operations ci_requests_fops = {
.open = ci_requests_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int ci_role_show(struct seq_file *s, void *data)
{
struct ci13xxx *ci = s->private;
seq_printf(s, "%s\n", ci_role(ci)->name);
return 0;
}
static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct ci13xxx *ci = s->private;
enum ci_role role;
char buf[8];
int ret;
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
if (ci->roles[role] &&
!strncmp(buf, ci->roles[role]->name,
strlen(ci->roles[role]->name)))
break;
if (role == CI_ROLE_END || role == ci->role)
return -EINVAL;
ci_role_stop(ci);
ret = ci_role_start(ci, role);
return ret ? ret : count;
}
static int ci_role_open(struct inode *inode, struct file *file)
{
return single_open(file, ci_role_show, inode->i_private);
}
static const struct file_operations ci_role_fops = {
.open = ci_role_open,
.write = ci_role_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* dbg_create_files: initializes the attribute interface
* @dev: device
* @ci: device
*
* This function returns an error code
*/
int dbg_create_files(struct device *dev)
int dbg_create_files(struct ci13xxx *ci)
{
int retval = 0;
struct dentry *dent;
if (dev == NULL)
return -EINVAL;
retval = device_create_file(dev, &dev_attr_device);
if (retval)
goto done;
retval = device_create_file(dev, &dev_attr_driver);
if (retval)
goto rm_device;
retval = device_create_file(dev, &dev_attr_events);
if (retval)
goto rm_driver;
retval = device_create_file(dev, &dev_attr_inters);
if (retval)
goto rm_events;
retval = device_create_file(dev, &dev_attr_port_test);
if (retval)
goto rm_inters;
retval = device_create_file(dev, &dev_attr_qheads);
if (retval)
goto rm_port_test;
retval = device_create_file(dev, &dev_attr_registers);
if (retval)
goto rm_qheads;
retval = device_create_file(dev, &dev_attr_requests);
if (retval)
goto rm_registers;
return 0;
ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
if (!ci->debugfs)
return -ENOMEM;
rm_registers:
device_remove_file(dev, &dev_attr_registers);
rm_qheads:
device_remove_file(dev, &dev_attr_qheads);
rm_port_test:
device_remove_file(dev, &dev_attr_port_test);
rm_inters:
device_remove_file(dev, &dev_attr_inters);
rm_events:
device_remove_file(dev, &dev_attr_events);
rm_driver:
device_remove_file(dev, &dev_attr_driver);
rm_device:
device_remove_file(dev, &dev_attr_device);
done:
return retval;
dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
&ci_device_fops);
if (!dent)
goto err;
dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
ci, &ci_port_test_fops);
if (!dent)
goto err;
dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
&ci_qheads_fops);
if (!dent)
goto err;
dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
&ci_requests_fops);
if (!dent)
goto err;
dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
&ci_role_fops);
if (dent)
return 0;
err:
debugfs_remove_recursive(ci->debugfs);
return -ENOMEM;
}
/**
* dbg_remove_files: destroys the attribute interface
* @dev: device
*
* This function returns an error code
* @ci: device
*/
int dbg_remove_files(struct device *dev)
void dbg_remove_files(struct ci13xxx *ci)
{
if (dev == NULL)
return -EINVAL;
device_remove_file(dev, &dev_attr_requests);
device_remove_file(dev, &dev_attr_registers);
device_remove_file(dev, &dev_attr_qheads);
device_remove_file(dev, &dev_attr_port_test);
device_remove_file(dev, &dev_attr_inters);
device_remove_file(dev, &dev_attr_events);
device_remove_file(dev, &dev_attr_driver);
device_remove_file(dev, &dev_attr_device);
return 0;
debugfs_remove_recursive(ci->debugfs);
}

View File

@ -14,42 +14,16 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
void dbg_interrupt(u32 intmask);
void dbg_done(u8 addr, const u32 token, int status);
void dbg_event(u8 addr, const char *name, int status);
void dbg_queue(u8 addr, const struct usb_request *req, int status);
void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
int dbg_create_files(struct device *dev);
int dbg_remove_files(struct device *dev);
int dbg_create_files(struct ci13xxx *ci);
void dbg_remove_files(struct ci13xxx *ci);
#else
static inline void dbg_interrupt(u32 intmask)
{
}
static inline void dbg_done(u8 addr, const u32 token, int status)
{
}
static inline void dbg_event(u8 addr, const char *name, int status)
{
}
static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
{
}
static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
{
}
static inline int dbg_create_files(struct device *dev)
static inline int dbg_create_files(struct ci13xxx *ci)
{
return 0;
}
static inline int dbg_remove_files(struct device *dev)
static inline void dbg_remove_files(struct ci13xxx *ci)
{
return 0;
}
#endif

View File

@ -13,14 +13,8 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
if (dir) {
mask = ENDPTCTRL_TXT; /* type */
data = type << ffs_nr(mask);
data = type << __ffs(mask);
mask |= ENDPTCTRL_TXS; /* unstall */
mask |= ENDPTCTRL_TXR; /* reset data toggle */
@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
data |= ENDPTCTRL_TXE;
} else {
mask = ENDPTCTRL_RXT; /* type */
data = type << ffs_nr(mask);
data = type << __ffs(mask);
mask |= ENDPTCTRL_RXS; /* unstall */
mask |= ENDPTCTRL_RXR; /* reset data toggle */
@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
return reg;
}
static void hw_enable_vbus_intr(struct ci13xxx *ci)
{
hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
queue_work(ci->wq, &ci->vbus_work);
}
static void hw_disable_vbus_intr(struct ci13xxx *ci)
{
hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
}
/**
* hw_test_and_clear_setup_guard: test & clear setup guard (execute without
* interruption)
@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
{
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
value << ffs_nr(DEVICEADDR_USBADR));
value << __ffs(DEVICEADDR_USBADR));
}
/**
@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
return 0;
}
static void vbus_work(struct work_struct *work)
{
struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
usb_gadget_vbus_connect(&ci->gadget);
else
usb_gadget_vbus_disconnect(&ci->gadget);
}
/******************************************************************************
* UTIL block
*****************************************************************************/
@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
return -ENOMEM;
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
mReq->zptr->next = TD_TERMINATE;
mReq->zptr->token = TD_STATUS_ACTIVE;
mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
if (!mReq->req.no_interrupt)
mReq->zptr->token |= TD_IOC;
mReq->zptr->token |= cpu_to_le32(TD_IOC);
}
ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
if (ret)
@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
* TODO - handle requests which spawns into several TDs
*/
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
mReq->ptr->token &= TD_TOTAL_BYTES;
mReq->ptr->token |= TD_STATUS_ACTIVE;
mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
if (mReq->zptr) {
mReq->ptr->next = mReq->zdma;
mReq->ptr->next = cpu_to_le32(mReq->zdma);
} else {
mReq->ptr->next = TD_TERMINATE;
mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
if (!mReq->req.no_interrupt)
mReq->ptr->token |= TD_IOC;
mReq->ptr->token |= cpu_to_le32(TD_IOC);
}
mReq->ptr->page[0] = mReq->req.dma;
for (i = 1; i < 5; i++)
mReq->ptr->page[i] =
(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
for (i = 1; i < TD_PAGE_COUNT; i++) {
u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
page &= ~TD_RESERVED_MASK;
mReq->ptr->page[i] = cpu_to_le32(page);
}
wmb();
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
u32 next = mReq->dma & TD_ADDR_MASK;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
if (mReqPrev->zptr)
mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
mReqPrev->zptr->next = cpu_to_le32(next);
else
mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
mReqPrev->ptr->next = cpu_to_le32(next);
wmb();
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
goto done;
@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
}
/* QH configuration */
mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
mEp->qh.ptr->cap |= QH_ZLT;
mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
mEp->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
wmb(); /* synchronize before ep prime */
@ -506,14 +483,16 @@ done:
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
u32 tmptoken = le32_to_cpu(mReq->ptr->token);
if (mReq->req.status != -EALREADY)
return -EINVAL;
if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
if ((TD_STATUS_ACTIVE & tmptoken) != 0)
return -EBUSY;
if (mReq->zptr) {
if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
return -EBUSY;
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
mReq->req.status = mReq->ptr->token & TD_STATUS;
mReq->req.status = tmptoken & TD_STATUS;
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
mReq->req.status = -1;
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
mReq->req.status = -1;
mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
mReq->req.actual = mReq->req.length - mReq->req.actual;
mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
@ -561,6 +540,12 @@ __acquires(mEp->lock)
struct ci13xxx_req *mReq = \
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
if (mReq->zptr) {
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
}
list_del_init(&mReq->queue);
mReq->req.status = -ESHUTDOWN;
@ -629,8 +614,6 @@ __acquires(ci->lock)
{
int retval;
dbg_event(0xFF, "BUS RST", 0);
spin_unlock(&ci->lock);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
@ -667,6 +650,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
usb_ep_free_request(ep, req);
}
/**
* _ep_queue: queues (submits) an I/O request to an endpoint
*
* Caller must hold lock
*/
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
struct ci13xxx *ci = mEp->ci;
int retval = 0;
if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
return -EINVAL;
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
if (req->length)
mEp = (ci->ep0_dir == RX) ?
ci->ep0out : ci->ep0in;
if (!list_empty(&mEp->qh.queue)) {
_ep_nuke(mEp);
retval = -EOVERFLOW;
dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
_usb_addr(mEp));
}
}
/* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&mReq->queue)) {
dev_err(mEp->ci->dev, "request already in queue\n");
return -EBUSY;
}
if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
dev_err(mEp->ci->dev, "request bigger than one td\n");
return -EMSGSIZE;
}
/* push request */
mReq->req.status = -EINPROGRESS;
mReq->req.actual = 0;
retval = _hardware_enqueue(mEp, mReq);
if (retval == -EALREADY)
retval = 0;
if (!retval)
list_add_tail(&mReq->queue, &mEp->qh.queue);
return retval;
}
/**
* isr_get_status_response: get_status request response
* @ci: ci struct
@ -714,9 +750,7 @@ __acquires(mEp->lock)
}
/* else do nothing; reserved for future use */
spin_unlock(mEp->lock);
retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
spin_lock(mEp->lock);
retval = _ep_queue(&mEp->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
* This function returns an error code
*/
static int isr_setup_status_phase(struct ci13xxx *ci)
__releases(mEp->lock)
__acquires(mEp->lock)
{
int retval;
struct ci13xxx_ep *mEp;
@ -773,9 +805,7 @@ __acquires(mEp->lock)
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
spin_unlock(mEp->lock);
retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
spin_lock(mEp->lock);
retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
return retval;
}
@ -801,7 +831,6 @@ __acquires(mEp->lock)
if (retval < 0)
break;
list_del_init(&mReq->queue);
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@ -814,8 +843,6 @@ __acquires(mEp->lock)
if (retval == -EBUSY)
retval = 0;
if (retval < 0)
dbg_event(_usb_addr(mEp), "DONE", retval);
return retval;
}
@ -847,8 +874,6 @@ __acquires(ci->lock)
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
dbg_event(_usb_addr(mEp),
"ERROR", err);
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev,
@ -884,8 +909,6 @@ __acquires(ci->lock)
ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
dbg_setup(_usb_addr(mEp), &req);
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@ -997,8 +1020,6 @@ delegate:
}
if (err < 0) {
dbg_event(_usb_addr(mEp), "ERROR", err);
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev, "error: ep_set_halt\n");
@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep,
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
u32 cap = 0;
if (ep == NULL || desc == NULL)
return -EINVAL;
@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep,
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
dbg_event(_usb_addr(mEp), "ENABLE", 0);
mEp->qh.ptr->cap = 0;
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
mEp->qh.ptr->cap |= QH_IOS;
else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
mEp->qh.ptr->cap &= ~QH_MULT;
else
mEp->qh.ptr->cap &= ~QH_ZLT;
cap |= QH_IOS;
if (mEp->num)
cap |= QH_ZLT;
cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
mEp->qh.ptr->cap |=
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
mEp->qh.ptr->cap = cpu_to_le32(cap);
mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
/*
* Enable endpoints in the HW other than ep0 as ep0
@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep)
direction = mEp->dir;
do {
dbg_event(_usb_addr(mEp), "DISABLE", 0);
retval |= _ep_nuke(mEp);
retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
}
}
dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
return (mReq == NULL) ? NULL : &mReq->req;
}
@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
kfree(mReq);
dbg_event(_usb_addr(mEp), "FREE", 0);
spin_unlock_irqrestore(mEp->lock, flags);
}
@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
struct ci13xxx *ci = mEp->ci;
int retval = 0;
unsigned long flags;
@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
if (req->length)
mEp = (ci->ep0_dir == RX) ?
ci->ep0out : ci->ep0in;
if (!list_empty(&mEp->qh.queue)) {
_ep_nuke(mEp);
retval = -EOVERFLOW;
dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
_usb_addr(mEp));
}
}
/* first nuke then test link, e.g. previous status has not sent */
if (!list_empty(&mReq->queue)) {
retval = -EBUSY;
dev_err(mEp->ci->dev, "request already in queue\n");
goto done;
}
if (req->length > 4 * CI13XXX_PAGE_SIZE) {
req->length = 4 * CI13XXX_PAGE_SIZE;
retval = -EMSGSIZE;
dev_warn(mEp->ci->dev, "request length truncated\n");
}
dbg_queue(_usb_addr(mEp), req, retval);
/* push request */
mReq->req.status = -EINPROGRESS;
mReq->req.actual = 0;
retval = _hardware_enqueue(mEp, mReq);
if (retval == -EALREADY) {
dbg_event(_usb_addr(mEp), "QUEUE", retval);
retval = 0;
}
if (!retval)
list_add_tail(&mReq->queue, &mEp->qh.queue);
done:
retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
}
@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
spin_lock_irqsave(mEp->lock, flags);
dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
/* pop request */
@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)
direction = mEp->dir;
do {
dbg_event(_usb_addr(mEp), "HALT", value);
retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
if (!value)
@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep)
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
dbg_event(_usb_addr(mEp), "WEDGE", 0);
mEp->wedge = 1;
spin_unlock_irqrestore(mEp->lock, flags);
return usb_ep_set_halt(ep);
@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep)
spin_lock_irqsave(mEp->lock, flags);
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
spin_unlock_irqrestore(mEp->lock, flags);
@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
hw_enable_vbus_intr(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
} else {
hw_device_state(ci, 0);
@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
if (ci->vbus_active) {
if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
if (ci->platdata->flags & CI13XXX_REGS_SHARED)
hw_device_reset(ci, USBMODE_CM_DC);
hw_enable_vbus_intr(ci);
}
} else {
pm_runtime_put_sync(&ci->gadget.dev);
goto done;
@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
}
}
intr = hw_test_and_clear_intr_active(ci);
dbg_interrupt(intr);
if (intr) {
/* order defines priority - do NOT change it */
@ -1676,28 +1633,11 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
} else {
retval = IRQ_NONE;
}
intr = hw_read(ci, OP_OTGSC, ~0);
hw_write(ci, OP_OTGSC, ~0, intr);
if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
queue_work(ci->wq, &ci->vbus_work);
spin_unlock(&ci->lock);
return retval;
}
/**
* udc_release: driver release function
* @dev: device
*
* Currently does nothing
*/
static void udc_release(struct device *dev)
{
}
/**
* udc_start: initialize gadget role
* @ci: chipidea controller
@ -1717,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
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 */
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
sizeof(struct ci13xxx_qh),
@ -1758,24 +1692,13 @@ static int udc_start(struct ci13xxx *ci)
retval = hw_device_reset(ci, USBMODE_CM_DC);
if (retval)
goto put_transceiver;
hw_enable_vbus_intr(ci);
}
retval = device_register(&ci->gadget.dev);
if (retval) {
put_device(&ci->gadget.dev);
goto put_transceiver;
}
retval = dbg_create_files(ci->dev);
if (retval)
goto unreg_device;
if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
goto remove_dbg;
goto put_transceiver;
}
retval = usb_add_gadget_udc(dev, &ci->gadget);
@ -1795,10 +1718,6 @@ remove_trans:
}
dev_err(dev, "error = %i\n", retval);
remove_dbg:
dbg_remove_files(ci->dev);
unreg_device:
device_unregister(&ci->gadget.dev);
put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver);
@ -1821,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci == NULL)
return;
hw_disable_vbus_intr(ci);
cancel_work_sync(&ci->vbus_work);
usb_del_gadget_udc(&ci->gadget);
destroy_eps(ci);
@ -1836,8 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
dbg_remove_files(ci->dev);
device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget));
}
@ -1864,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
INIT_WORK(&ci->vbus_work, vbus_work);
return 0;
}

View File

@ -40,7 +40,7 @@ struct ci13xxx_td {
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
} __attribute__ ((packed));
} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
struct ci13xxx_qh {
@ -57,7 +57,7 @@ struct ci13xxx_qh {
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
} __attribute__ ((packed));
} __attribute__ ((packed, aligned(4)));
/**
* struct ci13xxx_req - usb request representation

View File

@ -0,0 +1,261 @@
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "ci13xxx_imx.h"
#define USB_DEV_MAX 4
#define MX25_USB_PHY_CTRL_OFFSET 0x08
#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
#define MX53_USB_UH2_CTRL_OFFSET 0x14
#define MX53_USB_UH3_CTRL_OFFSET 0x18
#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
#define MX6_BM_OVER_CUR_DIS BIT(7)
struct imx_usbmisc {
void __iomem *base;
spinlock_t lock;
struct clk *clk;
struct usbmisc_usb_device usbdev[USB_DEV_MAX];
const struct usbmisc_ops *ops;
};
static struct imx_usbmisc *usbmisc;
static struct usbmisc_usb_device *get_usbdev(struct device *dev)
{
int i, ret;
for (i = 0; i < USB_DEV_MAX; i++) {
if (usbmisc->usbdev[i].dev == dev)
return &usbmisc->usbdev[i];
else if (!usbmisc->usbdev[i].dev)
break;
}
if (i >= USB_DEV_MAX)
return ERR_PTR(-EBUSY);
ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
if (ret)
return ERR_PTR(ret);
return &usbmisc->usbdev[i];
}
static int usbmisc_imx25_post(struct device *dev)
{
struct usbmisc_usb_device *usbdev;
void __iomem *reg;
unsigned long flags;
u32 val;
usbdev = get_usbdev(dev);
if (IS_ERR(usbdev))
return PTR_ERR(usbdev);
reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
if (usbdev->evdo) {
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(reg);
writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
spin_unlock_irqrestore(&usbmisc->lock, flags);
usleep_range(5000, 10000); /* needed to stabilize voltage */
}
return 0;
}
static int usbmisc_imx53_init(struct device *dev)
{
struct usbmisc_usb_device *usbdev;
void __iomem *reg = NULL;
unsigned long flags;
u32 val = 0;
usbdev = get_usbdev(dev);
if (IS_ERR(usbdev))
return PTR_ERR(usbdev);
if (usbdev->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
switch (usbdev->index) {
case 0:
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
break;
case 1:
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
break;
case 2:
reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
break;
case 3:
reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
break;
}
if (reg && val)
writel(val, reg);
spin_unlock_irqrestore(&usbmisc->lock, flags);
}
return 0;
}
static int usbmisc_imx6q_init(struct device *dev)
{
struct usbmisc_usb_device *usbdev;
unsigned long flags;
u32 reg;
usbdev = get_usbdev(dev);
if (IS_ERR(usbdev))
return PTR_ERR(usbdev);
if (usbdev->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base + usbdev->index * 4);
writel(reg | MX6_BM_OVER_CUR_DIS,
usbmisc->base + usbdev->index * 4);
spin_unlock_irqrestore(&usbmisc->lock, flags);
}
return 0;
}
static const struct usbmisc_ops imx25_usbmisc_ops = {
.post = usbmisc_imx25_post,
};
static const struct usbmisc_ops imx53_usbmisc_ops = {
.init = usbmisc_imx53_init,
};
static const struct usbmisc_ops imx6q_usbmisc_ops = {
.init = usbmisc_imx6q_init,
};
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",
.data = &imx25_usbmisc_ops,
},
{
.compatible = "fsl,imx53-usbmisc",
.data = &imx53_usbmisc_ops,
},
{
.compatible = "fsl,imx6q-usbmisc",
.data = &imx6q_usbmisc_ops,
},
{ /* sentinel */ }
};
static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_usbmisc *data;
int ret;
struct of_device_id *tmp_dev;
if (usbmisc)
return -EBUSY;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
spin_lock_init(&data->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
return PTR_ERR(data->clk);
}
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(&pdev->dev,
"clk_prepare_enable failed, err=%d\n", ret);
return ret;
}
tmp_dev = (struct of_device_id *)
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
usbmisc = data;
ret = usbmisc_set_ops(data->ops);
if (ret) {
usbmisc = NULL;
clk_disable_unprepare(data->clk);
return ret;
}
return 0;
}
static int usbmisc_imx_remove(struct platform_device *pdev)
{
usbmisc_unset_ops(usbmisc->ops);
clk_disable_unprepare(usbmisc->clk);
usbmisc = NULL;
return 0;
}
static struct platform_driver usbmisc_imx_driver = {
.probe = usbmisc_imx_probe,
.remove = usbmisc_imx_remove,
.driver = {
.name = "usbmisc_imx",
.owner = THIS_MODULE,
.of_match_table = usbmisc_imx_dt_ids,
},
};
int usbmisc_imx_drv_init(void)
{
return platform_driver_register(&usbmisc_imx_driver);
}
subsys_initcall(usbmisc_imx_drv_init);
void usbmisc_imx_drv_exit(void)
{
platform_driver_unregister(&usbmisc_imx_driver);
}
module_exit(usbmisc_imx_drv_exit);
MODULE_ALIAS("platform:usbmisc-imx");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("driver for imx usb non-core registers");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");

View File

@ -1,162 +0,0 @@
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include "ci13xxx_imx.h"
#define USB_DEV_MAX 4
#define BM_OVER_CUR_DIS BIT(7)
struct imx6q_usbmisc {
void __iomem *base;
spinlock_t lock;
struct clk *clk;
struct usbmisc_usb_device usbdev[USB_DEV_MAX];
};
static struct imx6q_usbmisc *usbmisc;
static struct usbmisc_usb_device *get_usbdev(struct device *dev)
{
int i, ret;
for (i = 0; i < USB_DEV_MAX; i++) {
if (usbmisc->usbdev[i].dev == dev)
return &usbmisc->usbdev[i];
else if (!usbmisc->usbdev[i].dev)
break;
}
if (i >= USB_DEV_MAX)
return ERR_PTR(-EBUSY);
ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
if (ret)
return ERR_PTR(ret);
return &usbmisc->usbdev[i];
}
static int usbmisc_imx6q_init(struct device *dev)
{
struct usbmisc_usb_device *usbdev;
unsigned long flags;
u32 reg;
usbdev = get_usbdev(dev);
if (IS_ERR(usbdev))
return PTR_ERR(usbdev);
if (usbdev->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base + usbdev->index * 4);
writel(reg | BM_OVER_CUR_DIS,
usbmisc->base + usbdev->index * 4);
spin_unlock_irqrestore(&usbmisc->lock, flags);
}
return 0;
}
static const struct usbmisc_ops imx6q_usbmisc_ops = {
.init = usbmisc_imx6q_init,
};
static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
{ .compatible = "fsl,imx6q-usbmisc"},
{ /* sentinel */ }
};
static int usbmisc_imx6q_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx6q_usbmisc *data;
int ret;
if (usbmisc)
return -EBUSY;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
spin_lock_init(&data->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
return PTR_ERR(data->clk);
}
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(&pdev->dev,
"clk_prepare_enable failed, err=%d\n", ret);
return ret;
}
ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
if (ret) {
clk_disable_unprepare(data->clk);
return ret;
}
usbmisc = data;
return 0;
}
static int usbmisc_imx6q_remove(struct platform_device *pdev)
{
usbmisc_unset_ops(&imx6q_usbmisc_ops);
clk_disable_unprepare(usbmisc->clk);
return 0;
}
static struct platform_driver usbmisc_imx6q_driver = {
.probe = usbmisc_imx6q_probe,
.remove = usbmisc_imx6q_remove,
.driver = {
.name = "usbmisc_imx6q",
.owner = THIS_MODULE,
.of_match_table = usbmisc_imx6q_dt_ids,
},
};
int __init usbmisc_imx6q_drv_init(void)
{
return platform_driver_register(&usbmisc_imx6q_driver);
}
subsys_initcall(usbmisc_imx6q_drv_init);
void __exit usbmisc_imx6q_drv_exit(void)
{
platform_driver_unregister(&usbmisc_imx6q_driver);
}
module_exit(usbmisc_imx6q_drv_exit);
MODULE_ALIAS("platform:usbmisc-imx6q");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");

View File

@ -2,11 +2,10 @@
# USB Class driver configuration
#
comment "USB Device Class drivers"
depends on USB
config USB_ACM
tristate "USB Modem (CDC ACM) support"
depends on USB && TTY
depends on TTY
---help---
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
@ -21,7 +20,6 @@ config USB_ACM
config USB_PRINTER
tristate "USB Printer support"
depends on USB
help
Say Y here if you want to connect a USB printer to your computer's
USB port.
@ -31,7 +29,6 @@ config USB_PRINTER
config USB_WDM
tristate "USB Wireless Device Management support"
depends on USB
---help---
This driver supports the WMC Device Management functionality
of cell phones compliant to the CDC WMC specification. You can use
@ -42,7 +39,6 @@ config USB_WDM
config USB_TMC
tristate "USB Test and Measurement Class support"
depends on USB
help
Say Y here if you want to connect a USB device that follows
the USB.org specification for USB Test and Measurement devices

View File

@ -828,14 +828,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
return rv;
}
static const __u32 acm_tty_speed[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600,
1200, 1800, 2400, 4800, 9600, 19200, 38400,
57600, 115200, 230400, 460800, 500000, 576000,
921600, 1000000, 1152000, 1500000, 2000000,
2500000, 3000000, 3500000, 4000000
};
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{

View File

@ -13,6 +13,7 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)
return 0;
}
static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct wdm_device *desc = file->private_data;
int rv = 0;
switch (cmd) {
case IOCTL_WDM_MAX_COMMAND:
if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
rv = -EFAULT;
break;
default:
rv = -ENOTTY;
}
return rv;
}
static const struct file_operations wdm_fops = {
.owner = THIS_MODULE,
.read = wdm_read,
@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = {
.flush = wdm_flush,
.release = wdm_release,
.poll = wdm_poll,
.unlocked_ioctl = wdm_ioctl,
.compat_ioctl = wdm_ioctl,
.llseek = noop_llseek,
};

View File

@ -718,50 +718,32 @@ exit:
static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
{
u8 *buffer;
int rv;
buffer = kmalloc(2, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
goto exit;
return rv;
}
rv = 0;
exit:
kfree(buffer);
return rv;
return 0;
}
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
{
u8 *buffer;
int rv;
buffer = kmalloc(2, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
goto exit;
return rv;
}
rv = 0;
exit:
kfree(buffer);
return rv;
return 0;
}
static int get_capabilities(struct usbtmc_device_data *data)

View File

@ -3,7 +3,6 @@
#
config USB_DEBUG
bool "USB verbose debug messages"
depends on USB
help
Say Y here if you want the USB core & hub drivers to produce a bunch
of debug messages to the system log. Select this if you are having a
@ -11,7 +10,6 @@ config USB_DEBUG
config USB_ANNOUNCE_NEW_DEVICES
bool "USB announce new devices"
depends on USB
default N
help
Say Y here if you want the USB core to always announce the
@ -25,11 +23,24 @@ config USB_ANNOUNCE_NEW_DEVICES
log, or have any doubts about this, say N here.
comment "Miscellaneous USB options"
depends on USB
config USB_DEFAULT_PERSIST
bool "Enable USB persist by default"
default y
help
Say N here if you don't want USB power session persistance
enabled by default. If you say N it will make suspended USB
devices that lose power get reenumerated as if they had been
unplugged, causing any mounted filesystems to be lost. The
persist feature can still be enabled for individual devices
through the power/persist sysfs node. See
Documentation/usb/persist.txt for more info.
If you have any questions about this, say Y here, only say N
if you know exactly what you are doing.
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation"
depends on USB
help
If you say Y here, the USB subsystem will use dynamic minor
allocation for any device that uses the USB major number.
@ -38,25 +49,8 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here.
config USB_SUSPEND
bool "USB runtime power management (autosuspend) and wakeup"
depends on USB && PM_RUNTIME
help
If you say Y here, you can use driver calls or the sysfs
"power/control" file to enable or disable autosuspend for
individual USB peripherals (see
Documentation/usb/power-management.txt for more details).
Also, USB "remote wakeup" signaling is supported, whereby some
USB devices (like keyboards and network adapters) can wake up
their parent hub. That wakeup cascades up the USB tree, and
could wake the system from states like suspend-to-RAM.
If you are unsure about this, say N here.
config USB_OTG
bool "OTG support"
depends on USB
depends on USB_SUSPEND
default n
help

View File

@ -739,6 +739,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
index &= 0xff;
switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT:
if ((index & ~USB_DIR_IN) == 0)
return 0;
ret = findintfep(ps->dev, index);
if (ret >= 0)
ret = checkintf(ps, ret);

View File

@ -1196,9 +1196,14 @@ done:
*
* This is the central routine for suspending USB devices. It calls the
* suspend methods for all the interface drivers in @udev and then calls
* the suspend method for @udev itself. If an error occurs at any stage,
* all the interfaces which were suspended are resumed so that they remain
* in the same state as the device.
* the suspend method for @udev itself. When the routine is called in
* autosuspend, if an error occurs at any stage, all the interfaces
* which were suspended are resumed so that they remain in the same
* state as the device, but when called from system sleep, all error
* from suspend methods of interfaces and the non-root-hub device itself
* are simply ignored, so all suspended interfaces are only resumed
* to the device's state when @udev is root-hub and its suspend method
* returns failure.
*
* Autosuspend requests originating from a child device or an interface
* driver may be made without the protection of @udev's device lock, but
@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (++i < n) {
intf = udev->actconfig->interface[i];
usb_resume_interface(udev, intf, msg, 0);
if (udev->actconfig) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (++i < n) {
intf = udev->actconfig->interface[i];
usb_resume_interface(udev, intf, msg, 0);
}
}
/* If the suspend succeeded then prevent any more URB submissions
@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
/**
* usb_enable_autosuspend - allow a USB device to be autosuspended
@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
return ret;
}
#endif /* CONFIG_USB_SUSPEND */
#endif /* CONFIG_PM_RUNTIME */
struct bus_type usb_bus_type = {
.name = "usb",

View File

@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)
c = usb_choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
if (err && err != -ENODEV) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to

View File

@ -37,119 +37,123 @@
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
#ifdef CONFIG_PM_SLEEP
/* Coordinate handoffs between EHCI and companion controllers
* during system resume
/*
* Coordinate handoffs between EHCI and companion controllers
* during EHCI probing and system resume.
*/
static DEFINE_MUTEX(companions_mutex);
static DECLARE_RWSEM(companions_rwsem);
#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
enum companion_action {
SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
};
static inline int is_ohci_or_uhci(struct pci_dev *pdev)
{
return pdev->class == CL_OHCI || pdev->class == CL_UHCI;
}
static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
enum companion_action action)
typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd);
/* Iterate over PCI devices in the same slot as pdev and call fn for each */
static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
companion_fn fn)
{
struct pci_dev *companion;
struct usb_hcd *companion_hcd;
unsigned int slot = PCI_SLOT(pdev->devfn);
/* Iterate through other PCI functions in the same slot.
* If pdev is OHCI or UHCI then we are looking for EHCI, and
* vice versa.
/*
* Iterate through other PCI functions in the same slot.
* If the function's drvdata isn't set then it isn't bound to
* a USB host controller driver, so skip it.
*/
companion = NULL;
for_each_pci_dev(companion) {
if (companion->bus != pdev->bus ||
PCI_SLOT(companion->devfn) != slot)
continue;
companion_hcd = pci_get_drvdata(companion);
if (!companion_hcd)
continue;
/* For SET_HS_COMPANION, store a pointer to the EHCI bus in
* the OHCI/UHCI companion bus structure.
* For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
* in the OHCI/UHCI companion bus structure.
* For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
* companion controllers have fully resumed.
*/
if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
companion->class == CL_EHCI) {
/* action must be SET_HS_COMPANION */
dev_dbg(&companion->dev, "HS companion for %s\n",
dev_name(&pdev->dev));
hcd->self.hs_companion = &companion_hcd->self;
} else if (pdev->class == CL_EHCI &&
(companion->class == CL_OHCI ||
companion->class == CL_UHCI)) {
switch (action) {
case SET_HS_COMPANION:
dev_dbg(&pdev->dev, "HS companion for %s\n",
dev_name(&companion->dev));
companion_hcd->self.hs_companion = &hcd->self;
break;
case CLEAR_HS_COMPANION:
companion_hcd->self.hs_companion = NULL;
break;
case WAIT_FOR_COMPANIONS:
device_pm_wait_for_dev(&pdev->dev,
&companion->dev);
break;
}
}
fn(pdev, hcd, companion, companion_hcd);
}
}
static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
/*
* We're about to add an EHCI controller, which will unceremoniously grab
* all the port connections away from its companions. To prevent annoying
* error messages, lock the companion's root hub and gracefully unconfigure
* it beforehand. Leave it locked until the EHCI controller is all set.
*/
static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
mutex_lock(&companions_mutex);
dev_set_drvdata(&pdev->dev, hcd);
companion_common(pdev, hcd, SET_HS_COMPANION);
mutex_unlock(&companions_mutex);
struct usb_device *udev;
if (is_ohci_or_uhci(companion)) {
udev = companion_hcd->self.root_hub;
usb_lock_device(udev);
usb_set_configuration(udev, 0);
}
}
static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
/*
* Adding the EHCI controller has either succeeded or failed. Set the
* companion pointer accordingly, and in either case, reconfigure and
* unlock the root hub.
*/
static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
mutex_lock(&companions_mutex);
dev_set_drvdata(&pdev->dev, NULL);
struct usb_device *udev;
/* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
hcd->self.hs_companion = NULL;
/* Otherwise search for companion buses and clear their pointers */
else
companion_common(pdev, hcd, CLEAR_HS_COMPANION);
mutex_unlock(&companions_mutex);
if (is_ohci_or_uhci(companion)) {
if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */
dev_dbg(&pdev->dev, "HS companion for %s\n",
dev_name(&companion->dev));
companion_hcd->self.hs_companion = &hcd->self;
}
udev = companion_hcd->self.root_hub;
usb_set_configuration(udev, 1);
usb_unlock_device(udev);
}
}
static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
/*
* We just added a non-EHCI controller. Find the EHCI controller to
* which it is a companion, and store a pointer to the bus structure.
*/
static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
/* Only EHCI controllers need to wait.
* No locking is needed because a controller cannot be resumed
* while one of its companions is getting unbound.
*/
if (pdev->class == CL_EHCI)
companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) {
dev_dbg(&pdev->dev, "FS/LS companion for %s\n",
dev_name(&companion->dev));
hcd->self.hs_companion = &companion_hcd->self;
}
}
#else /* !CONFIG_PM_SLEEP */
/* We are removing an EHCI controller. Clear the companions' pointers. */
static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
if (is_ohci_or_uhci(companion))
companion_hcd->self.hs_companion = NULL;
}
static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
#ifdef CONFIG_PM
#endif /* !CONFIG_PM_SLEEP */
/* An EHCI controller must wait for its companions before resuming. */
static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
if (is_ohci_or_uhci(companion))
device_pm_wait_for_dev(&pdev->dev, &companion->dev);
}
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
driver->description)) {
dev_dbg(&dev->dev, "controller already in use\n");
retval = -EBUSY;
goto clear_companion;
goto put_hcd;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (region == PCI_ROM_RESOURCE) {
dev_dbg(&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
goto clear_companion;
goto put_hcd;
}
}
pci_set_master(dev);
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
/* Note: dev_set_drvdata must be called while holding the rwsem */
if (dev->class == CL_EHCI) {
down_write(&companions_rwsem);
dev_set_drvdata(&dev->dev, hcd);
for_each_companion(dev, hcd, ehci_pre_add);
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
if (retval != 0)
dev_set_drvdata(&dev->dev, NULL);
for_each_companion(dev, hcd, ehci_post_add);
up_write(&companions_rwsem);
} else {
down_read(&companions_rwsem);
dev_set_drvdata(&dev->dev, hcd);
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
if (retval != 0)
dev_set_drvdata(&dev->dev, NULL);
else
for_each_companion(dev, hcd, non_ehci_add);
up_read(&companions_rwsem);
}
if (retval != 0)
goto unmap_registers;
set_hs_companion(dev, hcd);
if (pci_dev_run_wake(dev))
pm_runtime_put_noidle(&dev->dev);
@ -266,8 +289,7 @@ release_mem_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else
release_region(hcd->rsrc_start, hcd->rsrc_len);
clear_companion:
clear_hs_companion(dev, hcd);
put_hcd:
usb_put_hcd(hcd);
disable_pci:
pci_disable_device(dev);
@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
usb_hcd_irq(0, hcd);
local_irq_enable();
usb_remove_hcd(hcd);
/* Note: dev_set_drvdata must be called while holding the rwsem */
if (dev->class == CL_EHCI) {
down_write(&companions_rwsem);
for_each_companion(dev, hcd, ehci_remove);
usb_remove_hcd(hcd);
dev_set_drvdata(&dev->dev, NULL);
up_write(&companions_rwsem);
} else {
/* Not EHCI; just clear the companion pointer */
down_read(&companions_rwsem);
hcd->self.hs_companion = NULL;
usb_remove_hcd(hcd);
dev_set_drvdata(&dev->dev, NULL);
up_read(&companions_rwsem);
}
if (hcd->driver->flags & HCD_MEMORY) {
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else {
release_region(hcd->rsrc_start, hcd->rsrc_len);
}
clear_hs_companion(dev, hcd);
usb_put_hcd(hcd);
pci_disable_device(dev);
}
@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event)
pci_set_master(pci_dev);
if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
if (event != PM_EVENT_AUTO_RESUME)
wait_for_companions(pci_dev, hcd);
/*
* Only EHCI controllers have to wait for their companions.
* No locking is needed because PCI controller drivers do not
* get unbound during system resume.
*/
if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)
for_each_companion(pci_dev, hcd,
ehci_wait_for_companions);
retval = hcd->driver->pci_resume(hcd,
event == PM_EVENT_RESTORE);

View File

@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
#endif /* CONFIG_USB_SUSPEND */
#endif /* CONFIG_PM_RUNTIME */
/*-------------------------------------------------------------------------*/
@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
@ -2590,7 +2590,7 @@ error_create_attr_group:
hcd->rh_registered = 0;
spin_unlock_irq(&hcd_root_hub_lock);
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
@ -2645,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
cancel_work_sync(&hcd->wakeup_work);
#endif

View File

@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,
mutex_lock(&hub->status_mutex);
ret = get_port_status(hub->hdev, port1, &hub->status->port);
if (ret < 4) {
dev_err(hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
if (ret != -ENODEV)
dev_err(hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
if (ret >= 0)
ret = -EIO;
} else {
@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)
/* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags);
status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
if (status)
if (status && status != -ENODEV)
dev_err (&hdev->dev,
"clear tt %d (%04x) error %d\n",
clear->tt, clear->devinfo, status);
@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,
mutex_lock(&hub->status_mutex);
ret = get_hub_status(hub->hdev, &hub->status->hub);
if (ret < 0)
dev_err (hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
else {
if (ret < 0) {
if (ret != -ENODEV)
dev_err(hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
} else {
*status = le16_to_cpu(hub->status->hub.wHubStatus);
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
return -EINVAL;
ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
if (ret) {
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
if (ret)
return ret;
}
/* Wait for the link to enter the disabled state. */
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
ret = usb_clear_port_feature(hdev, port1,
USB_PORT_FEAT_ENABLE);
}
if (ret)
if (ret && ret != -ENODEV)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
return ret;
@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,
message = "hub has too many ports!";
ret = -ENODEV;
goto fail;
} else if (hub->descriptor->bNbrPorts == 0) {
message = "hub doesn't have any ports!";
ret = -ENODEV;
goto fail;
}
hdev->maxchild = hub->descriptor->bNbrPorts;
@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)
if (udev->config == NULL) {
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
if (err != -ENODEV)
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
return err;
}
}
@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
status = set_port_feature(hub->hdev, port1, (warm ?
USB_PORT_FEAT_BH_PORT_RESET :
USB_PORT_FEAT_RESET));
if (status) {
if (status == -ENODEV) {
; /* The hub is gone */
} else if (status) {
dev_err(hub->intfdev,
"cannot %sreset port %d (err = %d)\n",
warm ? "warm " : "", port1, status);
} else {
status = hub_port_wait_reset(hub, port1, udev, delay,
warm);
if (status && status != -ENOTCONN)
if (status && status != -ENOTCONN && status != -ENODEV)
dev_dbg(hub->intfdev,
"port_wait_reset: err = %d\n",
status);
@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_enable_ltm);
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM
/*
* usb_disable_function_remotewakeup - disable usb3.0
* device's function remote wakeup
@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*
* If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
* If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
* suspended only when their bus goes into global suspend (i.e., the root
* hub is suspended). Nevertheless, we change @udev->state to
* USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
* upstream port setting is stored in @udev->port_is_suspended.
*
* Returns 0 on success, else negative errno.
*/
@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
enum pm_qos_flags_status pm_qos_stat;
int port1 = udev->portnum;
int status;
bool really_suspend = true;
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
else
else if (PMSG_IS_AUTO(msg))
status = set_port_feature(hub->hdev, port1,
USB_PORT_FEAT_SUSPEND);
/*
* For system suspend, we do not need to enable the suspend feature
* on individual USB-2 ports. The devices will automatically go
* into suspend a few ms after the root hub stops sending packets.
* The USB 2.0 spec calls this "global suspend".
*/
else {
really_suspend = false;
status = 0;
}
if (status) {
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
port1, status);
@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
udev->do_remote_wakeup);
usb_set_device_state(udev, USB_STATE_SUSPENDED);
udev->port_is_suspended = 1;
msleep(10);
if (really_suspend) {
udev->port_is_suspended = 1;
msleep(10);
}
}
/*
@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_RUNTIME
/* caller has locked udev */
int usb_remote_wakeup(struct usb_device *udev)
{
@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)
return status;
}
#else /* CONFIG_USB_SUSPEND */
/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
return 0;
}
/* However we may need to do a reset-resume */
int usb_port_resume(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
int port1 = udev->portnum;
int status;
u16 portchange, portstatus;
status = hub_port_status(hub, port1, &portstatus, &portchange);
status = check_port_resume_type(udev,
hub, port1, status, portchange, portstatus);
if (status) {
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
hub_port_logical_disconnect(hub, port1);
} else if (udev->reset_resume) {
dev_dbg(&udev->dev, "reset-resume\n");
status = usb_reset_and_verify_device(udev);
}
return status;
}
#endif
static int check_ports_changed(struct usb_hub *hub)
@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
if (r) {
dev_err(&udev->dev,
"device descriptor read/64, error %d\n",
r);
if (r != -ENODEV)
dev_err(&udev->dev, "device descriptor read/64, error %d\n",
r);
retval = -EMSGSIZE;
continue;
}
@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
msleep(200);
}
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
devnum, retval);
if (retval != -ENODEV)
dev_err(&udev->dev, "device not accepting address %d, error %d\n",
devnum, retval);
goto fail;
}
if (udev->speed == USB_SPEED_SUPER) {
@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, 8);
if (retval < 8) {
dev_err(&udev->dev,
if (retval != -ENODEV)
dev_err(&udev->dev,
"device descriptor read/8, error %d\n",
retval);
if (retval >= 0)
@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(udev->descriptor)) {
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
retval);
if (retval != -ENODEV)
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce_be_stable(hub, port1);
if (status < 0) {
if (printk_ratelimit())
if (status != -ENODEV && printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
else
unit_load = 100;
status = 0;
for (i = 0; i < SET_CONFIG_TRIES; i++) {
/* reallocate for each attempt, since references
@ -4526,9 +4522,11 @@ loop:
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||
!(hcd->driver->port_handed_over)(hcd, port1))
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
port1);
!(hcd->driver->port_handed_over)(hcd, port1)) {
if (status != -ENOTCONN && status != -ENODEV)
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
port1);
}
done:
hub_port_disable(hub, port1, 1);

View File

@ -70,7 +70,7 @@ static void usb_port_device_release(struct device *dev)
kfree(port_dev);
}
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
static int usb_port_runtime_resume(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
@ -138,7 +138,7 @@ static int usb_port_runtime_suspend(struct device *dev)
#endif
static const struct dev_pm_ops usb_port_pm_ops = {
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_port_runtime_suspend,
.runtime_resume = usb_port_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,

View File

@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
/* For the present, all devices default to USB-PERSIST enabled */
#if 0 /* was: #ifdef CONFIG_PM */
#ifdef CONFIG_USB_DEFAULT_PERSIST
if (!(udev->quirks & USB_QUIRK_RESET))
udev->persist_enabled = 1;
#else
/* Hubs are automatically enabled for USB-PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
udev->persist_enabled = 1;
#else
/* In the absence of PM, we can safely enable USB-PERSIST
* for all devices. It will affect things like hub resets
* and EMF-related port disables.
*/
if (!(udev->quirks & USB_QUIRK_RESET))
udev->persist_enabled = 1;
#endif /* CONFIG_PM */
#endif /* CONFIG_USB_DEFAULT_PERSIST */
}
void usb_detect_interface_quirks(struct usb_device *udev)

View File

@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)
#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
static ssize_t
show_connected_duration(struct device *dev, struct device_attribute *attr,
@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)
#define add_power_attributes(dev) 0
#define remove_power_attributes(dev) do {} while (0)
#endif /* CONFIG_USB_SUSPEND */
#endif /* CONFIG_PM_RUNTIME */
/* Descriptor fields */

View File

@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
void usb_poison_urb(struct urb *urb)
{
might_sleep();
if (!(urb && urb->dev && urb->ep))
if (!urb)
return;
atomic_inc(&urb->reject);
if (!urb->dev || !urb->ep)
return;
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
}

View File

@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";
static bool nousb; /* Disable USB when built into kernel image */
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
.thaw = usb_dev_thaw,
.poweroff = usb_dev_poweroff,
.restore = usb_dev_restore,
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle,

View File

@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
#endif
#ifdef CONFIG_USB_SUSPEND
#ifdef CONFIG_PM_RUNTIME
extern void usb_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);

View File

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

View File

@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
* Returns a pointer to the allocated event buffer structure on success
* 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;
@ -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)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_core_num_eps(dwc);
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err0;
}
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
return 0;
@ -351,8 +359,6 @@ err0:
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_event_buffers_cleanup(dwc);
usb_phy_shutdown(dwc->usb2_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);
}
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");
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");
return -EPROBE_DEFER;
}
@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs_size = resource_size(res);
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))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
else if (!strncmp("high", maximum_speed, 4))
@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev)
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) {
case DWC3_MODE_DEVICE:
@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
goto err1;
goto err2;
}
break;
case DWC3_MODE_HOST:
@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
goto err1;
goto err2;
}
break;
case DWC3_MODE_DRD:
@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
goto err1;
goto err2;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
goto err1;
goto err2;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", mode);
goto err1;
goto err2;
}
dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize debugfs\n");
goto err2;
goto err3;
}
pm_runtime_allow(dev);
return 0;
err2:
err3:
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
@ -546,6 +587,9 @@ err2:
break;
}
err2:
dwc3_event_buffers_cleanup(dwc);
err1:
dwc3_core_exit(dwc);
@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev)
break;
}
dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc);
dwc3_core_exit(dwc);
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
static const struct of_device_id of_dwc3_match[] = {
{
@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = {
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
.pm = DWC3_PM_OPS,
},
};

View File

@ -154,8 +154,9 @@
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
#define DWC3_OEVTEN 0xcc08
#define DWC3_OSTS 0xcc0C
#define DWC3_OEVT 0xcc08
#define DWC3_OEVTEN 0xcc0C
#define DWC3_OSTS 0xcc10
/* Bit fields */
@ -369,6 +370,9 @@ struct dwc3_trb;
* @list: a list of event buffers
* @buf: _THE_ 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
* @dwc: pointer to DWC controller
*/
@ -376,6 +380,10 @@ struct dwc3_event_buffer {
void *buf;
unsigned length;
unsigned int lpos;
unsigned int count;
unsigned int flags;
#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma;
@ -487,12 +495,6 @@ enum dwc3_link_state {
DWC3_LINK_STATE_MASK = 0x0f,
};
enum dwc3_device_state {
DWC3_DEFAULT_STATE,
DWC3_ADDRESS_STATE,
DWC3_CONFIGURED_STATE,
};
/* TRB Length, PCM and Status */
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
@ -574,6 +576,14 @@ struct dwc3_hwparams {
/* HWPARAMS1 */
#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 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
* @irq: IRQ number
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
* @mode: mode of operation
* @usb2_phy: pointer to USB2 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
* @three_stage_setup: set if we perform a three phase setup
* @ep0_bounced: true when we used bounce buffer
@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
* @u2pel: parameter from Set SEL request.
* @u1sel: 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
* @ep0state: state of endpoint zero
* @link_state: link state
@ -656,8 +669,10 @@ struct dwc3 {
dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req;
/* device lock */
spinlock_t lock;
struct device *dev;
struct platform_device *xhci;
@ -675,6 +690,10 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@ -694,6 +713,9 @@ struct dwc3 {
#define DWC3_REVISION_202A 0x5533202a
#define DWC3_REVISION_210A 0x5533210a
#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 three_stage_setup:1;
@ -704,11 +726,11 @@ struct dwc3 {
unsigned delayed_status:1;
unsigned needs_fifo_resize:1;
unsigned resize_fifos:1;
unsigned pullups_connected:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
enum dwc3_device_state dev_state;
u16 isoch_delay;
u16 u2sel;
@ -718,6 +740,9 @@ struct dwc3 {
u8 speed;
u8 num_out_eps;
u8 num_in_eps;
void *mem;
struct dwc3_hwparams hwparams;
@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ }
#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 */

View File

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

View File

@ -22,9 +22,9 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/of.h>
#include <linux/of_platform.h>
struct dwc3_exynos {
struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev;
@ -86,21 +86,30 @@ err1:
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 int dwc3_exynos_probe(struct platform_device *pdev)
{
struct platform_device *dwc3;
struct dwc3_exynos *exynos;
struct clk *clk;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
int ret = -ENOMEM;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos) {
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.
* Once we move to full device tree support this will vanish off.
*/
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
if (!dev->dma_mask)
dev->dma_mask = &dwc3_exynos_dma_mask;
platform_set_drvdata(pdev, exynos);
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
return ret;
}
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
return -ENOMEM;
goto err1;
}
clk = devm_clk_get(dev, "usbdrd30");
@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
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->clk = clk;
clk_enable(exynos->clk);
clk_prepare_enable(exynos->clk);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
goto err2;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(dev, "failed to register dwc3 device\n");
if (node) {
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to add dwc3 core\n");
goto err2;
}
} else {
dev_err(dev, "no device node, failed to add dwc3 core\n");
ret = -ENODEV;
goto err2;
}
return 0;
err2:
clk_disable(clk);
clk_disable_unprepare(clk);
err1:
platform_device_put(dwc3);
return ret;
}
@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
platform_device_unregister(exynos->dwc3);
platform_device_unregister(exynos->usb2_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;
}
@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
#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 = {
.probe = dwc3_exynos_probe,
.remove = dwc3_exynos_remove,
.driver = {
.name = "exynos-dwc3",
.of_match_table = of_match_ptr(exynos_dwc3_match),
.pm = DEV_PM_OPS,
},
};

View File

@ -52,7 +52,6 @@
#include <linux/of_platform.h>
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
/*
* All these registers belong to OMAP's Wrapper around the
@ -117,20 +116,17 @@ struct dwc3_omap {
/* device lock */
spinlock_t lock;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev;
int irq;
void __iomem *base;
void *context;
u32 resource_size;
u32 utmi_otg_status;
u32 dma_status:1;
};
struct dwc3_omap *_omap;
static struct dwc3_omap *_omap;
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);
}
void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{
u32 val;
struct dwc3_omap *omap = _omap;
if (!omap)
return -EPROBE_DEFER;
switch (status) {
case OMAP_DWC3_ID_GROUND:
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");
}
return;
return 0;
}
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)
{
struct dwc3_omap *omap = _omap;
@ -307,121 +252,10 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
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;
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 */
reg = USBOTGSS_IRQO_COREIRQ_ST;
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);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
}
if (node) {
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(&pdev->dev,
"failed to add create dwc3 core\n");
return ret;
}
static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
{
/* disable all IRQs */
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
}
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;
@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
platform_device_unregister(omap->usb2_phy);
platform_device_unregister(omap->usb3_phy);
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
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[] = {
{
"ti,dwc3",
.compatible = "ti,dwc3"
},
{ },
};
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 = {
.probe = dwc3_omap_probe,
.remove = dwc3_omap_remove,
.driver = {
.name = "omap-dwc3",
.of_match_table = of_dwc3_match,
.pm = DEV_PM_OPS,
},
};

View File

@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
#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 = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
.driver = {
.pm = DEV_PM_OPS,
},
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");

View File

@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 wIndex;
u32 reg;
int ret;
enum usb_device_state state;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
recip = ctrl->bRequestType & USB_RECIP_MASK;
state = dwc->gadget.state;
switch (recip) {
case USB_RECIP_DEVICE:
@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
* default control pipe
*/
case USB_DEVICE_U1_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
break;
case USB_DEVICE_U2_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
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)
{
enum usb_device_state state = dwc->gadget.state;
u32 addr;
u32 reg;
@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
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");
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);
if (addr)
dwc->dev_state = DWC3_ADDRESS_STATE;
usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
else
dwc->dev_state = DWC3_DEFAULT_STATE;
usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
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)
{
enum usb_device_state state = dwc->gadget.state;
u32 cfg;
int ret;
u32 reg;
@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc->start_config_issued = false;
cfg = le16_to_cpu(ctrl->wValue);
switch (dwc->dev_state) {
case DWC3_DEFAULT_STATE:
switch (state) {
case USB_STATE_DEFAULT:
return -EINVAL;
break;
case DWC3_ADDRESS_STATE:
case USB_STATE_ADDRESS:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
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
* nothing is pending from application.
@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
}
break;
case DWC3_CONFIGURED_STATE:
case USB_STATE_CONFIGURED:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
if (!cfg)
dwc->dev_state = DWC3_ADDRESS_STATE;
usb_gadget_set_state(&dwc->gadget,
USB_STATE_ADDRESS);
break;
default:
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)
{
struct dwc3_ep *dep;
enum usb_device_state state = dwc->gadget.state;
u16 wLength;
u16 wValue;
if (dwc->dev_state == DWC3_DEFAULT_STATE)
if (state == USB_STATE_DEFAULT)
return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);

View File

@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
dwc->pullups_connected = false;
}
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;
}
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,
struct usb_gadget_driver *driver)
{
@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
int irq;
u32 reg;
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.dev.driver = &driver->driver;
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->ep0state = EP0_SETUP_PHASE;
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);
return 0;
@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int irq;
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[1]);
dwc->gadget_driver = NULL;
dwc->gadget.dev.driver = NULL;
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;
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);
if (!dep) {
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,
(epnum & 1) ? "in" : "out");
dep->endpoint.name = dep->name;
dep->direction = (epnum & 1);
@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
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)
{
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++) {
dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_free_trb_pool(dep);
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,
struct dwc3_request *req, struct dwc3_trb *trb,
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;
dep = dwc->eps[epnum];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
int ret;
dep = dwc->eps[epnum];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_STALL))
continue;
@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
}
/* 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 */
if (dwc->revision < DWC3_REVISION_194A) {
@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
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
@ -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)
{
struct dwc3_event_buffer *evt;
int left;
u32 count;
evt = dwc->ev_buffs[buf];
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
evt = dwc->ev_buffs[buf];
left = count;
evt->count = count;
evt->flags |= DWC3_EVENT_PENDING;
while (left > 0) {
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;
return IRQ_WAKE_THREAD;
}
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;
status = dwc3_process_event_buf(dwc, i);
if (status == IRQ_HANDLED)
if (status == IRQ_WAKE_THREAD)
ret = status;
}
@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{
u32 reg;
int ret;
int irq;
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
&dwc->ctrl_req_addr, GFP_KERNEL);
@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3;
}
dev_set_name(&dwc->gadget.dev, "gadget");
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.dev.parent = dwc->dev;
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";
/*
@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret)
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_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, 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);
/* automatic phy suspend only on recent versions */
/* Enable USB2 LPM and automatic phy suspend only on recent versions */
if (dwc->revision >= DWC3_REVISION_194A) {
dwc3_gadget_usb2_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);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
goto err7;
goto err5;
}
return 0;
err7:
device_unregister(&dwc->gadget.dev);
err6:
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
free_irq(irq, dwc);
err5:
dwc3_gadget_free_endpoints(dwc);
@ -2588,15 +2674,11 @@ err0:
return ret;
}
/* -------------------------------------------------------------------------- */
void dwc3_gadget_exit(struct dwc3 *dwc)
{
int irq;
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);
@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
dwc->ctrl_req, dwc->ctrl_req_addr);
device_unregister(&dwc->gadget.dev);
}
int dwc3_gadget_prepare(struct dwc3 *dwc)
{
if (dwc->pullups_connected)
dwc3_gadget_disable_irq(dwc);
return 0;
}
void dwc3_gadget_complete(struct dwc3 *dwc)
{
if (dwc->pullups_connected) {
dwc3_gadget_enable_irq(dwc);
dwc3_gadget_run_stop(dwc, true);
}
}
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
return 0;
}
int dwc3_gadget_resume(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int ret;
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret)
goto err0;
dep = dwc->eps[1];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret)
goto err1;
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
return 0;
err1:
__dwc3_gadget_ep_disable(dwc->eps[0]);
err0:
return ret;
}

View File

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

View File

@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.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_NET2272) += net2272.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
# USB Functions
obj-$(CONFIG_USB_F_ACM) += f_acm.o
f_ss_lb-y := f_loopback.o f_sourcesink.o
obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o
usb_f_acm-y := f_acm.o
obj-$(CONFIG_USB_F_ACM) += usb_f_acm.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
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

View File

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

View File

@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
/* Some gadget drivers use both ep0 directions.
* 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);
spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
/* set SD */
@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
if (dev->active)
pci_disable_device(pdev);
device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL);
udc_remove(dev);
@ -3245,8 +3242,6 @@ static int udc_pci_probe(
dev->phys_addr = resource;
dev->irq = pdev->irq;
dev->pdev = pdev;
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
/* general probing */
if (udc_probe(dev) == 0)
@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
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);
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)
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 */
init_timer(&udc_timer);
udc_timer.function = udc_timer_function;

View File

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

View File

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

View File

@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
if (req->req.status == -EINPROGRESS)
req->req.status = status;
if (req->mapped) {
dma_unmap_single(
&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;
}
if (req->using_dma)
usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
DBG(DBG_GADGET | DBG_REQ,
"%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;
INIT_LIST_HEAD(&req->queue);
req->req.dma = DMA_ADDR_INVALID;
return &req->req;
}
@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
return -EINVAL;
}
ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
if (ret)
return ret;
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)
| USBA_DMA_CH_EN | USBA_DMA_END_BUF_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->driver = driver;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
clk_enable(udc->pclk);
@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
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",
(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);
/* 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;
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_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin;
@ -2007,9 +1980,6 @@ err_add_udc:
gpio_free(udc->vbus_pin);
}
device_unregister(&udc->gadget.dev);
err_device_add:
free_irq(irq, udc);
err_request_irq:
kfree(usba_ep);
@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
clk_put(udc->hclk);
clk_put(udc->pclk);
device_unregister(&udc->gadget.dev);
return 0;
}

View File

@ -216,12 +216,6 @@
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
#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 CTRL_IOMEM_ID 1

View File

@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
udc->driver = driver;
driver->driver.bus = NULL;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node;
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);
udc->driver = NULL;
udc->gadget.dev.driver = NULL;
/*
* 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
***********************************************************************/
/**
* 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.
* @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);
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.ops = &bcm63xx_udc_ops;
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)
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);
rc = usb_add_gadget_udc(dev, &udc->gadget);
if (!rc)
return 0;
bcm63xx_udc_cleanup_debugfs(udc);
device_unregister(&udc->gadget.dev);
out_uninit:
bcm63xx_uninit_udc_hw(udc);
return rc;
@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
bcm63xx_udc_cleanup_debugfs(udc);
usb_del_gadget_udc(&udc->gadget);
device_unregister(&udc->gadget.dev);
BUG_ON(udc->driver);
platform_set_drvdata(pdev, NULL);

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
dum->devstatus = 0;
dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
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",
driver->driver.name);
dum->gadget.dev.driver = NULL;
dum->driver = NULL;
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
* released along with it. */
static void dummy_gadget_release(struct device *dev)
{
return;
}
static void init_dummy_udc_hw(struct dummy *dum)
{
int i;
@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER;
dev_set_name(&dum->gadget.dev, "gadget");
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);
rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
err_dev:
usb_del_gadget_udc(&dum->gadget);
err_udc:
device_unregister(&dum->gadget.dev);
return rc;
}
@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&dum->gadget);
platform_set_drvdata(pdev, NULL);
device_remove_file(&dum->gadget.dev, &dev_attr_function);
device_unregister(&dum->gadget.dev);
return 0;
}
@ -1923,7 +1906,7 @@ done:
}
/* usb 3.0 root hub device descriptor */
struct {
static struct {
struct usb_bos_descriptor bos;
struct usb_ss_cap_descriptor ss_cap;
} __packed usb3_bos_desc = {

View File

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

View File

@ -715,72 +715,6 @@ fail:
return status;
}
static struct f_acm *acm_alloc_basic_func(void)
{
struct f_acm *acm;
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm)
return NULL;
spin_lock_init(&acm->lock);
acm->port.connect = acm_connect;
acm->port.disconnect = acm_disconnect;
acm->port.send_break = acm_send_break;
acm->port.func.name = "acm";
/* descriptors are per-instance copies */
acm->port.func.bind = acm_bind;
acm->port.func.set_alt = acm_set_alt;
acm->port.func.setup = acm_setup;
acm->port.func.disable = acm_disable;
return acm;
}
#ifdef USB_FACM_INCLUDED
static void
acm_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)
{
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_acm *acm;
acm = acm_alloc_basic_func();
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm)
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);
acm->port_num = opts->port_num;
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;
}
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)
{
struct f_serial_opts *opts;
opts = container_of(fi, struct f_serial_opts, func_inst);
gserial_free_line(opts->port_num);
kfree(opts);
}
static struct usb_function_instance *acm_alloc_instance(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 = 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;
}
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
MODULE_LICENSE("GPL");
#endif

View File

@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
* for calling @gether_cleanup() before module unload.
*/
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;
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);
ecm_string_defs[1].s = ecm->ethaddr;
ecm->port.ioport = dev;
ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet";

View File

@ -528,7 +528,7 @@ error:
* Caller must have called @gether_setup(). Caller is also responsible
* 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;
int status;
@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
if (!eem)
return -ENOMEM;
eem->port.ioport = dev;
eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem";

View File

@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* 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;
int status;
@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
ncm->port.ioport = dev;
ncm->port.is_fixed = true;
ncm->port.func.name = "cdc_network";

View File

@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
/*-------------------------------------------------------------------------*/
static struct usb_interface_descriptor obex_control_intf __initdata = {
static struct usb_interface_descriptor obex_control_intf = {
.bLength = sizeof(obex_control_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
.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),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1,
@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
.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),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 2,
@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
.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),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
.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),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
.bSlaveInterface0 = 2,
};
static struct usb_cdc_obex_desc obex_desc __initdata = {
static struct usb_cdc_obex_desc obex_desc = {
.bLength = sizeof(obex_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_OBEX_TYPE,
@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
/* 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,
.bDescriptorType = USB_DT_ENDPOINT,
@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
.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,
.bDescriptorType = USB_DT_ENDPOINT,
@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
.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_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
/* 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,
.bDescriptorType = USB_DT_ENDPOINT,
@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
.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,
.bDescriptorType = USB_DT_ENDPOINT,
@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
.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_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
/*-------------------------------------------------------------------------*/
static int __init
obex_bind(struct usb_configuration *c, struct usb_function *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;
}
static int obex_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_obex *obex = func_to_obex(f);
int status;
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 */
status = usb_interface_id(c, f);
@ -319,6 +348,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
/* allocate instance-specific endpoints */
status = -ENODEV;
ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
if (!ep)
goto fail;
@ -376,29 +406,16 @@ fail:
return status;
}
#ifdef USBF_OBEX_INCLUDED
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;
usb_free_all_descriptors(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
* @c: the configuration to support the CDC OBEX instance
@ -412,21 +429,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
struct f_obex *obex;
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 */
obex = kzalloc(sizeof *obex, GFP_KERNEL);
if (!obex)
@ -441,7 +443,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
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.unbind = obex_old_unbind;
obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable;
@ -453,5 +455,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
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_LICENSE("GPL");

View File

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

View File

@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include "u_serial.h"
@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
/* interface descriptor: */
static struct usb_interface_descriptor gser_interface_desc __initdata = {
static struct usb_interface_descriptor gser_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
/* 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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.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_fs_in_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: */
static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
static struct usb_endpoint_descriptor gser_hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.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,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.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_hs_in_desc,
(struct usb_descriptor_header *) &gser_hs_out_desc,
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,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.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,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.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,
.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_ss_in_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 */
static int __init
gser_bind(struct usb_configuration *c, struct usb_function *f)
static int gser_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_gser *gser = func_to_gser(f);
int status;
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 */
status = usb_interface_id(c, f);
if (status < 0)
@ -246,44 +258,115 @@ fail:
return status;
}
static void
gser_unbind(struct usb_configuration *c, struct usb_function *f)
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
usb_free_all_descriptors(f);
kfree(func_to_gser(f));
return container_of(to_config_group(item), struct f_serial_opts,
func_inst.group);
}
/**
* gser_bind_config - add a generic serial function to a configuration
* @c: the configuration to support the serial instance
* @port_num: /dev/ttyGS* port this interface will use
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*/
int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
CONFIGFS_ATTR_STRUCT(f_serial_opts);
static ssize_t f_serial_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 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;
int status;
/* 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;
}
struct f_serial_opts *opts;
/* allocate and initialize one new instance */
gser = kzalloc(sizeof *gser, GFP_KERNEL);
gser = kzalloc(sizeof(*gser), GFP_KERNEL);
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.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.set_alt = gser_set_alt;
gser->port.func.disable = gser_disable;
gser->port.func.free_func = gser_free;
status = usb_add_function(c, &gser->port.func);
if (status)
kfree(gser);
return status;
return &gser->port.func;
}
DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Al Borchers");
MODULE_AUTHOR("David Brownell");

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