diff options
333 files changed, 25607 insertions, 9056 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 5f75f8f..b6fbe51 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -220,3 +220,10 @@ Description: If the device doesn't support LTM, the file will read "no". The file will be present for all speeds of USB devices, and will always read "no" for USB 1.1 and USB 2.0 devices. + +What: /sys/bus/usb/devices/.../(hub interface)/portX +Date: August 2012 +Contact: Lan Tianyu <tianyu.lan@intel.com> +Description: + The /sys/bus/usb/devices/.../(hub interface)/portX + is usb port device's sysfs directory. diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt new file mode 100644 index 0000000..ca8fa56 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt @@ -0,0 +1,14 @@ +AM33XX MUSB GLUE + - compatible : Should be "ti,musb-am33xx" + - ti,hwmods : must be "usb_otg_hs" + - 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 + MUSB configuration-specific setting. Should be set to "16" + - ram_bits : Specifies the ram address size. Should be set to "12" + - port0_mode : Should be "3" to represent OTG. "1" signifies HOST and "2" + represents PERIPHERAL. + - port1_mode : Should be "1" to represent HOST. "3" signifies OTG and "2" + represents PERIPHERAL. + - power : Should be "250". This signifies the controller can supply upto + 500mA when operating in host mode. diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt index 2c29041..5778b9c 100644 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -7,7 +7,10 @@ Required properties: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port +- fsl,usbmisc: phandler of non-core register device, with one argument + that indicate usb controller index - vbus-supply: regulator for vbus +- disable-over-current: disable over current detect Examples: usb@02184000 { /* USB OTG */ @@ -15,4 +18,6 @@ usb@02184000 { /* USB OTG */ reg = <0x02184000 0x200>; interrupts = <0 43 0x04>; fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; + disable-over-current; }; diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt new file mode 100644 index 0000000..29a043e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -0,0 +1,33 @@ +OMAP GLUE + +OMAP MUSB GLUE + - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" + - ti,hwmods : must be "usb_otg_hs" + - 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 + 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 + 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" + represents PERIPHERAL. + - power : Should be "50". This signifies the controller can supply upto + 100mA when operating in host mode. + +SOC specific device node entry +usb_otg_hs: usb_otg_hs@4a0ab000 { + compatible = "ti,omap4-musb"; + ti,hwmods = "usb_otg_hs"; + multipoint = <1>; + num_eps = <16>; + ram_bits = <12>; +}; + +Board specific device node entry +&usb_otg_hs { + interface_type = <1>; + mode = <3>; + power = <50>; +}; diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt new file mode 100644 index 0000000..91477d6 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/platform-uhci.txt @@ -0,0 +1,12 @@ +Generic Platform UHCI controllers. + +Required properties: + - compatible: Should be "platform-uhci". + - reg: Address range of the uhci registers + - interrupts: Should contain the uhci interrupt. + +usb: uhci@D8007301 { + compatible = "platform-uhci", "usb-uhci"; + reg = <0xD8007301 0x200>; + interrupts = <0>; +}; diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt new file mode 100644 index 0000000..79729a9 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/pxa-usb.txt @@ -0,0 +1,31 @@ +PXA USB controllers + +OHCI + +Required properties: + - compatible: Should be "marvell,pxa-ohci" for USB controllers + used in host mode. + +Optional properties: + - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3" + If present, enables the appropriate USB port of the controller. + - "marvell,port-mode" selects the mode of the ports: + 1 = PMM_NPS_MODE + 2 = PMM_GLOBAL_MODE + 3 = PMM_PERPORT_MODE + - "marvell,power-sense-low" - power sense pin is low-active. + - "marvell,power-control-low" - power control pin is low-active. + - "marvell,no-oc-protection" - disable over-current protection. + - "marvell,oc-mode-perport" - enable per-port over-current protection. + - "marvell,power_on_delay" Power On to Power Good time - in ms. + +Example: + + usb0: ohci@4c000000 { + compatible = "marvell,pxa-ohci", "usb-ohci"; + reg = <0x4c000000 0x100000>; + interrupts = <18>; + marvell,enable-port1; + marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */ + }; + diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt new file mode 100644 index 0000000..36b9aed --- /dev/null +++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt @@ -0,0 +1,40 @@ +USB COMPARATOR OF TWL CHIPS + +TWL6030 USB COMPARATOR + - compatible : Should be "ti,twl6030-usb" + - interrupts : Two interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts when + the controller has to act as host and the second interrupt number is the + usb interrupt number that raises VBUS interrupts when the controller has to + act as device + - usb-supply : phandle to the regulator device tree node. It should be vusb + if it is twl6030 or ldousb if it is twl6025 subclass. + +twl6030-usb { + compatible = "ti,twl6030-usb"; + interrupts = < 4 10 >; +}; + +Board specific device node entry +&twl6030-usb { + usb-supply = <&vusb>; +}; + +TWL4030 USB PHY AND COMPARATOR + - compatible : Should be "ti,twl4030-usb" + - interrupts : The interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts + and VBUS interrupts. The second interrupt number is optional. + - <supply-name>-supply : phandle to the regulator device tree node. + <supply-name> should be vusb1v5, vusb1v8 and vusb3v1 + - usb_mode : The mode used by the phy to connect to the controller. "1" + specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode. + +twl4030-usb { + compatible = "ti,twl4030-usb"; + interrupts = < 10 4 >; + usb1v5-supply = <&vusb1v5>; + usb1v8-supply = <&vusb1v8>; + usb3v1-supply = <&vusb3v1>; + usb_mode = <1>; +}; diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt new file mode 100644 index 0000000..80d4148 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt @@ -0,0 +1,17 @@ +USB PHY + +OMAP USB2 PHY + +Required properties: + - compatible: Should be "ti,omap-usb2" + - reg : Address and length of the register set for the device. Also +add the address of control module dev conf register until a driver for +control module is added + +This is usually a subnode of ocp2scp to which it is connected. + +usb2phy@4a0ad080 { + compatible = "ti,omap-usb2"; + reg = <0x4a0ad080 0x58>, + <0x4a002300 0x4>; +}; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt new file mode 100644 index 0000000..97ce94e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt @@ -0,0 +1,14 @@ +* Freescale i.MX non-core registers + +Required properties: +- #index-cells: Cells used to descibe usb controller index. Should be <1> +- compatible: Should be one of below: + "fsl,imx6q-usbmisc" for imx6q +- reg: Should contain registers location and length + +Examples: +usbmisc@02184800 { + #index-cells = <1>; + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; +}; diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt new file mode 100644 index 0000000..5fb8fd6 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt @@ -0,0 +1,12 @@ +VIA VT8500 and Wondermedia WM8xxx SoC USB controllers. + +Required properties: + - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci". + - reg: Address range of the ehci registers. size should be 0x200 + - interrupts: Should contain the ehci interrupt. + +usb: ehci@D8007100 { + compatible = "wm,prizm-ehci", "usb-ehci"; + reg = <0xD8007100 0x200>; + interrupts = <1>; +}; diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index bc55d38..43975ba 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -463,17 +463,6 @@ Who: Bjorn Helgaas <bhelgaas@google.com> ---------------------------- -What: Low Performance USB Block driver ("CONFIG_BLK_DEV_UB") -When: 3.6 -Why: This driver provides support for USB storage devices like "USB - sticks". As of now, it is deactivated in Debian, Fedora and - Ubuntu. All current users can switch over to usb-storage - (CONFIG_USB_STORAGE) which only drawback is the additional SCSI - stack. -Who: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> - ----------------------------- - What: get_robust_list syscall When: 2013 Why: There appear to be no production users of the get_robust_list syscall, diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt index 074b159..35d70ed 100644 --- a/Documentation/usb/persist.txt +++ b/Documentation/usb/persist.txt @@ -155,6 +155,9 @@ If the kernel gets fooled in this way, it's almost certain to cause data corruption and to crash your system. You'll have no one to blame but yourself. +For those devices with avoid_reset_quirk attribute being set, persist +maybe fail because they may morph after reset. + YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK! That having been said, most of the time there shouldn't be any trouble diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 0d362e9..3d2a988 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -32,6 +32,7 @@ #include <linux/spi/ads7846.h> #include <linux/i2c/twl.h> #include <linux/usb/otg.h> +#include <linux/usb/nop-usb-xceiv.h> #include <linux/smsc911x.h> #include <linux/wl12xx.h> diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index afb6091..64b564f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -5890,6 +5890,12 @@ static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = { .pa_end = 0x4a0ab003, .flags = ADDR_TYPE_RT }, + { + /* XXX: Remove this once control module driver is in place */ + .pa_start = 0x4a00233c, + .pa_end = 0x4a00233f, + .flags = ADDR_TYPE_RT + }, { } }; diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c index d52651a..874aecc 100644 --- a/arch/arm/mach-omap2/omap_phy_internal.c +++ b/arch/arm/mach-omap2/omap_phy_internal.c @@ -31,144 +31,6 @@ #include <plat/usb.h> #include "control.h" -/* OMAP control module register for UTMI PHY */ -#define CONTROL_DEV_CONF 0x300 -#define PHY_PD 0x1 - -#define USBOTGHS_CONTROL 0x33c -#define AVALID BIT(0) -#define BVALID BIT(1) -#define VBUSVALID BIT(2) -#define SESSEND BIT(3) -#define IDDIG BIT(4) - -static struct clk *phyclk, *clk48m, *clk32k; -static void __iomem *ctrl_base; -static int usbotghs_control; - -int omap4430_phy_init(struct device *dev) -{ - ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K); - if (!ctrl_base) { - pr_err("control module ioremap failed\n"); - return -ENOMEM; - } - /* Power down the phy */ - __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF); - - if (!dev) { - iounmap(ctrl_base); - return 0; - } - - phyclk = clk_get(dev, "ocp2scp_usb_phy_ick"); - if (IS_ERR(phyclk)) { - dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n"); - iounmap(ctrl_base); - return PTR_ERR(phyclk); - } - - clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m"); - if (IS_ERR(clk48m)) { - dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n"); - clk_put(phyclk); - iounmap(ctrl_base); - return PTR_ERR(clk48m); - } - - clk32k = clk_get(dev, "usb_phy_cm_clk32k"); - if (IS_ERR(clk32k)) { - dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n"); - clk_put(phyclk); - clk_put(clk48m); - iounmap(ctrl_base); - return PTR_ERR(clk32k); - } - return 0; -} - -int omap4430_phy_set_clk(struct device *dev, int on) -{ - static int state; - - if (on && !state) { - /* Enable the phy clocks */ - clk_enable(phyclk); - clk_enable(clk48m); - clk_enable(clk32k); - state = 1; - } else if (state) { - /* Disable the phy clocks */ - clk_disable(phyclk); - clk_disable(clk48m); - clk_disable(clk32k); - state = 0; - } - return 0; -} - -int omap4430_phy_power(struct device *dev, int ID, int on) -{ - if (on) { - if (ID) - /* enable VBUS valid, IDDIG groung */ - __raw_writel(AVALID | VBUSVALID, ctrl_base + - USBOTGHS_CONTROL); - else - /* - * Enable VBUS Valid, AValid and IDDIG - * high impedance - */ - __raw_writel(IDDIG | AVALID | VBUSVALID, - ctrl_base + USBOTGHS_CONTROL); - } else { - /* Enable session END and IDIG to high impedance. */ - __raw_writel(SESSEND | IDDIG, ctrl_base + - USBOTGHS_CONTROL); - } - return 0; -} - -int omap4430_phy_suspend(struct device *dev, int suspend) -{ - if (suspend) { - /* Disable the clocks */ - omap4430_phy_set_clk(dev, 0); - /* Power down the phy */ - __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF); - - /* save the context */ - usbotghs_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL); - } else { - /* Enable the internel phy clcoks */ - omap4430_phy_set_clk(dev, 1); - /* power on the phy */ - if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) { - __raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF); - mdelay(200); - } - - /* restore the context */ - __raw_writel(usbotghs_control, ctrl_base + USBOTGHS_CONTROL); - } - - return 0; -} - -int omap4430_phy_exit(struct device *dev) -{ - if (ctrl_base) - iounmap(ctrl_base); - if (phyclk) - clk_put(phyclk); - if (clk48m) - clk_put(clk48m); - if (clk32k) - clk_put(clk32k); - - return 0; -} - void am35x_musb_reset(void) { u32 regval; diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index db5ff66..329b726 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -251,11 +251,6 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, #if defined(CONFIG_ARCH_OMAP4) static struct twl4030_usb_data omap4_usb_pdata = { - .phy_init = omap4430_phy_init, - .phy_exit = omap4430_phy_exit, - .phy_power = omap4430_phy_power, - .phy_set_clock = omap4430_phy_set_clk, - .phy_suspend = omap4430_phy_suspend, }; static struct regulator_init_data omap4_vdac_idata = { diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index c4a5768..e9b4b23 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -117,7 +117,4 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) dev->dma_mask = &musb_dmamask; dev->coherent_dma_mask = musb_dmamask; put_device(dev); - - if (cpu_is_omap44xx()) - omap4430_phy_init(dev); } diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index c3d7303..0e82b7f 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o -obj-$(CONFIG_USB_SUPPORT) += usb_phy.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index c70e65f..d8ab762 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -27,7 +27,7 @@ #include <mach/irqs.h> #include <mach/iomap.h> #include <mach/dma.h> -#include <mach/usb_phy.h> +#include <linux/usb/tegra_usb_phy.h> #include "gpio-names.h" #include "devices.h" diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h index 4f50527..906a61f 100644 --- a/arch/arm/mach-tegra/devices.h +++ b/arch/arm/mach-tegra/devices.h @@ -22,7 +22,7 @@ #include <linux/platform_device.h> #include <linux/platform_data/tegra_usb.h> -#include <mach/usb_phy.h> +#include <linux/usb/tegra_usb_phy.h> extern struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config; diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c index f9fbeb2..6fd9d60 100644 --- a/arch/arm/mach-vt8500/bv07.c +++ b/arch/arm/mach-vt8500/bv07.c @@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = { &vt8500_device_uart0, &vt8500_device_lcdc, &vt8500_device_ehci, + &vt8500_device_uhci, &vt8500_device_ge_rops, &vt8500_device_pwm, &vt8500_device_pwmbl, diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c index 19519ae..def7fe3 100644 --- a/arch/arm/mach-vt8500/devices-vt8500.c +++ b/arch/arm/mach-vt8500/devices-vt8500.c @@ -48,6 +48,11 @@ void __init vt8500_set_resources(void) tmp[1] = wmt_irq_res(IRQ_EHCI); wmt_res_add(&vt8500_device_ehci, tmp, 2); + /* vt8500 uses a single IRQ for both EHCI and UHCI controllers */ + tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512); + tmp[1] = wmt_irq_res(IRQ_EHCI); + wmt_res_add(&vt8500_device_uhci, tmp, 2); + tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256); wmt_res_add(&vt8500_device_ge_rops, tmp, 1); diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c index db4594e..c810454 100644 --- a/arch/arm/mach-vt8500/devices-wm8505.c +++ b/arch/arm/mach-vt8500/devices-wm8505.c @@ -55,6 +55,10 @@ void __init wm8505_set_resources(void) tmp[1] = wmt_irq_res(IRQ_EHCI); wmt_res_add(&vt8500_device_ehci, tmp, 2); + tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512); + tmp[1] = wmt_irq_res(IRQ_UHCI); + wmt_res_add(&vt8500_device_uhci, tmp, 2); + tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256); wmt_res_add(&vt8500_device_ge_rops, tmp, 1); diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c index 1fcdc36..46ff82d 100644 --- a/arch/arm/mach-vt8500/devices.c +++ b/arch/arm/mach-vt8500/devices.c @@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = { }, }; +static u64 uhci_dma_mask = DMA_BIT_MASK(32); + +struct platform_device vt8500_device_uhci = { + .name = "platform-uhci", + .id = 0, + .dev = { + .dma_mask = &uhci_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + struct platform_device vt8500_device_ge_rops = { .name = "wmt_ge_rops", .id = -1, diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h index 188d4e1..0e6d9f9 100644 --- a/arch/arm/mach-vt8500/devices.h +++ b/arch/arm/mach-vt8500/devices.h @@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5; extern struct platform_device vt8500_device_lcdc; extern struct platform_device vt8500_device_wm8505_fb; extern struct platform_device vt8500_device_ehci; +extern struct platform_device vt8500_device_uhci; extern struct platform_device vt8500_device_ge_rops; extern struct platform_device vt8500_device_pwm; extern struct platform_device vt8500_device_pwmbl; diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c index db19886..4804e2a 100644 --- a/arch/arm/mach-vt8500/wm8505_7in.c +++ b/arch/arm/mach-vt8500/wm8505_7in.c @@ -32,6 +32,7 @@ static void __iomem *pmc_hiber; static struct platform_device *devices[] __initdata = { &vt8500_device_uart0, &vt8500_device_ehci, + &vt8500_device_uhci, &vt8500_device_wm8505_fb, &vt8500_device_ge_rops, &vt8500_device_pwm, diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index a796407..f529407 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -353,18 +353,6 @@ config BLK_DEV_SX8 Use devices /dev/sx8/$N and /dev/sx8/$Np$M. -config BLK_DEV_UB - tristate "Low Performance USB Block driver (deprecated)" - depends on USB - help - This driver supports certain USB attached storage devices - such as flash keys. - - If you enable this driver, it is recommended to avoid conflicts - with usb-storage by enabling USB_LIBUSUAL. - - If unsure, say N. - config BLK_DEV_RAM tristate "RAM block device support" ---help--- diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5b79505..17e82df 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o -obj-$(CONFIG_BLK_DEV_UB) += ub.o obj-$(CONFIG_BLK_DEV_HD) += hd.o obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o diff --git a/drivers/block/ub.c b/drivers/block/ub.c deleted file mode 100644 index fcec022..0000000 --- a/drivers/block/ub.c +++ /dev/null @@ -1,2474 +0,0 @@ -/* - * The low performance USB storage driver (ub). - * - * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) - * - * This work is a part of Linux kernel, is derived from it, - * and is not licensed separately. See file COPYING for details. - * - * TODO (sorted by decreasing priority) - * -- Return sense now that rq allows it (we always auto-sense anyway). - * -- set readonly flag for CDs, set removable flag for CF readers - * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) - * -- verify the 13 conditions and do bulk resets - * -- highmem - * -- move top_sense and work_bcs into separate allocations (if they survive) - * for cache purists and esoteric architectures. - * -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ? - * -- prune comments, they are too volumnous - * -- Resove XXX's - * -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb_usual.h> -#include <linux/blkdev.h> -#include <linux/timer.h> -#include <linux/scatterlist.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <scsi/scsi.h> - -#define DRV_NAME "ub" - -#define UB_MAJOR 180 - -/* - * The command state machine is the key model for understanding of this driver. - * - * The general rule is that all transitions are done towards the bottom - * of the diagram, thus preventing any loops. - * - * An exception to that is how the STAT state is handled. A counter allows it - * to be re-entered along the path marked with [C]. - * - * +--------+ - * ! INIT ! - * +--------+ - * ! - * ub_scsi_cmd_start fails ->--------------------------------------\ - * ! ! - * V ! - * +--------+ ! - * ! CMD ! ! - * +--------+ ! - * ! +--------+ ! - * was -EPIPE -->-------------------------------->! CLEAR ! ! - * ! +--------+ ! - * ! ! ! - * was error -->------------------------------------- ! --------->\ - * ! ! ! - * /--<-- cmd->dir == NONE ? ! ! - * ! ! ! ! - * ! V ! ! - * ! +--------+ ! ! - * ! ! DATA ! ! ! - * ! +--------+ ! ! - * ! ! +---------+ ! ! - * ! was -EPIPE -->--------------->! CLR2STS ! ! ! - * ! ! +---------+ ! ! - * ! ! ! ! ! - * ! ! was error -->---- ! --------->\ - * ! was error -->--------------------- ! ------------- ! --------->\ - * ! ! ! ! ! - * ! V ! ! ! - * \--->+--------+ ! ! ! - * ! STAT !<--------------------------/ ! ! - * /--->+--------+ ! ! - * ! ! ! ! - * [C] was -EPIPE -->-----------\ ! ! - * ! ! ! ! ! - * +<---- len == 0 ! ! ! - * ! ! ! ! ! - * ! was error -->--------------------------------------!---------->\ - * ! ! ! ! ! - * +<---- bad CSW ! ! ! - * +<---- bad tag ! ! ! - * ! ! V ! ! - * ! ! +--------+ ! ! - * ! ! ! CLRRS ! ! ! - * ! ! +--------+ ! ! - * ! ! ! ! ! - * \------- ! --------------------[C]--------\ ! ! - * ! ! ! ! - * cmd->error---\ +--------+ ! ! - * ! +--------------->! SENSE !<----------/ ! - * STAT_FAIL----/ +--------+ ! - * ! ! V - * ! V +--------+ - * \--------------------------------\--------------------->! DONE ! - * +--------+ - */ - -/* - * This many LUNs per USB device. - * Every one of them takes a host, see UB_MAX_HOSTS. - */ -#define UB_MAX_LUNS 9 - -/* - */ - -#define UB_PARTS_PER_LUN 8 - -#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ - -#define UB_SENSE_SIZE 18 - -/* - */ -struct ub_dev; - -#define UB_MAX_REQ_SG 9 /* cdrecord requires 32KB and maybe a header */ -#define UB_MAX_SECTORS 64 - -/* - * A second is more than enough for a 32K transfer (UB_MAX_SECTORS) - * even if a webcam hogs the bus, but some devices need time to spin up. - */ -#define UB_URB_TIMEOUT (HZ*2) -#define UB_DATA_TIMEOUT (HZ*5) /* ZIP does spin-ups in the data phase */ -#define UB_STAT_TIMEOUT (HZ*5) /* Same spinups and eject for a dataless cmd. */ -#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ - -/* - * An instance of a SCSI command in transit. - */ -#define UB_DIR_NONE 0 -#define UB_DIR_READ 1 -#define UB_DIR_ILLEGAL2 2 -#define UB_DIR_WRITE 3 - -#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ - (((c)==UB_DIR_READ)? 'r': 'n')) - -enum ub_scsi_cmd_state { - UB_CMDST_INIT, /* Initial state */ - UB_CMDST_CMD, /* Command submitted */ - UB_CMDST_DATA, /* Data phase */ - UB_CMDST_CLR2STS, /* Clearing before requesting status */ - UB_CMDST_STAT, /* Status phase */ - UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ - UB_CMDST_CLRRS, /* Clearing before retrying status */ - UB_CMDST_SENSE, /* Sending Request Sense */ - UB_CMDST_DONE /* Final state */ -}; - -struct ub_scsi_cmd { - unsigned char cdb[UB_MAX_CDB_SIZE]; - unsigned char cdb_len; - - unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ - enum ub_scsi_cmd_state state; - unsigned int tag; - struct ub_scsi_cmd *next; - - int error; /* Return code - valid upon done */ - unsigned int act_len; /* Return size */ - unsigned char key, asc, ascq; /* May be valid if error==-EIO */ - - int stat_count; /* Retries getting status. */ - unsigned int timeo; /* jiffies until rq->timeout changes */ - - unsigned int len; /* Requested length */ - unsigned int current_sg; - unsigned int nsg; /* sgv[nsg] */ - struct scatterlist sgv[UB_MAX_REQ_SG]; - - struct ub_lun *lun; - void (*done)(struct ub_dev *, struct ub_scsi_cmd *); - void *back; -}; - -struct ub_request { - struct request *rq; - unsigned int current_try; - unsigned int nsg; /* sgv[nsg] */ - struct scatterlist sgv[UB_MAX_REQ_SG]; -}; - -/* - */ -struct ub_capacity { - unsigned long nsec; /* Linux size - 512 byte sectors */ - unsigned int bsize; /* Linux hardsect_size */ - unsigned int bshift; /* Shift between 512 and hard sects */ -}; - -/* - * This is a direct take-off from linux/include/completion.h - * The difference is that I do not wait on this thing, just poll. - * When I want to wait (ub_probe), I just use the stock completion. - * - * Note that INIT_COMPLETION takes no lock. It is correct. But why - * in the bloody hell that thing takes struct instead of pointer to struct - * is quite beyond me. I just copied it from the stock completion. - */ -struct ub_completion { - unsigned int done; - spinlock_t lock; -}; - -static DEFINE_MUTEX(ub_mutex); -static inline void ub_init_completion(struct ub_completion *x) -{ - x->done = 0; - spin_lock_init(&x->lock); -} - -#define UB_INIT_COMPLETION(x) ((x).done = 0) - -static void ub_complete(struct ub_completion *x) -{ - unsigned long flags; - - spin_lock_irqsave(&x->lock, flags); - x->done++; - spin_unlock_irqrestore(&x->lock, flags); -} - -static int ub_is_completed(struct ub_completion *x) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&x->lock, flags); - ret = x->done; - spin_unlock_irqrestore(&x->lock, flags); - return ret; -} - -/* - */ -struct ub_scsi_cmd_queue { - int qlen, qmax; - struct ub_scsi_cmd *head, *tail; -}; - -/* - * The block device instance (one per LUN). - */ -struct ub_lun { - struct ub_dev *udev; - struct list_head link; - struct gendisk *disk; - int id; /* Host index */ - int num; /* LUN number */ - char name[16]; - - int changed; /* Media was changed */ - int removable; - int readonly; - - struct ub_request urq; - - /* Use Ingo's mempool if or when we have more than one command. */ - /* - * Currently we never need more than one command for the whole device. - * However, giving every LUN a command is a cheap and automatic way - * to enforce fairness between them. - */ - int cmda[1]; - struct ub_scsi_cmd cmdv[1]; - - struct ub_capacity capacity; -}; - -/* - * The USB device instance. - */ -struct ub_dev { - spinlock_t *lock; - atomic_t poison; /* The USB device is disconnected */ - int openc; /* protected by ub_lock! */ - /* kref is too implicit for our taste */ - int reset; /* Reset is running */ - int bad_resid; - unsigned int tagcnt; - char name[12]; - struct usb_device *dev; - struct usb_interface *intf; - - struct list_head luns; - - unsigned int send_bulk_pipe; /* cached pipe values */ - unsigned int recv_bulk_pipe; - unsigned int send_ctrl_pipe; - unsigned int recv_ctrl_pipe; - - struct tasklet_struct tasklet; - - struct ub_scsi_cmd_queue cmd_queue; - struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */ - unsigned char top_sense[UB_SENSE_SIZE]; - - struct ub_completion work_done; - struct urb work_urb; - struct timer_list work_timer; - int last_pipe; /* What might need clearing */ - __le32 signature; /* Learned signature */ - struct bulk_cb_wrap work_bcb; - struct bulk_cs_wrap work_bcs; - struct usb_ctrlrequest work_cr; - - struct work_struct reset_work; - wait_queue_head_t reset_wait; -}; - -/* - */ -static void ub_cleanup(struct ub_dev *sc); -static int ub_request_fn_1(struct ub_lun *lun, struct request *rq); -static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq); -static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq); -static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_end_rq(struct request *rq, unsigned int status); -static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, - struct ub_request *urq, struct ub_scsi_cmd *cmd); -static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_urb_complete(struct urb *urb); -static void ub_scsi_action(unsigned long _dev); -static void ub_scsi_dispatch(struct ub_dev *sc); -static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); -static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, - int stalled_pipe); -static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); -static void ub_reset_enter(struct ub_dev *sc, int try); -static void ub_reset_task(struct work_struct *work); -static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun); -static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, - struct ub_capacity *ret); -static int ub_sync_reset(struct ub_dev *sc); -static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe); -static int ub_probe_lun(struct ub_dev *sc, int lnum); - -/* - */ -#ifdef CONFIG_USB_LIBUSUAL - -#define ub_usb_ids usb_storage_usb_ids -#else - -static const struct usb_device_id ub_usb_ids[] = { - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, ub_usb_ids); -#endif /* CONFIG_USB_LIBUSUAL */ - -/* - * Find me a way to identify "next free minor" for add_disk(), - * and the array disappears the next day. However, the number of - * hosts has something to do with the naming and /proc/partitions. - * This has to be thought out in detail before changing. - * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. - */ -#define UB_MAX_HOSTS 26 -static char ub_hostv[UB_MAX_HOSTS]; - -#define UB_QLOCK_NUM 5 -static spinlock_t ub_qlockv[UB_QLOCK_NUM]; -static int ub_qlock_next = 0; - -static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */ - -/* - * The id allocator. - * - * This also stores the host for indexing by minor, which is somewhat dirty. - */ -static int ub_id_get(void) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&ub_lock, flags); - for (i = 0; i < UB_MAX_HOSTS; i++) { - if (ub_hostv[i] == 0) { - ub_hostv[i] = 1; - spin_unlock_irqrestore(&ub_lock, flags); - return i; - } - } - spin_unlock_irqrestore(&ub_lock, flags); - return -1; -} - -static void ub_id_put(int id) -{ - unsigned long flags; - - if (id < 0 || id >= UB_MAX_HOSTS) { - printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id); - return; - } - - spin_lock_irqsave(&ub_lock, flags); - if (ub_hostv[id] == 0) { - spin_unlock_irqrestore(&ub_lock, flags); - printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); - return; - } - ub_hostv[id] = 0; - spin_unlock_irqrestore(&ub_lock, flags); -} - -/* - * This is necessitated by the fact that blk_cleanup_queue does not - * necesserily destroy the queue. Instead, it may merely decrease q->refcnt. - * Since our blk_init_queue() passes a spinlock common with ub_dev, - * we have life time issues when ub_cleanup frees ub_dev. - */ -static spinlock_t *ub_next_lock(void) -{ - unsigned long flags; - spinlock_t *ret; - - spin_lock_irqsave(&ub_lock, flags); - ret = &ub_qlockv[ub_qlock_next]; - ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM; - spin_unlock_irqrestore(&ub_lock, flags); - return ret; -} - -/* - * Downcount for deallocation. This rides on two assumptions: - * - once something is poisoned, its refcount cannot grow - * - opens cannot happen at this time (del_gendisk was done) - * If the above is true, we can drop the lock, which we need for - * blk_cleanup_queue(): the silly thing may attempt to sleep. - * [Actually, it never needs to sleep for us, but it calls might_sleep()] - */ -static void ub_put(struct ub_dev *sc) -{ - unsigned long flags; - - spin_lock_irqsave(&ub_lock, flags); - --sc->openc; - if (sc->openc == 0 && atomic_read(&sc->poison)) { - spin_unlock_irqrestore(&ub_lock, flags); - ub_cleanup(sc); - } else { - spin_unlock_irqrestore(&ub_lock, flags); - } -} - -/* - * Final cleanup and deallocation. - */ -static void ub_cleanup(struct ub_dev *sc) -{ - struct list_head *p; - struct ub_lun *lun; - struct request_queue *q; - - while (!list_empty(&sc->luns)) { - p = sc->luns.next; - lun = list_entry(p, struct ub_lun, link); - list_del(p); - - /* I don't think queue can be NULL. But... Stolen from sx8.c */ - if ((q = lun->disk->queue) != NULL) - blk_cleanup_queue(q); - /* - * If we zero disk->private_data BEFORE put_disk, we have - * to check for NULL all over the place in open, release, - * check_media and revalidate, because the block level - * semaphore is well inside the put_disk. - * But we cannot zero after the call, because *disk is gone. - * The sd.c is blatantly racy in this area. - */ - /* disk->private_data = NULL; */ - put_disk(lun->disk); - lun->disk = NULL; - - ub_id_put(lun->id); - kfree(lun); - } - - usb_set_intfdata(sc->intf, NULL); - usb_put_intf(sc->intf); - usb_put_dev(sc->dev); - kfree(sc); -} - -/* - * The "command allocator". - */ -static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun) -{ - struct ub_scsi_cmd *ret; - - if (lun->cmda[0]) - return NULL; - ret = &lun->cmdv[0]; - lun->cmda[0] = 1; - return ret; -} - -static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd) -{ - if (cmd != &lun->cmdv[0]) { - printk(KERN_WARNING "%s: releasing a foreign cmd %p\n", - lun->name, cmd); - return; - } - if (!lun->cmda[0]) { - printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name); - return; - } - lun->cmda[0] = 0; -} - -/* - * The command queue. - */ -static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - - if (t->qlen++ == 0) { - t->head = cmd; - t->tail = cmd; - } else { - t->tail->next = cmd; - t->tail = cmd; - } - - if (t->qlen > t->qmax) - t->qmax = t->qlen; -} - -static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - - if (t->qlen++ == 0) { - t->head = cmd; - t->tail = cmd; - } else { - cmd->next = t->head; - t->head = cmd; - } - - if (t->qlen > t->qmax) - t->qmax = t->qlen; -} - -static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) -{ - struct ub_scsi_cmd_queue *t = &sc->cmd_queue; - struct ub_scsi_cmd *cmd; - - if (t->qlen == 0) - return NULL; - if (--t->qlen == 0) - t->tail = NULL; - cmd = t->head; - t->head = cmd->next; - cmd->next = NULL; - return cmd; -} - -#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head) - -/* - * The request function is our main entry point - */ - -static void ub_request_fn(struct request_queue *q) -{ - struct ub_lun *lun = q->queuedata; - struct request *rq; - - while ((rq = blk_peek_request(q)) != NULL) { - if (ub_request_fn_1(lun, rq) != 0) { - blk_stop_queue(q); - break; - } - } -} - -static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) -{ - struct ub_dev *sc = lun->udev; - struct ub_scsi_cmd *cmd; - struct ub_request *urq; - int n_elem; - - if (atomic_read(&sc->poison)) { - blk_start_request(rq); - ub_end_rq(rq, DID_NO_CONNECT << 16); - return 0; - } - - if (lun->changed && rq->cmd_type != REQ_TYPE_BLOCK_PC) { - blk_start_request(rq); - ub_end_rq(rq, SAM_STAT_CHECK_CONDITION); - return 0; - } - - if (lun->urq.rq != NULL) - return -1; - if ((cmd = ub_get_cmd(lun)) == NULL) - return -1; - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - - blk_start_request(rq); - - urq = &lun->urq; - memset(urq, 0, sizeof(struct ub_request)); - urq->rq = rq; - - /* - * get scatterlist from block layer - */ - sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG); - n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); - if (n_elem < 0) { - /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */ - printk(KERN_INFO "%s: failed request map (%d)\n", - lun->name, n_elem); - goto drop; - } - if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ - printk(KERN_WARNING "%s: request with %d segments\n", - lun->name, n_elem); - goto drop; - } - urq->nsg = n_elem; - - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - ub_cmd_build_packet(sc, lun, cmd, urq); - } else { - ub_cmd_build_block(sc, lun, cmd, urq); - } - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; - cmd->done = ub_rw_cmd_done; - cmd->back = urq; - - cmd->tag = sc->tagcnt++; - if (ub_submit_scsi(sc, cmd) != 0) - goto drop; - - return 0; - -drop: - ub_put_cmd(lun, cmd); - ub_end_rq(rq, DID_ERROR << 16); - return 0; -} - -static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq) -{ - struct request *rq = urq->rq; - unsigned int block, nblks; - - if (rq_data_dir(rq) == WRITE) - cmd->dir = UB_DIR_WRITE; - else - cmd->dir = UB_DIR_READ; - - cmd->nsg = urq->nsg; - memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg); - - /* - * build the command - * - * The call to blk_queue_logical_block_size() guarantees that request - * is aligned, but it is given in terms of 512 byte units, always. - */ - block = blk_rq_pos(rq) >> lun->capacity.bshift; - nblks = blk_rq_sectors(rq) >> lun->capacity.bshift; - - cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10; - /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ - cmd->cdb[2] = block >> 24; - cmd->cdb[3] = block >> 16; - cmd->cdb[4] = block >> 8; - cmd->cdb[5] = block; - cmd->cdb[7] = nblks >> 8; - cmd->cdb[8] = nblks; - cmd->cdb_len = 10; - - cmd->len = blk_rq_bytes(rq); -} - -static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, - struct ub_scsi_cmd *cmd, struct ub_request *urq) -{ - struct request *rq = urq->rq; - - if (blk_rq_bytes(rq) == 0) { - cmd->dir = UB_DIR_NONE; - } else { - if (rq_data_dir(rq) == WRITE) - cmd->dir = UB_DIR_WRITE; - else - cmd->dir = UB_DIR_READ; - } - - cmd->nsg = urq->nsg; - memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg); - - memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); - cmd->cdb_len = rq->cmd_len; - - cmd->len = blk_rq_bytes(rq); - - /* - * To reapply this to every URB is not as incorrect as it looks. - * In return, we avoid any complicated tracking calculations. - */ - cmd->timeo = rq->timeout; -} - -static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_lun *lun = cmd->lun; - struct ub_request *urq = cmd->back; - struct request *rq; - unsigned int scsi_status; - - rq = urq->rq; - - if (cmd->error == 0) { - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - if (cmd->act_len >= rq->resid_len) - rq->resid_len = 0; - else - rq->resid_len -= cmd->act_len; - scsi_status = 0; - } else { - if (cmd->act_len != cmd->len) { - scsi_status = SAM_STAT_CHECK_CONDITION; - } else { - scsi_status = 0; - } - } - } else { - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */ - memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE); - rq->sense_len = UB_SENSE_SIZE; - if (sc->top_sense[0] != 0) - scsi_status = SAM_STAT_CHECK_CONDITION; - else - scsi_status = DID_ERROR << 16; - } else { - if (cmd->error == -EIO && - (cmd->key == 0 || - cmd->key == MEDIUM_ERROR || - cmd->key == UNIT_ATTENTION)) { - if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) - return; - } - scsi_status = SAM_STAT_CHECK_CONDITION; - } - } - - urq->rq = NULL; - - ub_put_cmd(lun, cmd); - ub_end_rq(rq, scsi_status); - blk_start_queue(lun->disk->queue); -} - -static void ub_end_rq(struct request *rq, unsigned int scsi_status) -{ - int error; - - if (scsi_status == 0) { - error = 0; - } else { - error = -EIO; - rq->errors = scsi_status; - } - __blk_end_request_all(rq, error); -} - -static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, - struct ub_request *urq, struct ub_scsi_cmd *cmd) -{ - - if (atomic_read(&sc->poison)) - return -ENXIO; - - ub_reset_enter(sc, urq->current_try); - - if (urq->current_try >= 3) - return -EIO; - urq->current_try++; - - /* Remove this if anyone complains of flooding. */ - printk(KERN_DEBUG "%s: dir %c len/act %d/%d " - "[sense %x %02x %02x] retry %d\n", - sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len, - cmd->key, cmd->asc, cmd->ascq, urq->current_try); - - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - ub_cmd_build_block(sc, lun, cmd, urq); - - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; - cmd->done = ub_rw_cmd_done; - cmd->back = urq; - - cmd->tag = sc->tagcnt++; - -#if 0 /* Wasteful */ - return ub_submit_scsi(sc, cmd); -#else - ub_cmdq_add(sc, cmd); - return 0; -#endif -} - -/* - * Submit a regular SCSI operation (not an auto-sense). - * - * The Iron Law of Good Submit Routine is: - * Zero return - callback is done, Nonzero return - callback is not done. - * No exceptions. - * - * Host is assumed locked. - */ -static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (cmd->state != UB_CMDST_INIT || - (cmd->dir != UB_DIR_NONE && cmd->len == 0)) { - return -EINVAL; - } - - ub_cmdq_add(sc, cmd); - /* - * We can call ub_scsi_dispatch(sc) right away here, but it's a little - * safer to jump to a tasklet, in case upper layers do something silly. - */ - tasklet_schedule(&sc->tasklet); - return 0; -} - -/* - * Submit the first URB for the queued command. - * This function does not deal with queueing in any way. - */ -static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct bulk_cb_wrap *bcb; - int rc; - - bcb = &sc->work_bcb; - - /* - * ``If the allocation length is eighteen or greater, and a device - * server returns less than eithteen bytes of data, the application - * client should assume that the bytes not transferred would have been - * zeroes had the device server returned those bytes.'' - * - * We zero sense for all commands so that when a packet request - * fails it does not return a stale sense. - */ - memset(&sc->top_sense, 0, UB_SENSE_SIZE); - - /* set up the command wrapper */ - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->Tag = cmd->tag; /* Endianness is not important */ - bcb->DataTransferLength = cpu_to_le32(cmd->len); - bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0; - bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0; - bcb->Length = cmd->cdb_len; - - /* copy the command payload */ - memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE); - - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->send_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, - bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - return rc; - } - - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - - cmd->state = UB_CMDST_CMD; - return 0; -} - -/* - * Timeout handler. - */ -static void ub_urb_timeout(unsigned long arg) -{ - struct ub_dev *sc = (struct ub_dev *) arg; - unsigned long flags; - - spin_lock_irqsave(sc->lock, flags); - if (!ub_is_completed(&sc->work_done)) - usb_unlink_urb(&sc->work_urb); - spin_unlock_irqrestore(sc->lock, flags); -} - -/* - * Completion routine for the work URB. - * - * This can be called directly from usb_submit_urb (while we have - * the sc->lock taken) and from an interrupt (while we do NOT have - * the sc->lock taken). Therefore, bounce this off to a tasklet. - */ -static void ub_urb_complete(struct urb *urb) -{ - struct ub_dev *sc = urb->context; - - ub_complete(&sc->work_done); - tasklet_schedule(&sc->tasklet); -} - -static void ub_scsi_action(unsigned long _dev) -{ - struct ub_dev *sc = (struct ub_dev *) _dev; - unsigned long flags; - - spin_lock_irqsave(sc->lock, flags); - ub_scsi_dispatch(sc); - spin_unlock_irqrestore(sc->lock, flags); -} - -static void ub_scsi_dispatch(struct ub_dev *sc) -{ - struct ub_scsi_cmd *cmd; - int rc; - - while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) { - if (cmd->state == UB_CMDST_DONE) { - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - } else if (cmd->state == UB_CMDST_INIT) { - if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) - break; - cmd->error = rc; - cmd->state = UB_CMDST_DONE; - } else { - if (!ub_is_completed(&sc->work_done)) - break; - del_timer(&sc->work_timer); - ub_scsi_urb_compl(sc, cmd); - } - } -} - -static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct urb *urb = &sc->work_urb; - struct bulk_cs_wrap *bcs; - int endp; - int len; - int rc; - - if (atomic_read(&sc->poison)) { - ub_state_done(sc, cmd, -ENODEV); - return; - } - - endp = usb_pipeendpoint(sc->last_pipe); - if (usb_pipein(sc->last_pipe)) - endp |= USB_DIR_IN; - - if (cmd->state == UB_CMDST_CLEAR) { - if (urb->status == -EPIPE) { - /* - * STALL while clearning STALL. - * The control pipe clears itself - nothing to do. - */ - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_sense(sc, cmd); - - } else if (cmd->state == UB_CMDST_CLR2STS) { - if (urb->status == -EPIPE) { - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_stat(sc, cmd); - - } else if (cmd->state == UB_CMDST_CLRRS) { - if (urb->status == -EPIPE) { - printk(KERN_NOTICE "%s: stall on control pipe\n", - sc->name); - goto Bad_End; - } - - /* - * We ignore the result for the halt clear. - */ - - usb_reset_endpoint(sc->dev, endp); - - ub_state_stat_counted(sc, cmd); - - } else if (cmd->state == UB_CMDST_CMD) { - switch (urb->status) { - case 0: - break; - case -EOVERFLOW: - goto Bad_End; - case -EPIPE: - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - /* - * This is typically ENOMEM or some other such shit. - * Retrying is pointless. Just do Bad End on it... - */ - ub_state_done(sc, cmd, rc); - return; - } - cmd->state = UB_CMDST_CLEAR; - return; - case -ESHUTDOWN: /* unplug */ - case -EILSEQ: /* unplug timeout on uhci */ - ub_state_done(sc, cmd, -ENODEV); - return; - default: - goto Bad_End; - } - if (urb->actual_length != US_BULK_CB_WRAP_LEN) { - goto Bad_End; - } - - if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) { - ub_state_stat(sc, cmd); - return; - } - - // udelay(125); // usb-storage has this - ub_data_start(sc, cmd); - - } else if (cmd->state == UB_CMDST_DATA) { - if (urb->status == -EPIPE) { - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - ub_state_done(sc, cmd, rc); - return; - } - cmd->state = UB_CMDST_CLR2STS; - return; - } - if (urb->status == -EOVERFLOW) { - /* - * A babble? Failure, but we must transfer CSW now. - */ - cmd->error = -EOVERFLOW; /* A cheap trick... */ - ub_state_stat(sc, cmd); - return; - } - - if (cmd->dir == UB_DIR_WRITE) { - /* - * Do not continue writes in case of a failure. - * Doing so would cause sectors to be mixed up, - * which is worse than sectors lost. - * - * We must try to read the CSW, or many devices - * get confused. - */ - len = urb->actual_length; - if (urb->status != 0 || - len != cmd->sgv[cmd->current_sg].length) { - cmd->act_len += len; - - cmd->error = -EIO; - ub_state_stat(sc, cmd); - return; - } - - } else { - /* - * If an error occurs on read, we record it, and - * continue to fetch data in order to avoid bubble. - * - * As a small shortcut, we stop if we detect that - * a CSW mixed into data. - */ - if (urb->status != 0) - cmd->error = -EIO; - - len = urb->actual_length; - if (urb->status != 0 || - len != cmd->sgv[cmd->current_sg].length) { - if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN) - goto Bad_End; - } - } - - cmd->act_len += urb->actual_length; - - if (++cmd->current_sg < cmd->nsg) { - ub_data_start(sc, cmd); - return; - } - ub_state_stat(sc, cmd); - - } else if (cmd->state == UB_CMDST_STAT) { - if (urb->status == -EPIPE) { - rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); - if (rc != 0) { - printk(KERN_NOTICE "%s: " - "unable to submit clear (%d)\n", - sc->name, rc); - ub_state_done(sc, cmd, rc); - return; - } - - /* - * Having a stall when getting CSW is an error, so - * make sure uppper levels are not oblivious to it. - */ - cmd->error = -EIO; /* A cheap trick... */ - - cmd->state = UB_CMDST_CLRRS; - return; - } - - /* Catch everything, including -EOVERFLOW and other nasties. */ - if (urb->status != 0) - goto Bad_End; - - if (urb->actual_length == 0) { - ub_state_stat_counted(sc, cmd); - return; - } - - /* - * Check the returned Bulk protocol status. - * The status block has to be validated first. - */ - - bcs = &sc->work_bcs; - - if (sc->signature == cpu_to_le32(0)) { - /* - * This is the first reply, so do not perform the check. - * Instead, remember the signature the device uses - * for future checks. But do not allow a nul. - */ - sc->signature = bcs->Signature; - if (sc->signature == cpu_to_le32(0)) { - ub_state_stat_counted(sc, cmd); - return; - } - } else { - if (bcs->Signature != sc->signature) { - ub_state_stat_counted(sc, cmd); - return; - } - } - - if (bcs->Tag != cmd->tag) { - /* - * This usually happens when we disagree with the - * device's microcode about something. For instance, - * a few of them throw this after timeouts. They buffer - * commands and reply at commands we timed out before. - * Without flushing these replies we loop forever. - */ - ub_state_stat_counted(sc, cmd); - return; - } - - if (!sc->bad_resid) { - len = le32_to_cpu(bcs->Residue); - if (len != cmd->len - cmd->act_len) { - /* - * Only start ignoring if this cmd ended well. - */ - if (cmd->len == cmd->act_len) { - printk(KERN_NOTICE "%s: " - "bad residual %d of %d, ignoring\n", - sc->name, len, cmd->len); - sc->bad_resid = 1; - } - } - } - - switch (bcs->Status) { - case US_BULK_STAT_OK: - break; - case US_BULK_STAT_FAIL: - ub_state_sense(sc, cmd); - return; - case US_BULK_STAT_PHASE: - goto Bad_End; - default: - printk(KERN_INFO "%s: unknown CSW status 0x%x\n", - sc->name, bcs->Status); - ub_state_done(sc, cmd, -EINVAL); - return; - } - - /* Not zeroing error to preserve a babble indicator */ - if (cmd->error != 0) { - ub_state_sense(sc, cmd); - return; - } - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - - } else if (cmd->state == UB_CMDST_SENSE) { - ub_state_done(sc, cmd, -EIO); - - } else { - printk(KERN_WARNING "%s: wrong command state %d\n", - sc->name, cmd->state); - ub_state_done(sc, cmd, -EINVAL); - return; - } - return; - -Bad_End: /* Little Excel is dead */ - ub_state_done(sc, cmd, -EIO); -} - -/* - * Factorization helper for the command state machine: - * Initiate a data segment transfer. - */ -static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct scatterlist *sg = &cmd->sgv[cmd->current_sg]; - int pipe; - int rc; - - UB_INIT_COMPLETION(sc->work_done); - - if (cmd->dir == UB_DIR_READ) - pipe = sc->recv_bulk_pipe; - else - pipe = sc->send_bulk_pipe; - sc->last_pipe = pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg), - sg->length, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return; - } - - if (cmd->timeo) - sc->work_timer.expires = jiffies + cmd->timeo; - else - sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; - add_timer(&sc->work_timer); - - cmd->state = UB_CMDST_DATA; -} - -/* - * Factorization helper for the command state machine: - * Finish the command. - */ -static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) -{ - - cmd->error = rc; - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read. - */ -static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - int rc; - - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->recv_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, - &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - /* XXX Clear stalls */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return -1; - } - - if (cmd->timeo) - sc->work_timer.expires = jiffies + cmd->timeo; - else - sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; - add_timer(&sc->work_timer); - return 0; -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state. - */ -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (__ub_state_stat(sc, cmd) != 0) - return; - - cmd->stat_count = 0; - cmd->state = UB_CMDST_STAT; -} - -/* - * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state with counter (along [C] path). - */ -static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - - if (++cmd->stat_count >= 4) { - ub_state_sense(sc, cmd); - return; - } - - if (__ub_state_stat(sc, cmd) != 0) - return; - - cmd->state = UB_CMDST_STAT; -} - -/* - * Factorization helper for the command state machine: - * Submit a REQUEST SENSE and go to SENSE state. - */ -static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct ub_scsi_cmd *scmd; - struct scatterlist *sg; - int rc; - - if (cmd->cdb[0] == REQUEST_SENSE) { - rc = -EPIPE; - goto error; - } - - scmd = &sc->top_rqs_cmd; - memset(scmd, 0, sizeof(struct ub_scsi_cmd)); - scmd->cdb[0] = REQUEST_SENSE; - scmd->cdb[4] = UB_SENSE_SIZE; - scmd->cdb_len = 6; - scmd->dir = UB_DIR_READ; - scmd->state = UB_CMDST_INIT; - scmd->nsg = 1; - sg = &scmd->sgv[0]; - sg_init_table(sg, UB_MAX_REQ_SG); - sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE, - (unsigned long)sc->top_sense & (PAGE_SIZE-1)); - scmd->len = UB_SENSE_SIZE; - scmd->lun = cmd->lun; - scmd->done = ub_top_sense_done; - scmd->back = cmd; - - scmd->tag = sc->tagcnt++; - - cmd->state = UB_CMDST_SENSE; - - ub_cmdq_insert(sc, scmd); - return; - -error: - ub_state_done(sc, cmd, rc); -} - -/* - * A helper for the command's state machine: - * Submit a stall clear. - */ -static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, - int stalled_pipe) -{ - int endp; - struct usb_ctrlrequest *cr; - int rc; - - endp = usb_pipeendpoint(stalled_pipe); - if (usb_pipein (stalled_pipe)) - endp |= USB_DIR_IN; - - cr = &sc->work_cr; - cr->bRequestType = USB_RECIP_ENDPOINT; - cr->bRequest = USB_REQ_CLEAR_FEATURE; - cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); - cr->wIndex = cpu_to_le16(endp); - cr->wLength = cpu_to_le16(0); - - UB_INIT_COMPLETION(sc->work_done); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - ub_complete(&sc->work_done); - return rc; - } - - sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&sc->work_timer); - return 0; -} - -/* - */ -static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) -{ - unsigned char *sense = sc->top_sense; - struct ub_scsi_cmd *cmd; - - /* - * Find the command which triggered the unit attention or a check, - * save the sense into it, and advance its state machine. - */ - if ((cmd = ub_cmdq_peek(sc)) == NULL) { - printk(KERN_WARNING "%s: sense done while idle\n", sc->name); - return; - } - if (cmd != scmd->back) { - printk(KERN_WARNING "%s: " - "sense done for wrong command 0x%x\n", - sc->name, cmd->tag); - return; - } - if (cmd->state != UB_CMDST_SENSE) { - printk(KERN_WARNING "%s: sense done with bad cmd state %d\n", - sc->name, cmd->state); - return; - } - - /* - * Ignoring scmd->act_len, because the buffer was pre-zeroed. - */ - cmd->key = sense[2] & 0x0F; - cmd->asc = sense[12]; - cmd->ascq = sense[13]; - - ub_scsi_urb_compl(sc, cmd); -} - -/* - * Reset management - */ - -static void ub_reset_enter(struct ub_dev *sc, int try) -{ - - if (sc->reset) { - /* This happens often on multi-LUN devices. */ - return; - } - sc->reset = try + 1; - -#if 0 /* Not needed because the disconnect waits for us. */ - unsigned long flags; - spin_lock_irqsave(&ub_lock, flags); - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); -#endif - -#if 0 /* We let them stop themselves. */ - struct ub_lun *lun; - list_for_each_entry(lun, &sc->luns, link) { - blk_stop_queue(lun->disk->queue); - } -#endif - - schedule_work(&sc->reset_work); -} - -static void ub_reset_task(struct work_struct *work) -{ - struct ub_dev *sc = container_of(work, struct ub_dev, reset_work); - unsigned long flags; - struct ub_lun *lun; - int rc; - - if (!sc->reset) { - printk(KERN_WARNING "%s: Running reset unrequested\n", - sc->name); - return; - } - - if (atomic_read(&sc->poison)) { - ; - } else if ((sc->reset & 1) == 0) { - ub_sync_reset(sc); - msleep(700); /* usb-storage sleeps 6s (!) */ - ub_probe_clear_stall(sc, sc->recv_bulk_pipe); - ub_probe_clear_stall(sc, sc->send_bulk_pipe); - } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) { - ; - } else { - rc = usb_lock_device_for_reset(sc->dev, sc->intf); - if (rc < 0) { - printk(KERN_NOTICE - "%s: usb_lock_device_for_reset failed (%d)\n", - sc->name, rc); - } else { - rc = usb_reset_device(sc->dev); - if (rc < 0) { - printk(KERN_NOTICE "%s: " - "usb_lock_device_for_reset failed (%d)\n", - sc->name, rc); - } - usb_unlock_device(sc->dev); - } - } - - /* - * In theory, no commands can be running while reset is active, - * so nobody can ask for another reset, and so we do not need any - * queues of resets or anything. We do need a spinlock though, - * to interact with block layer. - */ - spin_lock_irqsave(sc->lock, flags); - sc->reset = 0; - tasklet_schedule(&sc->tasklet); - list_for_each_entry(lun, &sc->luns, link) { - blk_start_queue(lun->disk->queue); - } - wake_up(&sc->reset_wait); - spin_unlock_irqrestore(sc->lock, flags); -} - -/* - * XXX Reset brackets are too much hassle to implement, so just stub them - * in order to prevent forced unbinding (which deadlocks solid when our - * ->disconnect method waits for the reset to complete and this kills keventd). - * - * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device, - * or else the post_reset is invoked, and restats I/O on a locked device. - */ -static int ub_pre_reset(struct usb_interface *iface) { - return 0; -} - -static int ub_post_reset(struct usb_interface *iface) { - return 0; -} - -/* - * This is called from a process context. - */ -static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun) -{ - - lun->readonly = 0; /* XXX Query this from the device */ - - lun->capacity.nsec = 0; - lun->capacity.bsize = 512; - lun->capacity.bshift = 0; - - if (ub_sync_tur(sc, lun) != 0) - return; /* Not ready */ - lun->changed = 0; - - if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) { - /* - * The retry here means something is wrong, either with the - * device, with the transport, or with our code. - * We keep this because sd.c has retries for capacity. - */ - if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) { - lun->capacity.nsec = 0; - lun->capacity.bsize = 512; - lun->capacity.bshift = 0; - } - } -} - -/* - * The open funcion. - * This is mostly needed to keep refcounting, but also to support - * media checks on removable media drives. - */ -static int ub_bd_open(struct block_device *bdev, fmode_t mode) -{ - struct ub_lun *lun = bdev->bd_disk->private_data; - struct ub_dev *sc = lun->udev; - unsigned long flags; - int rc; - - spin_lock_irqsave(&ub_lock, flags); - if (atomic_read(&sc->poison)) { - spin_unlock_irqrestore(&ub_lock, flags); - return -ENXIO; - } - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); - - if (lun->removable || lun->readonly) - check_disk_change(bdev); - - /* - * The sd.c considers ->media_present and ->changed not equivalent, - * under some pretty murky conditions (a failure of READ CAPACITY). - * We may need it one day. - */ - if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) { - rc = -ENOMEDIUM; - goto err_open; - } - - if (lun->readonly && (mode & FMODE_WRITE)) { - rc = -EROFS; - goto err_open; - } - - return 0; - -err_open: - ub_put(sc); - return rc; -} - -static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode) -{ - int ret; - - mutex_lock(&ub_mutex); - ret = ub_bd_open(bdev, mode); - mutex_unlock(&ub_mutex); - - return ret; -} - - -/* - */ -static int ub_bd_release(struct gendisk *disk, fmode_t mode) -{ - struct ub_lun *lun = disk->private_data; - struct ub_dev *sc = lun->udev; - - mutex_lock(&ub_mutex); - ub_put(sc); - mutex_unlock(&ub_mutex); - - return 0; -} - -/* - * The ioctl interface. - */ -static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - void __user *usermem = (void __user *) arg; - int ret; - - mutex_lock(&ub_mutex); - ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem); - mutex_unlock(&ub_mutex); - - return ret; -} - -/* - * This is called by check_disk_change if we reported a media change. - * The main onjective here is to discover the features of the media such as - * the capacity, read-only status, etc. USB storage generally does not - * need to be spun up, but if we needed it, this would be the place. - * - * This call can sleep. - * - * The return code is not used. - */ -static int ub_bd_revalidate(struct gendisk *disk) -{ - struct ub_lun *lun = disk->private_data; - - ub_revalidate(lun->udev, lun); - - /* XXX Support sector size switching like in sr.c */ - blk_queue_logical_block_size(disk->queue, lun->capacity.bsize); - set_capacity(disk, lun->capacity.nsec); - // set_disk_ro(sdkp->disk, lun->readonly); - - return 0; -} - -/* - * The check is called by the block layer to verify if the media - * is still available. It is supposed to be harmless, lightweight and - * non-intrusive in case the media was not changed. - * - * This call can sleep. - * - * The return code is bool! - */ -static unsigned int ub_bd_check_events(struct gendisk *disk, - unsigned int clearing) -{ - struct ub_lun *lun = disk->private_data; - - if (!lun->removable) - return 0; - - /* - * We clean checks always after every command, so this is not - * as dangerous as it looks. If the TEST_UNIT_READY fails here, - * the device is actually not ready with operator or software - * intervention required. One dangerous item might be a drive which - * spins itself down, and come the time to write dirty pages, this - * will fail, then block layer discards the data. Since we never - * spin drives up, such devices simply cannot be used with ub anyway. - */ - if (ub_sync_tur(lun->udev, lun) != 0) { - lun->changed = 1; - return DISK_EVENT_MEDIA_CHANGE; - } - - return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0; -} - -static const struct block_device_operations ub_bd_fops = { - .owner = THIS_MODULE, - .open = ub_bd_unlocked_open, - .release = ub_bd_release, - .ioctl = ub_bd_ioctl, - .check_events = ub_bd_check_events, - .revalidate_disk = ub_bd_revalidate, -}; - -/* - * Common ->done routine for commands executed synchronously. - */ -static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) -{ - struct completion *cop = cmd->back; - complete(cop); -} - -/* - * Test if the device has a check condition on it, synchronously. - */ -static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun) -{ - struct ub_scsi_cmd *cmd; - enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) }; - unsigned long flags; - struct completion compl; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - - cmd->cdb[0] = TEST_UNIT_READY; - cmd->cdb_len = 6; - cmd->dir = UB_DIR_NONE; - cmd->state = UB_CMDST_INIT; - cmd->lun = lun; /* This may be NULL, but that's ok */ - cmd->done = ub_probe_done; - cmd->back = &compl; - - spin_lock_irqsave(sc->lock, flags); - cmd->tag = sc->tagcnt++; - - rc = ub_submit_scsi(sc, cmd); - spin_unlock_irqrestore(sc->lock, flags); - - if (rc != 0) - goto err_submit; - - wait_for_completion(&compl); - - rc = cmd->error; - - if (rc == -EIO && cmd->key != 0) /* Retries for benh's key */ - rc = cmd->key; - -err_submit: - kfree(cmd); -err_alloc: - return rc; -} - -/* - * Read the SCSI capacity synchronously (for probing). - */ -static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, - struct ub_capacity *ret) -{ - struct ub_scsi_cmd *cmd; - struct scatterlist *sg; - char *p; - enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 }; - unsigned long flags; - unsigned int bsize, shift; - unsigned long nsec; - struct completion compl; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - p = (char *)cmd + sizeof(struct ub_scsi_cmd); - - cmd->cdb[0] = 0x25; - cmd->cdb_len = 10; - cmd->dir = UB_DIR_READ; - cmd->state = UB_CMDST_INIT; - cmd->nsg = 1; - sg = &cmd->sgv[0]; - sg_init_table(sg, UB_MAX_REQ_SG); - sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1)); - cmd->len = 8; - cmd->lun = lun; - cmd->done = ub_probe_done; - cmd->back = &compl; - - spin_lock_irqsave(sc->lock, flags); - cmd->tag = sc->tagcnt++; - - rc = ub_submit_scsi(sc, cmd); - spin_unlock_irqrestore(sc->lock, flags); - - if (rc != 0) - goto err_submit; - - wait_for_completion(&compl); - - if (cmd->error != 0) { - rc = -EIO; - goto err_read; - } - if (cmd->act_len != 8) { - rc = -EIO; - goto err_read; - } - - /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */ - nsec = be32_to_cpu(*(__be32 *)p) + 1; - bsize = be32_to_cpu(*(__be32 *)(p + 4)); - switch (bsize) { - case 512: shift = 0; break; - case 1024: shift = 1; break; - case 2048: shift = 2; break; - case 4096: shift = 3; break; - default: - rc = -EDOM; - goto err_inv_bsize; - } - - ret->bsize = bsize; - ret->bshift = shift; - ret->nsec = nsec << shift; - rc = 0; - -err_inv_bsize: -err_read: -err_submit: - kfree(cmd); -err_alloc: - return rc; -} - -/* - */ -static void ub_probe_urb_complete(struct urb *urb) -{ - struct completion *cop = urb->context; - complete(cop); -} - -static void ub_probe_timeout(unsigned long arg) -{ - struct completion *cop = (struct completion *) arg; - complete(cop); -} - -/* - * Reset with a Bulk reset. - */ -static int ub_sync_reset(struct ub_dev *sc) -{ - int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int rc; - - init_completion(&compl); - - cr = &sc->work_cr; - cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - cr->bRequest = US_BULK_RESET_REQUEST; - cr->wValue = cpu_to_le16(0); - cr->wIndex = cpu_to_le16(ifnum); - cr->wLength = cpu_to_le16(0); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { - printk(KERN_WARNING - "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc); - return rc; - } - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - return sc->work_urb.status; -} - -/* - * Get number of LUNs by the way of Bulk GetMaxLUN command. - */ -static int ub_sync_getmaxlun(struct ub_dev *sc) -{ - int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber; - unsigned char *p; - enum { ALLOC_SIZE = 1 }; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int nluns; - int rc; - - init_completion(&compl); - - rc = -ENOMEM; - if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) - goto err_alloc; - *p = 55; - - cr = &sc->work_cr; - cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - cr->bRequest = US_BULK_GET_MAX_LUN; - cr->wValue = cpu_to_le16(0); - cr->wIndex = cpu_to_le16(ifnum); - cr->wLength = cpu_to_le16(1); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe, - (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) - goto err_submit; - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - if ((rc = sc->work_urb.status) < 0) - goto err_io; - - if (sc->work_urb.actual_length != 1) { - nluns = 0; - } else { - if ((nluns = *p) == 55) { - nluns = 0; - } else { - /* GetMaxLUN returns the maximum LUN number */ - nluns += 1; - if (nluns > UB_MAX_LUNS) - nluns = UB_MAX_LUNS; - } - } - - kfree(p); - return nluns; - -err_io: -err_submit: - kfree(p); -err_alloc: - return rc; -} - -/* - * Clear initial stalls. - */ -static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) -{ - int endp; - struct usb_ctrlrequest *cr; - struct completion compl; - struct timer_list timer; - int rc; - - init_completion(&compl); - - endp = usb_pipeendpoint(stalled_pipe); - if (usb_pipein (stalled_pipe)) - endp |= USB_DIR_IN; - - cr = &sc->work_cr; - cr->bRequestType = USB_RECIP_ENDPOINT; - cr->bRequest = USB_REQ_CLEAR_FEATURE; - cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); - cr->wIndex = cpu_to_le16(endp); - cr->wLength = cpu_to_le16(0); - - usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, - (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { - printk(KERN_WARNING - "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); - return rc; - } - - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - - wait_for_completion(&compl); - - del_timer_sync(&timer); - usb_kill_urb(&sc->work_urb); - - usb_reset_endpoint(sc->dev, endp); - - return 0; -} - -/* - * Get the pipe settings. - */ -static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, - struct usb_interface *intf) -{ - struct usb_host_interface *altsetting = intf->cur_altsetting; - struct usb_endpoint_descriptor *ep_in = NULL; - struct usb_endpoint_descriptor *ep_out = NULL; - struct usb_endpoint_descriptor *ep; - int i; - - /* - * Find the endpoints we need. - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * We will ignore any others. - */ - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - ep = &altsetting->endpoint[i].desc; - - /* Is it a BULK endpoint? */ - if (usb_endpoint_xfer_bulk(ep)) { - /* BULK in or out? */ - if (usb_endpoint_dir_in(ep)) { - if (ep_in == NULL) - ep_in = ep; - } else { - if (ep_out == NULL) - ep_out = ep; - } - } - } - - if (ep_in == NULL || ep_out == NULL) { - printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name); - return -ENODEV; - } - - /* Calculate and store the pipe values */ - sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0); - sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0); - sc->send_bulk_pipe = usb_sndbulkpipe(dev, - usb_endpoint_num(ep_out)); - sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, - usb_endpoint_num(ep_in)); - - return 0; -} - -/* - * Probing is done in the process context, which allows us to cheat - * and not to build a state machine for the discovery. - */ -static int ub_probe(struct usb_interface *intf, - const struct usb_device_id *dev_id) -{ - struct ub_dev *sc; - int nluns; - int rc; - int i; - - if (usb_usual_check_type(dev_id, USB_US_TYPE_UB)) - return -ENXIO; - - rc = -ENOMEM; - if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL) - goto err_core; - sc->lock = ub_next_lock(); - INIT_LIST_HEAD(&sc->luns); - usb_init_urb(&sc->work_urb); - tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); - atomic_set(&sc->poison, 0); - INIT_WORK(&sc->reset_work, ub_reset_task); - init_waitqueue_head(&sc->reset_wait); - - init_timer(&sc->work_timer); - sc->work_timer.data = (unsigned long) sc; - sc->work_timer.function = ub_urb_timeout; - - ub_init_completion(&sc->work_done); - sc->work_done.done = 1; /* A little yuk, but oh well... */ - - sc->dev = interface_to_usbdev(intf); - sc->intf = intf; - // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usb_set_intfdata(intf, sc); - usb_get_dev(sc->dev); - /* - * Since we give the interface struct to the block level through - * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent - * oopses on close after a disconnect (kernels 2.6.16 and up). - */ - usb_get_intf(sc->intf); - - snprintf(sc->name, 12, DRV_NAME "(%d.%d)", - sc->dev->bus->busnum, sc->dev->devnum); - - /* XXX Verify that we can handle the device (from descriptors) */ - - if (ub_get_pipes(sc, sc->dev, intf) != 0) - goto err_dev_desc; - - /* - * At this point, all USB initialization is done, do upper layer. - * We really hate halfway initialized structures, so from the - * invariants perspective, this ub_dev is fully constructed at - * this point. - */ - - /* - * This is needed to clear toggles. It is a problem only if we do - * `rmmod ub && modprobe ub` without disconnects, but we like that. - */ -#if 0 /* iPod Mini fails if we do this (big white iPod works) */ - ub_probe_clear_stall(sc, sc->recv_bulk_pipe); - ub_probe_clear_stall(sc, sc->send_bulk_pipe); -#endif - - /* - * The way this is used by the startup code is a little specific. - * A SCSI check causes a USB stall. Our common case code sees it - * and clears the check, after which the device is ready for use. - * But if a check was not present, any command other than - * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE). - * - * If we neglect to clear the SCSI check, the first real command fails - * (which is the capacity readout). We clear that and retry, but why - * causing spurious retries for no reason. - * - * Revalidation may start with its own TEST_UNIT_READY, but that one - * has to succeed, so we clear checks with an additional one here. - * In any case it's not our business how revaliadation is implemented. - */ - for (i = 0; i < 3; i++) { /* Retries for the schwag key from KS'04 */ - if ((rc = ub_sync_tur(sc, NULL)) <= 0) break; - if (rc != 0x6) break; - msleep(10); - } - - nluns = 1; - for (i = 0; i < 3; i++) { - if ((rc = ub_sync_getmaxlun(sc)) < 0) - break; - if (rc != 0) { - nluns = rc; - break; - } - msleep(100); - } - - for (i = 0; i < nluns; i++) { - ub_probe_lun(sc, i); - } - return 0; - -err_dev_desc: - usb_set_intfdata(intf, NULL); - usb_put_intf(sc->intf); - usb_put_dev(sc->dev); - kfree(sc); -err_core: - return rc; -} - -static int ub_probe_lun(struct ub_dev *sc, int lnum) -{ - struct ub_lun *lun; - struct request_queue *q; - struct gendisk *disk; - int rc; - - rc = -ENOMEM; - if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL) - goto err_alloc; - lun->num = lnum; - - rc = -ENOSR; - if ((lun->id = ub_id_get()) == -1) - goto err_id; - - lun->udev = sc; - - snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)", - lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num); - - lun->removable = 1; /* XXX Query this from the device */ - lun->changed = 1; /* ub_revalidate clears only */ - ub_revalidate(sc, lun); - - rc = -ENOMEM; - if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL) - goto err_diskalloc; - - sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); - disk->major = UB_MAJOR; - disk->first_minor = lun->id * UB_PARTS_PER_LUN; - disk->fops = &ub_bd_fops; - disk->private_data = lun; - disk->driverfs_dev = &sc->intf->dev; - - rc = -ENOMEM; - if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL) - goto err_blkqinit; - - disk->queue = q; - - blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); - blk_queue_max_segments(q, UB_MAX_REQ_SG); - blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */ - blk_queue_max_hw_sectors(q, UB_MAX_SECTORS); - blk_queue_logical_block_size(q, lun->capacity.bsize); - - lun->disk = disk; - q->queuedata = lun; - list_add(&lun->link, &sc->luns); - - set_capacity(disk, lun->capacity.nsec); - if (lun->removable) - disk->flags |= GENHD_FL_REMOVABLE; - - add_disk(disk); - - return 0; - -err_blkqinit: - put_disk(disk); -err_diskalloc: - ub_id_put(lun->id); -err_id: - kfree(lun); -err_alloc: - return rc; -} - -static void ub_disconnect(struct usb_interface *intf) -{ - struct ub_dev *sc = usb_get_intfdata(intf); - struct ub_lun *lun; - unsigned long flags; - - /* - * Prevent ub_bd_release from pulling the rug from under us. - * XXX This is starting to look like a kref. - * XXX Why not to take this ref at probe time? - */ - spin_lock_irqsave(&ub_lock, flags); - sc->openc++; - spin_unlock_irqrestore(&ub_lock, flags); - - /* - * Fence stall clearings, operations triggered by unlinkings and so on. - * We do not attempt to unlink any URBs, because we do not trust the - * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. - */ - atomic_set(&sc->poison, 1); - - /* - * Wait for reset to end, if any. - */ - wait_event(sc->reset_wait, !sc->reset); - - /* - * Blow away queued commands. - * - * Actually, this never works, because before we get here - * the HCD terminates outstanding URB(s). It causes our - * SCSI command queue to advance, commands fail to submit, - * and the whole queue drains. So, we just use this code to - * print warnings. - */ - spin_lock_irqsave(sc->lock, flags); - { - struct ub_scsi_cmd *cmd; - int cnt = 0; - while ((cmd = ub_cmdq_peek(sc)) != NULL) { - cmd->error = -ENOTCONN; - cmd->state = UB_CMDST_DONE; - ub_cmdq_pop(sc); - (*cmd->done)(sc, cmd); - cnt++; - } - if (cnt != 0) { - printk(KERN_WARNING "%s: " - "%d was queued after shutdown\n", sc->name, cnt); - } - } - spin_unlock_irqrestore(sc->lock, flags); - - /* - * Unregister the upper layer. - */ - list_for_each_entry(lun, &sc->luns, link) { - del_gendisk(lun->disk); - /* - * I wish I could do: - * queue_flag_set(QUEUE_FLAG_DEAD, q); - * As it is, we rely on our internal poisoning and let - * the upper levels to spin furiously failing all the I/O. - */ - } - - /* - * Testing for -EINPROGRESS is always a bug, so we are bending - * the rules a little. - */ - spin_lock_irqsave(sc->lock, flags); - if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */ - printk(KERN_WARNING "%s: " - "URB is active after disconnect\n", sc->name); - } - spin_unlock_irqrestore(sc->lock, flags); - - /* - * There is virtually no chance that other CPU runs a timeout so long - * after ub_urb_complete should have called del_timer, but only if HCD - * didn't forget to deliver a callback on unlink. - */ - del_timer_sync(&sc->work_timer); - - /* - * At this point there must be no commands coming from anyone - * and no URBs left in transit. - */ - - ub_put(sc); -} - -static struct usb_driver ub_driver = { - .name = "ub", - .probe = ub_probe, - .disconnect = ub_disconnect, - .id_table = ub_usb_ids, - .pre_reset = ub_pre_reset, - .post_reset = ub_post_reset, -}; - -static int __init ub_init(void) -{ - int rc; - int i; - - pr_info("'Low Performance USB Block' driver is deprecated. " - "Please switch to usb-storage\n"); - for (i = 0; i < UB_QLOCK_NUM; i++) - spin_lock_init(&ub_qlockv[i]); - - if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) - goto err_regblkdev; - - if ((rc = usb_register(&ub_driver)) != 0) - goto err_register; - - usb_usual_set_present(USB_US_TYPE_UB); - return 0; - -err_register: - unregister_blkdev(UB_MAJOR, DRV_NAME); -err_regblkdev: - return rc; -} - -static void __exit ub_exit(void) -{ - usb_deregister(&ub_driver); - - unregister_blkdev(UB_MAJOR, DRV_NAME); - usb_usual_clear_present(USB_US_TYPE_UB); -} - -module_init(ub_init); -module_exit(ub_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig index 8598111..8997a8c 100644 --- a/drivers/staging/ccg/Kconfig +++ b/drivers/staging/ccg/Kconfig @@ -17,4 +17,9 @@ config USB_G_CCG Configurable Composite Gadget can be compiled "M" only or not at all. + BIG FAT NOTE: DON'T RELY ON THIS USERINTERFACE HERE! AS PART + OF THE REWORK DONE HERE WILL BE A NEW USER INTERFACE WITHOUT ANY + COMPATIBILITY TO THIS SYSFS INTERFACE HERE. BE AWARE OF THIS + BEFORE SELECTING THIS. + endif # USB_GADGET diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile index 693da63..814fa9d 100644 --- a/drivers/staging/ccg/Makefile +++ b/drivers/staging/ccg/Makefile @@ -1,4 +1,2 @@ g_ccg-y := ccg.o -ccflags-y += -Idrivers/usb/gadget - obj-$(CONFIG_USB_G_CCG) += g_ccg.o diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c index 3fbb300..93e1e2f 100644 --- a/drivers/staging/ccg/ccg.c +++ b/drivers/staging/ccg/ccg.c @@ -32,7 +32,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> -#include <linux/usb/composite.h> +#include "composite.h" #include <linux/usb/gadget.h> #include "gadget_chips.h" @@ -44,19 +44,19 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "../../usb/gadget/usbstring.c" -#include "../../usb/gadget/config.c" -#include "../../usb/gadget/epautoconf.c" -#include "../../usb/gadget/composite.c" - -#include "../../usb/gadget/f_mass_storage.c" -#include "../../usb/gadget/u_serial.c" -#include "../../usb/gadget/f_acm.c" +#include "usbstring.c" +#include "config.c" +#include "epautoconf.c" +#include "composite.c" + +#include "f_mass_storage.c" +#include "u_serial.c" +#include "f_acm.c" #define USB_ETH_RNDIS y -#include "../../usb/gadget/f_rndis.c" -#include "../../usb/gadget/rndis.c" -#include "../../usb/gadget/u_ether.c" -#include "../../usb/gadget/f_fs.c" +#include "f_rndis.c" +#include "rndis.c" +#include "u_ether.c" +#include "f_fs.c" MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz"); MODULE_DESCRIPTION("Configurable Composite USB Gadget"); @@ -1156,6 +1156,7 @@ static int ccg_usb_unbind(struct usb_composite_dev *cdev) static struct usb_composite_driver ccg_usb_driver = { .name = "configurable_usb", .dev = &device_desc, + .bind = ccg_bind, .unbind = ccg_usb_unbind, .needs_serial = true, .iManufacturer = "Linux Foundation", @@ -1271,7 +1272,7 @@ static int __init init(void) composite_driver.setup = ccg_setup; composite_driver.disconnect = ccg_disconnect; - err = usb_composite_probe(&ccg_usb_driver, ccg_bind); + err = usb_composite_probe(&ccg_usb_driver); if (err) { class_destroy(ccg_class); kfree(dev); diff --git a/drivers/staging/ccg/composite.c b/drivers/staging/ccg/composite.c new file mode 100644 index 0000000..228b457 --- /dev/null +++ b/drivers/staging/ccg/composite.c @@ -0,0 +1,1688 @@ +/* + * composite.c - infrastructure for Composite USB Gadgets + * + * Copyright (C) 2006-2008 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* #define VERBOSE_DEBUG */ + +#include <linux/kallsyms.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/utsname.h> + +#include <linux/usb/composite.h> +#include <asm/unaligned.h> + +/* + * The code in this file is utility code, used to build a gadget driver + * from one or more "function" drivers, one or more "configuration" + * objects, and a "usb_composite_driver" by gluing them together along + * with the relevant device-wide data. + */ + +/* big enough to hold our biggest descriptor */ +#define USB_BUFSIZ 1024 + +static struct usb_composite_driver *composite; + +/* Some systems will need runtime overrides for the product identifiers + * published in the device descriptor, either numbers or strings or both. + * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). + */ + +static ushort idVendor; +module_param(idVendor, ushort, 0644); +MODULE_PARM_DESC(idVendor, "USB Vendor ID"); + +static ushort idProduct; +module_param(idProduct, ushort, 0644); +MODULE_PARM_DESC(idProduct, "USB Product ID"); + +static ushort bcdDevice; +module_param(bcdDevice, ushort, 0644); +MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); + +static char *iManufacturer; +module_param(iManufacturer, charp, 0644); +MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); + +static char *iProduct; +module_param(iProduct, charp, 0644); +MODULE_PARM_DESC(iProduct, "USB Product string"); + +static char *iSerialNumber; +module_param(iSerialNumber, charp, 0644); +MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); + +static char composite_manufacturer[50]; + +/*-------------------------------------------------------------------------*/ +/** + * next_ep_desc() - advance to the next EP descriptor + * @t: currect pointer within descriptor array + * + * Return: next EP descriptor or NULL + * + * Iterate over @t until either EP descriptor found or + * NULL (that indicates end of list) encountered + */ +static struct usb_descriptor_header** +next_ep_desc(struct usb_descriptor_header **t) +{ + for (; *t; t++) { + if ((*t)->bDescriptorType == USB_DT_ENDPOINT) + return t; + } + return NULL; +} + +/* + * for_each_ep_desc()- iterate over endpoint descriptors in the + * descriptors list + * @start: pointer within descriptor array. + * @ep_desc: endpoint descriptor to use as the loop cursor + */ +#define for_each_ep_desc(start, ep_desc) \ + for (ep_desc = next_ep_desc(start); \ + ep_desc; ep_desc = next_ep_desc(ep_desc+1)) + +/** + * config_ep_by_speed() - configures the given endpoint + * according to gadget speed. + * @g: pointer to the gadget + * @f: usb function + * @_ep: the endpoint to configure + * + * Return: error code, 0 on success + * + * This function chooses the right descriptors for a given + * endpoint according to gadget speed and saves it in the + * endpoint desc field. If the endpoint already has a descriptor + * assigned to it - overwrites it with currently corresponding + * descriptor. The endpoint maxpacket field is updated according + * to the chosen descriptor. + * Note: the supplied function should hold all the descriptors + * for supported speeds + */ +int config_ep_by_speed(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep) +{ + struct usb_composite_dev *cdev = get_gadget_data(g); + struct usb_endpoint_descriptor *chosen_desc = NULL; + struct usb_descriptor_header **speed_desc = NULL; + + struct usb_ss_ep_comp_descriptor *comp_desc = NULL; + int want_comp_desc = 0; + + struct usb_descriptor_header **d_spd; /* cursor for speed desc */ + + if (!g || !f || !_ep) + return -EIO; + + /* select desired speed */ + switch (g->speed) { + case USB_SPEED_SUPER: + if (gadget_is_superspeed(g)) { + speed_desc = f->ss_descriptors; + want_comp_desc = 1; + break; + } + /* else: Fall trough */ + case USB_SPEED_HIGH: + if (gadget_is_dualspeed(g)) { + speed_desc = f->hs_descriptors; + break; + } + /* else: fall through */ + default: + speed_desc = f->descriptors; + } + /* find descriptors */ + for_each_ep_desc(speed_desc, d_spd) { + chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; + if (chosen_desc->bEndpointAddress == _ep->address) + goto ep_found; + } + return -EIO; + +ep_found: + /* commit results */ + _ep->maxpacket = usb_endpoint_maxp(chosen_desc); + _ep->desc = chosen_desc; + _ep->comp_desc = NULL; + _ep->maxburst = 0; + _ep->mult = 0; + if (!want_comp_desc) + return 0; + + /* + * Companion descriptor should follow EP descriptor + * USB 3.0 spec, #9.6.7 + */ + comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); + if (!comp_desc || + (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) + return -EIO; + _ep->comp_desc = comp_desc; + if (g->speed == USB_SPEED_SUPER) { + switch (usb_endpoint_type(_ep->desc)) { + case USB_ENDPOINT_XFER_ISOC: + /* mult: bits 1:0 of bmAttributes */ + _ep->mult = comp_desc->bmAttributes & 0x3; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + _ep->maxburst = comp_desc->bMaxBurst + 1; + break; + default: + if (comp_desc->bMaxBurst != 0) + ERROR(cdev, "ep0 bMaxBurst must be 0\n"); + _ep->maxburst = 1; + break; + } + } + return 0; +} + +/** + * usb_add_function() - add a function to a configuration + * @config: the configuration + * @function: the function being added + * Context: single threaded during gadget setup + * + * After initialization, each configuration must have one or more + * functions added to it. Adding a function involves calling its @bind() + * method to allocate resources such as interface and string identifiers + * and endpoints. + * + * This function returns the value of the function's bind(), which is + * zero for success else a negative errno value. + */ +int usb_add_function(struct usb_configuration *config, + struct usb_function *function) +{ + int value = -EINVAL; + + DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", + function->name, function, + config->label, config); + + if (!function->set_alt || !function->disable) + goto done; + + function->config = config; + list_add_tail(&function->list, &config->functions); + + /* REVISIT *require* function->bind? */ + if (function->bind) { + value = function->bind(config, function); + if (value < 0) { + list_del(&function->list); + function->config = NULL; + } + } else + value = 0; + + /* We allow configurations that don't work at both speeds. + * If we run into a lowspeed Linux system, treat it the same + * as full speed ... it's the function drivers that will need + * to avoid bulk and ISO transfers. + */ + if (!config->fullspeed && function->descriptors) + config->fullspeed = true; + if (!config->highspeed && function->hs_descriptors) + config->highspeed = true; + if (!config->superspeed && function->ss_descriptors) + config->superspeed = true; + +done: + if (value) + DBG(config->cdev, "adding '%s'/%p --> %d\n", + function->name, function, value); + return value; +} + +/** + * usb_function_deactivate - prevent function and gadget enumeration + * @function: the function that isn't yet ready to respond + * + * Blocks response of the gadget driver to host enumeration by + * preventing the data line pullup from being activated. This is + * normally called during @bind() processing to change from the + * initial "ready to respond" state, or when a required resource + * becomes available. + * + * For example, drivers that serve as a passthrough to a userspace + * daemon can block enumeration unless that daemon (such as an OBEX, + * MTP, or print server) is ready to handle host requests. + * + * Not all systems support software control of their USB peripheral + * data pullups. + * + * Returns zero on success, else negative errno. + */ +int usb_function_deactivate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + unsigned long flags; + int status = 0; + + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->deactivations == 0) + status = usb_gadget_disconnect(cdev->gadget); + if (status == 0) + cdev->deactivations++; + + spin_unlock_irqrestore(&cdev->lock, flags); + return status; +} + +/** + * usb_function_activate - allow function and gadget enumeration + * @function: function on which usb_function_activate() was called + * + * Reverses effect of usb_function_deactivate(). If no more functions + * are delaying their activation, the gadget driver will respond to + * host enumeration procedures. + * + * Returns zero on success, else negative errno. + */ +int usb_function_activate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + unsigned long flags; + int status = 0; + + spin_lock_irqsave(&cdev->lock, flags); + + if (WARN_ON(cdev->deactivations == 0)) + status = -EINVAL; + else { + cdev->deactivations--; + if (cdev->deactivations == 0) + status = usb_gadget_connect(cdev->gadget); + } + + spin_unlock_irqrestore(&cdev->lock, flags); + return status; +} + +/** + * usb_interface_id() - allocate an unused interface ID + * @config: configuration associated with the interface + * @function: function handling the interface + * Context: single threaded during gadget setup + * + * usb_interface_id() is called from usb_function.bind() callbacks to + * allocate new interface IDs. The function driver will then store that + * ID in interface, association, CDC union, and other descriptors. It + * will also handle any control requests targeted at that interface, + * particularly changing its altsetting via set_alt(). There may + * also be class-specific or vendor-specific requests to handle. + * + * All interface identifier should be allocated using this routine, to + * ensure that for example different functions don't wrongly assign + * different meanings to the same identifier. Note that since interface + * identifiers are configuration-specific, functions used in more than + * one configuration (or more than once in a given configuration) need + * multiple versions of the relevant descriptors. + * + * Returns the interface ID which was allocated; or -ENODEV if no + * more interface IDs can be allocated. + */ +int usb_interface_id(struct usb_configuration *config, + struct usb_function *function) +{ + unsigned id = config->next_interface_id; + + if (id < MAX_CONFIG_INTERFACES) { + config->interface[id] = function; + config->next_interface_id = id + 1; + return id; + } + return -ENODEV; +} + +static int config_buf(struct usb_configuration *config, + enum usb_device_speed speed, void *buf, u8 type) +{ + struct usb_config_descriptor *c = buf; + void *next = buf + USB_DT_CONFIG_SIZE; + int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; + struct usb_function *f; + int status; + + /* write the config descriptor */ + c = buf; + c->bLength = USB_DT_CONFIG_SIZE; + c->bDescriptorType = type; + /* wTotalLength is written later */ + c->bNumInterfaces = config->next_interface_id; + c->bConfigurationValue = config->bConfigurationValue; + c->iConfiguration = config->iConfiguration; + c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; + c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); + + /* There may be e.g. OTG descriptors */ + if (config->descriptors) { + status = usb_descriptor_fillbuf(next, len, + config->descriptors); + if (status < 0) + return status; + len -= status; + next += status; + } + + /* add each function's descriptors */ + list_for_each_entry(f, &config->functions, list) { + struct usb_descriptor_header **descriptors; + + switch (speed) { + case USB_SPEED_SUPER: + descriptors = f->ss_descriptors; + break; + case USB_SPEED_HIGH: + descriptors = f->hs_descriptors; + break; + default: + descriptors = f->descriptors; + } + + if (!descriptors) + continue; + status = usb_descriptor_fillbuf(next, len, + (const struct usb_descriptor_header **) descriptors); + if (status < 0) + return status; + len -= status; + next += status; + } + + len = next - buf; + c->wTotalLength = cpu_to_le16(len); + return len; +} + +static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) +{ + struct usb_gadget *gadget = cdev->gadget; + struct usb_configuration *c; + u8 type = w_value >> 8; + enum usb_device_speed speed = USB_SPEED_UNKNOWN; + + if (gadget->speed == USB_SPEED_SUPER) + speed = gadget->speed; + else if (gadget_is_dualspeed(gadget)) { + int hs = 0; + if (gadget->speed == USB_SPEED_HIGH) + hs = 1; + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + if (hs) + speed = USB_SPEED_HIGH; + + } + + /* This is a lookup by config *INDEX* */ + w_value &= 0xff; + list_for_each_entry(c, &cdev->configs, list) { + /* ignore configs that won't work at this speed */ + switch (speed) { + case USB_SPEED_SUPER: + if (!c->superspeed) + continue; + break; + case USB_SPEED_HIGH: + if (!c->highspeed) + continue; + break; + default: + if (!c->fullspeed) + continue; + } + + if (w_value == 0) + return config_buf(c, speed, cdev->req->buf, type); + w_value--; + } + return -EINVAL; +} + +static int count_configs(struct usb_composite_dev *cdev, unsigned type) +{ + struct usb_gadget *gadget = cdev->gadget; + struct usb_configuration *c; + unsigned count = 0; + int hs = 0; + int ss = 0; + + if (gadget_is_dualspeed(gadget)) { + if (gadget->speed == USB_SPEED_HIGH) + hs = 1; + if (gadget->speed == USB_SPEED_SUPER) + ss = 1; + if (type == USB_DT_DEVICE_QUALIFIER) + hs = !hs; + } + list_for_each_entry(c, &cdev->configs, list) { + /* ignore configs that won't work at this speed */ + if (ss) { + if (!c->superspeed) + continue; + } else if (hs) { + if (!c->highspeed) + continue; + } else { + if (!c->fullspeed) + continue; + } + count++; + } + return count; +} + +/** + * bos_desc() - prepares the BOS descriptor. + * @cdev: pointer to usb_composite device to generate the bos + * descriptor for + * + * This function generates the BOS (Binary Device Object) + * descriptor and its device capabilities descriptors. The BOS + * descriptor should be supported by a SuperSpeed device. + */ +static int bos_desc(struct usb_composite_dev *cdev) +{ + struct usb_ext_cap_descriptor *usb_ext; + struct usb_ss_cap_descriptor *ss_cap; + struct usb_dcd_config_params dcd_config_params; + struct usb_bos_descriptor *bos = cdev->req->buf; + + bos->bLength = USB_DT_BOS_SIZE; + bos->bDescriptorType = USB_DT_BOS; + + bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); + bos->bNumDeviceCaps = 0; + + /* + * A SuperSpeed device shall include the USB2.0 extension descriptor + * and shall support LPM when operating in USB2.0 HS mode. + */ + usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); + usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; + usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); + + /* + * The Superspeed USB Capability descriptor shall be implemented by all + * SuperSpeed devices. + */ + ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); + ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; + ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; + ss_cap->bmAttributes = 0; /* LTM is not supported yet */ + ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | + USB_FULL_SPEED_OPERATION | + USB_HIGH_SPEED_OPERATION | + USB_5GBPS_OPERATION); + ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + + /* Get Controller configuration */ + if (cdev->gadget->ops->get_config_params) + cdev->gadget->ops->get_config_params(&dcd_config_params); + else { + dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; + dcd_config_params.bU2DevExitLat = + cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); + } + ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; + ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; + + return le16_to_cpu(bos->wTotalLength); +} + +static void device_qual(struct usb_composite_dev *cdev) +{ + struct usb_qualifier_descriptor *qual = cdev->req->buf; + + qual->bLength = sizeof(*qual); + qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; + /* POLICY: same bcdUSB and device type info at both speeds */ + qual->bcdUSB = cdev->desc.bcdUSB; + qual->bDeviceClass = cdev->desc.bDeviceClass; + qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; + qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; + /* ASSUME same EP0 fifo size at both speeds */ + qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; + qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); + qual->bRESERVED = 0; +} + +/*-------------------------------------------------------------------------*/ + +static void reset_config(struct usb_composite_dev *cdev) +{ + struct usb_function *f; + + DBG(cdev, "reset config\n"); + + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->disable) + f->disable(f); + + bitmap_zero(f->endpoints, 32); + } + cdev->config = NULL; +} + +static int set_config(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl, unsigned number) +{ + struct usb_gadget *gadget = cdev->gadget; + struct usb_configuration *c = NULL; + int result = -EINVAL; + unsigned power = gadget_is_otg(gadget) ? 8 : 100; + int tmp; + + if (number) { + list_for_each_entry(c, &cdev->configs, list) { + if (c->bConfigurationValue == number) { + /* + * We disable the FDs of the previous + * configuration only if the new configuration + * is a valid one + */ + if (cdev->config) + reset_config(cdev); + result = 0; + break; + } + } + if (result < 0) + goto done; + } else { /* Zero configuration value - need to reset the config */ + if (cdev->config) + reset_config(cdev); + result = 0; + } + + INFO(cdev, "%s config #%d: %s\n", + usb_speed_string(gadget->speed), + number, c ? c->label : "unconfigured"); + + if (!c) + goto done; + + cdev->config = c; + + /* Initialize all interfaces by setting them to altsetting zero. */ + for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { + struct usb_function *f = c->interface[tmp]; + struct usb_descriptor_header **descriptors; + + if (!f) + break; + + /* + * Record which endpoints are used by the function. This is used + * to dispatch control requests targeted at that endpoint to the + * function's setup callback instead of the current + * configuration's setup callback. + */ + switch (gadget->speed) { + case USB_SPEED_SUPER: + descriptors = f->ss_descriptors; + break; + case USB_SPEED_HIGH: + descriptors = f->hs_descriptors; + break; + default: + descriptors = f->descriptors; + } + + for (; *descriptors; ++descriptors) { + struct usb_endpoint_descriptor *ep; + int addr; + + if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) + continue; + + ep = (struct usb_endpoint_descriptor *)*descriptors; + addr = ((ep->bEndpointAddress & 0x80) >> 3) + | (ep->bEndpointAddress & 0x0f); + set_bit(addr, f->endpoints); + } + + result = f->set_alt(f, tmp, 0); + if (result < 0) { + DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", + tmp, f->name, f, result); + + reset_config(cdev); + goto done; + } + + if (result == USB_GADGET_DELAYED_STATUS) { + DBG(cdev, + "%s: interface %d (%s) requested delayed status\n", + __func__, tmp, f->name); + cdev->delayed_status++; + DBG(cdev, "delayed_status count %d\n", + cdev->delayed_status); + } + } + + /* when we return, be sure our power usage is valid */ + power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; +done: + usb_gadget_vbus_draw(gadget, power); + if (result >= 0 && cdev->delayed_status) + result = USB_GADGET_DELAYED_STATUS; + return result; +} + +/** + * usb_add_config() - add a configuration to a device. + * @cdev: wraps the USB gadget + * @config: the configuration, with bConfigurationValue assigned + * @bind: the configuration's bind function + * Context: single threaded during gadget setup + * + * One of the main tasks of a composite @bind() routine is to + * add each of the configurations it supports, using this routine. + * + * This function returns the value of the configuration's @bind(), which + * is zero for success else a negative errno value. Binding configurations + * assigns global resources including string IDs, and per-configuration + * resources such as interface IDs and endpoints. + */ +int usb_add_config(struct usb_composite_dev *cdev, + struct usb_configuration *config, + int (*bind)(struct usb_configuration *)) +{ + int status = -EINVAL; + struct usb_configuration *c; + + DBG(cdev, "adding config #%u '%s'/%p\n", + config->bConfigurationValue, + config->label, config); + + if (!config->bConfigurationValue || !bind) + goto done; + + /* Prevent duplicate configuration identifiers */ + list_for_each_entry(c, &cdev->configs, list) { + if (c->bConfigurationValue == config->bConfigurationValue) { + status = -EBUSY; + goto done; + } + } + + config->cdev = cdev; + list_add_tail(&config->list, &cdev->configs); + + INIT_LIST_HEAD(&config->functions); + config->next_interface_id = 0; + memset(config->interface, 0, sizeof(config->interface)); + + status = bind(config); + if (status < 0) { + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", + f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } + list_del(&config->list); + config->cdev = NULL; + } else { + unsigned i; + + DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", + config->bConfigurationValue, config, + config->superspeed ? " super" : "", + config->highspeed ? " high" : "", + config->fullspeed + ? (gadget_is_dualspeed(cdev->gadget) + ? " full" + : " full/low") + : ""); + + for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { + struct usb_function *f = config->interface[i]; + + if (!f) + continue; + DBG(cdev, " interface %d = %s/%p\n", + i, f->name, f); + } + } + + /* set_alt(), or next bind(), sets up + * ep->driver_data as needed. + */ + usb_ep_autoconfig_reset(cdev->gadget); + +done: + if (status) + DBG(cdev, "added config '%s'/%u --> %d\n", config->label, + config->bConfigurationValue, status); + return status; +} + +static void remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } + list_del(&config->list); + if (config->unbind) { + DBG(cdev, "unbind config '%s'/%p\n", config->label, config); + config->unbind(config); + /* may free memory for "c" */ + } +} + +/** + * usb_remove_config() - remove a configuration from a device. + * @cdev: wraps the USB gadget + * @config: the configuration + * + * Drivers must call usb_gadget_disconnect before calling this function + * to disconnect the device from the host and make sure the host will not + * try to enumerate the device while we are changing the config list. + */ +void usb_remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->config == config) + reset_config(cdev); + + spin_unlock_irqrestore(&cdev->lock, flags); + + remove_config(cdev, config); +} + +/*-------------------------------------------------------------------------*/ + +/* We support strings in multiple languages ... string descriptor zero + * says which languages are supported. The typical case will be that + * only one language (probably English) is used, with I18N handled on + * the host side. + */ + +static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) +{ + const struct usb_gadget_strings *s; + __le16 language; + __le16 *tmp; + + while (*sp) { + s = *sp; + language = cpu_to_le16(s->language); + for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { + if (*tmp == language) + goto repeat; + } + *tmp++ = language; +repeat: + sp++; + } +} + +static int lookup_string( + struct usb_gadget_strings **sp, + void *buf, + u16 language, + int id +) +{ + struct usb_gadget_strings *s; + int value; + + while (*sp) { + s = *sp++; + if (s->language != language) + continue; + value = usb_gadget_get_string(s, id, buf); + if (value > 0) + return value; + } + return -EINVAL; +} + +static int get_string(struct usb_composite_dev *cdev, + void *buf, u16 language, int id) +{ + struct usb_configuration *c; + struct usb_function *f; + int len; + const char *str; + + /* Yes, not only is USB's I18N support probably more than most + * folk will ever care about ... also, it's all supported here. + * (Except for UTF8 support for Unicode's "Astral Planes".) + */ + + /* 0 == report all available language codes */ + if (id == 0) { + struct usb_string_descriptor *s = buf; + struct usb_gadget_strings **sp; + + memset(s, 0, 256); + s->bDescriptorType = USB_DT_STRING; + + sp = composite->strings; + if (sp) + collect_langs(sp, s->wData); + + list_for_each_entry(c, &cdev->configs, list) { + sp = c->strings; + if (sp) + collect_langs(sp, s->wData); + + list_for_each_entry(f, &c->functions, list) { + sp = f->strings; + if (sp) + collect_langs(sp, s->wData); + } + } + + for (len = 0; len <= 126 && s->wData[len]; len++) + continue; + if (!len) + return -EINVAL; + + s->bLength = 2 * (len + 1); + return s->bLength; + } + + /* Otherwise, look up and return a specified string. First + * check if the string has not been overridden. + */ + if (cdev->manufacturer_override == id) + str = iManufacturer ?: composite->iManufacturer ?: + composite_manufacturer; + else if (cdev->product_override == id) + str = iProduct ?: composite->iProduct; + else if (cdev->serial_override == id) + str = iSerialNumber ?: composite->iSerialNumber; + else + str = NULL; + if (str) { + struct usb_gadget_strings strings = { + .language = language, + .strings = &(struct usb_string) { 0xff, str } + }; + return usb_gadget_get_string(&strings, 0xff, buf); + } + + /* String IDs are device-scoped, so we look up each string + * table we're told about. These lookups are infrequent; + * simpler-is-better here. + */ + if (composite->strings) { + len = lookup_string(composite->strings, buf, language, id); + if (len > 0) + return len; + } + list_for_each_entry(c, &cdev->configs, list) { + if (c->strings) { + len = lookup_string(c->strings, buf, language, id); + if (len > 0) + return len; + } + list_for_each_entry(f, &c->functions, list) { + if (!f->strings) + continue; + len = lookup_string(f->strings, buf, language, id); + if (len > 0) + return len; + } + } + return -EINVAL; +} + +/** + * usb_string_id() - allocate an unused string ID + * @cdev: the device whose string descriptor IDs are being allocated + * Context: single threaded during gadget setup + * + * @usb_string_id() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then store that ID in the appropriate descriptors and string table. + * + * All string identifier should be allocated using this, + * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure + * that for example different functions don't wrongly assign different + * meanings to the same identifier. + */ +int usb_string_id(struct usb_composite_dev *cdev) +{ + if (cdev->next_string_id < 254) { + /* string id 0 is reserved by USB spec for list of + * supported languages */ + /* 255 reserved as well? -- mina86 */ + cdev->next_string_id++; + return cdev->next_string_id; + } + return -ENODEV; +} + +/** + * usb_string_ids() - allocate unused string IDs in batch + * @cdev: the device whose string descriptor IDs are being allocated + * @str: an array of usb_string objects to assign numbers to + * Context: single threaded during gadget setup + * + * @usb_string_ids() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then copy IDs from the string table to the appropriate descriptors + * and string table for other languages. + * + * All string identifier should be allocated using this, + * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for + * example different functions don't wrongly assign different meanings + * to the same identifier. + */ +int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) +{ + int next = cdev->next_string_id; + + for (; str->s; ++str) { + if (unlikely(next >= 254)) + return -ENODEV; + str->id = ++next; + } + + cdev->next_string_id = next; + + return 0; +} + +/** + * usb_string_ids_n() - allocate unused string IDs in batch + * @c: the device whose string descriptor IDs are being allocated + * @n: number of string IDs to allocate + * Context: single threaded during gadget setup + * + * Returns the first requested ID. This ID and next @n-1 IDs are now + * valid IDs. At least provided that @n is non-zero because if it + * is, returns last requested ID which is now very useful information. + * + * @usb_string_ids_n() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then store that ID in the appropriate descriptors and string table. + * + * All string identifier should be allocated using this, + * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for + * example different functions don't wrongly assign different meanings + * to the same identifier. + */ +int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) +{ + unsigned next = c->next_string_id; + if (unlikely(n > 254 || (unsigned)next + n > 254)) + return -ENODEV; + c->next_string_id += n; + return next + 1; +} + + +/*-------------------------------------------------------------------------*/ + +static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DBG((struct usb_composite_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver(like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config and function specific setup. + */ +static int +composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + int status = 0; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u8 intf = w_index & 0xFF; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + struct usb_function *f = NULL; + u8 endp; + + /* partial re-init of the response message; the function or the + * gadget might need to intercept e.g. a control-OUT completion + * when we delegate to it. + */ + req->zero = 0; + req->complete = composite_setup_complete; + req->length = 0; + gadget->ep0->driver_data = cdev; + + switch (ctrl->bRequest) { + + /* we handle all standard USB descriptors */ + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + goto unknown; + switch (w_value >> 8) { + + case USB_DT_DEVICE: + cdev->desc.bNumConfigurations = + count_configs(cdev, USB_DT_DEVICE); + cdev->desc.bMaxPacketSize0 = + cdev->gadget->ep0->maxpacket; + if (gadget_is_superspeed(gadget)) { + if (gadget->speed >= USB_SPEED_SUPER) { + cdev->desc.bcdUSB = cpu_to_le16(0x0300); + cdev->desc.bMaxPacketSize0 = 9; + } else { + cdev->desc.bcdUSB = cpu_to_le16(0x0210); + } + } + + value = min(w_length, (u16) sizeof cdev->desc); + memcpy(req->buf, &cdev->desc, value); + break; + case USB_DT_DEVICE_QUALIFIER: + if (!gadget_is_dualspeed(gadget) || + gadget->speed >= USB_SPEED_SUPER) + break; + device_qual(cdev); + value = min_t(int, w_length, + sizeof(struct usb_qualifier_descriptor)); + break; + case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget_is_dualspeed(gadget) || + gadget->speed >= USB_SPEED_SUPER) + break; + /* FALLTHROUGH */ + case USB_DT_CONFIG: + value = config_desc(cdev, w_value); + if (value >= 0) + value = min(w_length, (u16) value); + break; + case USB_DT_STRING: + value = get_string(cdev, req->buf, + w_index, w_value & 0xff); + if (value >= 0) + value = min(w_length, (u16) value); + break; + case USB_DT_BOS: + if (gadget_is_superspeed(gadget)) { + value = bos_desc(cdev); + value = min(w_length, (u16) value); + } + break; + } + break; + + /* any number of configs can work */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + goto unknown; + if (gadget_is_otg(gadget)) { + if (gadget->a_hnp_support) + DBG(cdev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DBG(cdev, "HNP on another port\n"); + else + VDBG(cdev, "HNP inactive\n"); + } + spin_lock(&cdev->lock); + value = set_config(cdev, ctrl, w_value); + spin_unlock(&cdev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + goto unknown; + if (cdev->config) + *(u8 *)req->buf = cdev->config->bConfigurationValue; + else + *(u8 *)req->buf = 0; + value = min(w_length, (u16) 1); + break; + + /* function drivers must handle get/set altsetting; if there's + * no get() method, we know only altsetting zero works. + */ + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE) + goto unknown; + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + if (w_value && !f->set_alt) + break; + value = f->set_alt(f, w_index, w_value); + if (value == USB_GADGET_DELAYED_STATUS) { + DBG(cdev, + "%s: interface %d (%s) requested delayed status\n", + __func__, intf, f->name); + cdev->delayed_status++; + DBG(cdev, "delayed_status count %d\n", + cdev->delayed_status); + } + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto unknown; + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + /* lots of interfaces only need altsetting zero... */ + value = f->get_alt ? f->get_alt(f, w_index) : 0; + if (value < 0) + break; + *((u8 *)req->buf) = value; + value = min(w_length, (u16) 1); + break; + + /* + * USB 3.0 additions: + * Function driver should handle get_status request. If such cb + * wasn't supplied we respond with default value = 0 + * Note: function driver should supply such cb only for the first + * interface of the function + */ + case USB_REQ_GET_STATUS: + if (!gadget_is_superspeed(gadget)) + goto unknown; + if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) + goto unknown; + value = 2; /* This is the length of the get_status reply */ + put_unaligned_le16(0, req->buf); + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + status = f->get_status ? f->get_status(f) : 0; + if (status < 0) + break; + put_unaligned_le16(status & 0x0000ffff, req->buf); + break; + /* + * Function drivers should handle SetFeature/ClearFeature + * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied + * only for the first interface of the function + */ + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (!gadget_is_superspeed(gadget)) + goto unknown; + if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) + goto unknown; + switch (w_value) { + case USB_INTRF_FUNC_SUSPEND: + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + value = 0; + if (f->func_suspend) + value = f->func_suspend(f, w_index >> 8); + if (value < 0) { + ERROR(cdev, + "func_suspend() returned error %d\n", + value); + value = 0; + } + break; + } + break; + default: +unknown: + VDBG(cdev, + "non-core control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + + /* functions always handle their interfaces and endpoints... + * punt other recipients (other, WUSB, ...) to the current + * configuration code. + * + * REVISIT it could make sense to let the composite device + * take such requests too, if that's ever needed: to work + * in config 0, etc. + */ + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + break; + + case USB_RECIP_ENDPOINT: + endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); + list_for_each_entry(f, &cdev->config->functions, list) { + if (test_bit(endp, f->endpoints)) + break; + } + if (&f->list == &cdev->config->functions) + f = NULL; + break; + } + + if (f && f->setup) + value = f->setup(f, ctrl); + else { + struct usb_configuration *c; + + c = cdev->config; + if (c && c->setup) + value = c->setup(c, ctrl); + } + + goto done; + } + + /* respond with data transfer before status phase? */ + if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) { + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, req); + } + } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) { + WARN(cdev, + "%s: Delayed status not supported for w_length != 0", + __func__); + } + +done: + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void composite_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + unsigned long flags; + + /* REVISIT: should we have config and device level + * disconnect callbacks? + */ + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config) + reset_config(cdev); + if (composite->disconnect) + composite->disconnect(cdev); + spin_unlock_irqrestore(&cdev->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +static ssize_t composite_show_suspended(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_gadget *gadget = dev_to_usb_gadget(dev); + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + return sprintf(buf, "%d\n", cdev->suspended); +} + +static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); + +static void +composite_unbind(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + /* composite_disconnect() must already have been called + * by the underlying peripheral controller driver! + * so there's no i/o concurrency that could affect the + * state protected by cdev->lock. + */ + WARN_ON(cdev->config); + + while (!list_empty(&cdev->configs)) { + struct usb_configuration *c; + c = list_first_entry(&cdev->configs, + struct usb_configuration, list); + remove_config(cdev, c); + } + if (composite->unbind) + composite->unbind(cdev); + + if (cdev->req) { + kfree(cdev->req->buf); + usb_ep_free_request(gadget->ep0, cdev->req); + } + device_remove_file(&gadget->dev, &dev_attr_suspended); + kfree(cdev); + set_gadget_data(gadget, NULL); + composite = NULL; +} + +static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) +{ + if (!*desc) { + int ret = usb_string_id(cdev); + if (unlikely(ret < 0)) + WARNING(cdev, "failed to override string ID\n"); + else + *desc = ret; + } + + return *desc; +} + +static int composite_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct usb_composite_dev *cdev; + int status = -ENOMEM; + + cdev = kzalloc(sizeof *cdev, GFP_KERNEL); + if (!cdev) + return status; + + spin_lock_init(&cdev->lock); + cdev->gadget = gadget; + set_gadget_data(gadget, cdev); + INIT_LIST_HEAD(&cdev->configs); + + /* preallocate control response and buffer */ + cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); + if (!cdev->req) + goto fail; + cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); + if (!cdev->req->buf) + goto fail; + cdev->req->complete = composite_setup_complete; + gadget->ep0->driver_data = cdev; + + cdev->bufsiz = USB_BUFSIZ; + cdev->driver = composite; + + /* + * As per USB compliance update, a device that is actively drawing + * more than 100mA from USB must report itself as bus-powered in + * the GetStatus(DEVICE) call. + */ + if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_set_selfpowered(gadget); + + /* interface and string IDs start at zero via kzalloc. + * we force endpoints to start unassigned; few controller + * drivers will zero ep->driver_data. + */ + usb_ep_autoconfig_reset(cdev->gadget); + + /* composite gadget needs to assign strings for whole device (like + * serial number), register function drivers, potentially update + * power state and consumption, etc + */ + status = composite->bind(cdev); + if (status < 0) + goto fail; + + cdev->desc = *composite->dev; + + /* standardized runtime overrides for device ID data */ + if (idVendor) + cdev->desc.idVendor = cpu_to_le16(idVendor); + else + idVendor = le16_to_cpu(cdev->desc.idVendor); + if (idProduct) + cdev->desc.idProduct = cpu_to_le16(idProduct); + else + idProduct = le16_to_cpu(cdev->desc.idProduct); + if (bcdDevice) + cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + else + bcdDevice = le16_to_cpu(cdev->desc.bcdDevice); + + /* string overrides */ + if (iManufacturer || !cdev->desc.iManufacturer) { + if (!iManufacturer && !composite->iManufacturer && + !*composite_manufacturer) + snprintf(composite_manufacturer, + sizeof composite_manufacturer, + "%s %s with %s", + init_utsname()->sysname, + init_utsname()->release, + gadget->name); + + cdev->manufacturer_override = + override_id(cdev, &cdev->desc.iManufacturer); + } + + if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) + cdev->product_override = + override_id(cdev, &cdev->desc.iProduct); + + if (iSerialNumber || + (!cdev->desc.iSerialNumber && composite->iSerialNumber)) + cdev->serial_override = + override_id(cdev, &cdev->desc.iSerialNumber); + + /* has userspace failed to provide a serial number? */ + if (composite->needs_serial && !cdev->desc.iSerialNumber) + WARNING(cdev, "userspace failed to provide iSerialNumber\n"); + + /* finish up */ + status = device_create_file(&gadget->dev, &dev_attr_suspended); + if (status) + goto fail; + + INFO(cdev, "%s ready\n", composite->name); + return 0; + +fail: + composite_unbind(gadget); + return status; +} + +/*-------------------------------------------------------------------------*/ + +static void +composite_suspend(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_function *f; + + /* REVISIT: should we have config level + * suspend/resume callbacks? + */ + DBG(cdev, "suspend\n"); + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->suspend) + f->suspend(f); + } + } + if (composite->suspend) + composite->suspend(cdev); + + cdev->suspended = 1; + + usb_gadget_vbus_draw(gadget, 2); +} + +static void +composite_resume(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_function *f; + u8 maxpower; + + /* REVISIT: should we have config level + * suspend/resume callbacks? + */ + DBG(cdev, "resume\n"); + if (composite->resume) + composite->resume(cdev); + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->resume) + f->resume(f); + } + + maxpower = cdev->config->bMaxPower; + + usb_gadget_vbus_draw(gadget, maxpower ? + (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW); + } + + cdev->suspended = 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver composite_driver = { + .bind = composite_bind, + .unbind = composite_unbind, + + .setup = composite_setup, + .disconnect = composite_disconnect, + + .suspend = composite_suspend, + .resume = composite_resume, + + .driver = { + .owner = THIS_MODULE, + }, +}; + +/** + * usb_composite_probe() - register a composite driver + * @driver: the driver to register + * @bind: the callback used to allocate resources that are shared across the + * whole device, such as string IDs, and add its configurations using + * @usb_add_config(). This may fail by returning a negative errno + * value; it should return zero on successful initialization. + * Context: single threaded during gadget setup + * + * This function is used to register drivers using the composite driver + * framework. The return value is zero, or a negative errno value. + * Those values normally come from the driver's @bind method, which does + * all the work of setting up the driver to match the hardware. + * + * On successful return, the gadget is ready to respond to requests from + * the host, unless one of its components invokes usb_gadget_disconnect() + * while it was binding. That would usually be done in order to wait for + * some userspace participation. + */ +int usb_composite_probe(struct usb_composite_driver *driver) +{ + if (!driver || !driver->dev || composite || !driver->bind) + return -EINVAL; + + if (!driver->name) + driver->name = "composite"; + if (!driver->iProduct) + driver->iProduct = driver->name; + composite_driver.function = (char *) driver->name; + composite_driver.driver.name = driver->name; + composite_driver.max_speed = driver->max_speed; + composite = driver; + + return usb_gadget_probe_driver(&composite_driver); +} + +/** + * usb_composite_unregister() - unregister a composite driver + * @driver: the driver to unregister + * + * This function is used to unregister drivers using the composite + * driver framework. + */ +void usb_composite_unregister(struct usb_composite_driver *driver) +{ + if (composite != driver) + return; + usb_gadget_unregister_driver(&composite_driver); +} + +/** + * usb_composite_setup_continue() - Continue with the control transfer + * @cdev: the composite device who's control transfer was kept waiting + * + * This function must be called by the USB function driver to continue + * with the control transfer's data/status stage in case it had requested to + * delay the data/status stages. A USB function's setup handler (e.g. set_alt()) + * can request the composite framework to delay the setup request's data/status + * stages by returning USB_GADGET_DELAYED_STATUS. + */ +void usb_composite_setup_continue(struct usb_composite_dev *cdev) +{ + int value; + struct usb_request *req = cdev->req; + unsigned long flags; + + DBG(cdev, "%s\n", __func__); + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->delayed_status == 0) { + WARN(cdev, "%s: Unexpected call\n", __func__); + + } else if (--cdev->delayed_status == 0) { + DBG(cdev, "%s: Completing delayed status\n", __func__); + req->length = 0; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(cdev->gadget->ep0, req); + } + } + + spin_unlock_irqrestore(&cdev->lock, flags); +} + diff --git a/drivers/staging/ccg/composite.h b/drivers/staging/ccg/composite.h new file mode 100644 index 0000000..19a5adf --- /dev/null +++ b/drivers/staging/ccg/composite.h @@ -0,0 +1,395 @@ +/* + * composite.h -- framework for usb gadgets which are composite devices + * + * Copyright (C) 2006-2008 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LINUX_USB_COMPOSITE_H +#define __LINUX_USB_COMPOSITE_H + +/* + * This framework is an optional layer on top of the USB Gadget interface, + * making it easier to build (a) Composite devices, supporting multiple + * functions within any single configuration, and (b) Multi-configuration + * devices, also supporting multiple functions but without necessarily + * having more than one function per configuration. + * + * Example: a device with a single configuration supporting both network + * link and mass storage functions is a composite device. Those functions + * might alternatively be packaged in individual configurations, but in + * the composite model the host can use both functions at the same time. + */ + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +/* + * USB function drivers should return USB_GADGET_DELAYED_STATUS if they + * wish to delay the data/status stages of the control transfer till they + * are ready. The control transfer will then be kept from completing till + * all the function drivers that requested for USB_GADGET_DELAYED_STAUS + * invoke usb_composite_setup_continue(). + */ +#define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ + +struct usb_configuration; + +/** + * struct usb_function - describes one function of a configuration + * @name: For diagnostics, identifies the function. + * @strings: tables of strings, keyed by identifiers assigned during bind() + * and by language IDs provided in control requests + * @descriptors: Table of full (or low) speed descriptors, using interface and + * string identifiers assigned during @bind(). If this pointer is null, + * the function will not be available at full speed (or at low speed). + * @hs_descriptors: Table of high speed descriptors, using interface and + * string identifiers assigned during @bind(). If this pointer is null, + * the function will not be available at high speed. + * @ss_descriptors: Table of super speed descriptors, using interface and + * string identifiers assigned during @bind(). If this + * pointer is null after initiation, the function will not + * be available at super speed. + * @config: assigned when @usb_add_function() is called; this is the + * configuration with which this function is associated. + * @bind: Before the gadget can register, all of its functions bind() to the + * available resources including string and interface identifiers used + * in interface or class descriptors; endpoints; I/O buffers; and so on. + * @unbind: Reverses @bind; called as a side effect of unregistering the + * driver which added this function. + * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may + * initialize usb_ep.driver data at this time (when it is used). + * Note that setting an interface to its current altsetting resets + * interface state, and that all interfaces have a disabled state. + * @get_alt: Returns the active altsetting. If this is not provided, + * then only altsetting zero is supported. + * @disable: (REQUIRED) Indicates the function should be disabled. Reasons + * include host resetting or reconfiguring the gadget, and disconnection. + * @setup: Used for interface-specific control requests. + * @suspend: Notifies functions when the host stops sending USB traffic. + * @resume: Notifies functions when the host restarts USB traffic. + * @get_status: Returns function status as a reply to + * GetStatus() request when the recepient is Interface. + * @func_suspend: callback to be called when + * SetFeature(FUNCTION_SUSPEND) is reseived + * + * A single USB function uses one or more interfaces, and should in most + * cases support operation at both full and high speeds. Each function is + * associated by @usb_add_function() with a one configuration; that function + * causes @bind() to be called so resources can be allocated as part of + * setting up a gadget driver. Those resources include endpoints, which + * should be allocated using @usb_ep_autoconfig(). + * + * To support dual speed operation, a function driver provides descriptors + * for both high and full speed operation. Except in rare cases that don't + * involve bulk endpoints, each speed needs different endpoint descriptors. + * + * Function drivers choose their own strategies for managing instance data. + * The simplest strategy just declares it "static', which means the function + * can only be activated once. If the function needs to be exposed in more + * than one configuration at a given speed, it needs to support multiple + * usb_function structures (one for each configuration). + * + * A more complex strategy might encapsulate a @usb_function structure inside + * a driver-specific instance structure to allows multiple activations. An + * example of multiple activations might be a CDC ACM function that supports + * two or more distinct instances within the same configuration, providing + * several independent logical data links to a USB host. + */ +struct usb_function { + const char *name; + struct usb_gadget_strings **strings; + struct usb_descriptor_header **descriptors; + struct usb_descriptor_header **hs_descriptors; + struct usb_descriptor_header **ss_descriptors; + + struct usb_configuration *config; + + /* REVISIT: bind() functions can be marked __init, which + * makes trouble for section mismatch analysis. See if + * we can't restructure things to avoid mismatching. + * Related: unbind() may kfree() but bind() won't... + */ + + /* configuration management: bind/unbind */ + int (*bind)(struct usb_configuration *, + struct usb_function *); + void (*unbind)(struct usb_configuration *, + struct usb_function *); + + /* runtime state management */ + int (*set_alt)(struct usb_function *, + unsigned interface, unsigned alt); + int (*get_alt)(struct usb_function *, + unsigned interface); + void (*disable)(struct usb_function *); + int (*setup)(struct usb_function *, + const struct usb_ctrlrequest *); + void (*suspend)(struct usb_function *); + void (*resume)(struct usb_function *); + + /* USB 3.0 additions */ + int (*get_status)(struct usb_function *); + int (*func_suspend)(struct usb_function *, + u8 suspend_opt); + /* private: */ + /* internals */ + struct list_head list; + DECLARE_BITMAP(endpoints, 32); +}; + +int usb_add_function(struct usb_configuration *, struct usb_function *); + +int usb_function_deactivate(struct usb_function *); +int usb_function_activate(struct usb_function *); + +int usb_interface_id(struct usb_configuration *, struct usb_function *); + +int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, + struct usb_ep *_ep); + +#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */ + +/** + * struct usb_configuration - represents one gadget configuration + * @label: For diagnostics, describes the configuration. + * @strings: Tables of strings, keyed by identifiers assigned during @bind() + * and by language IDs provided in control requests. + * @descriptors: Table of descriptors preceding all function descriptors. + * Examples include OTG and vendor-specific descriptors. + * @unbind: Reverses @bind; called as a side effect of unregistering the + * driver which added this configuration. + * @setup: Used to delegate control requests that aren't handled by standard + * device infrastructure or directed at a specific interface. + * @bConfigurationValue: Copied into configuration descriptor. + * @iConfiguration: Copied into configuration descriptor. + * @bmAttributes: Copied into configuration descriptor. + * @bMaxPower: Copied into configuration descriptor. + * @cdev: assigned by @usb_add_config() before calling @bind(); this is + * the device associated with this configuration. + * + * Configurations are building blocks for gadget drivers structured around + * function drivers. Simple USB gadgets require only one function and one + * configuration, and handle dual-speed hardware by always providing the same + * functionality. Slightly more complex gadgets may have more than one + * single-function configuration at a given speed; or have configurations + * that only work at one speed. + * + * Composite devices are, by definition, ones with configurations which + * include more than one function. + * + * The lifecycle of a usb_configuration includes allocation, initialization + * of the fields described above, and calling @usb_add_config() to set up + * internal data and bind it to a specific device. The configuration's + * @bind() method is then used to initialize all the functions and then + * call @usb_add_function() for them. + * + * Those functions would normally be independent of each other, but that's + * not mandatory. CDC WMC devices are an example where functions often + * depend on other functions, with some functions subsidiary to others. + * Such interdependency may be managed in any way, so long as all of the + * descriptors complete by the time the composite driver returns from + * its bind() routine. + */ +struct usb_configuration { + const char *label; + struct usb_gadget_strings **strings; + const struct usb_descriptor_header **descriptors; + + /* REVISIT: bind() functions can be marked __init, which + * makes trouble for section mismatch analysis. See if + * we can't restructure things to avoid mismatching... + */ + + /* configuration management: unbind/setup */ + void (*unbind)(struct usb_configuration *); + int (*setup)(struct usb_configuration *, + const struct usb_ctrlrequest *); + + /* fields in the config descriptor */ + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 bMaxPower; + + struct usb_composite_dev *cdev; + + /* private: */ + /* internals */ + struct list_head list; + struct list_head functions; + u8 next_interface_id; + unsigned superspeed:1; + unsigned highspeed:1; + unsigned fullspeed:1; + struct usb_function *interface[MAX_CONFIG_INTERFACES]; +}; + +int usb_add_config(struct usb_composite_dev *, + struct usb_configuration *, + int (*)(struct usb_configuration *)); + +void usb_remove_config(struct usb_composite_dev *, + struct usb_configuration *); + +/** + * struct usb_composite_driver - groups configurations into a gadget + * @name: For diagnostics, identifies the driver. + * @iProduct: Used as iProduct override if @dev->iProduct is not set. + * If NULL value of @name is taken. + * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is + * not set. If NULL a default "<system> <release> with <udc>" value + * will be used. + * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is + * not set. + * @dev: Template descriptor for the device, including default device + * identifiers. + * @strings: tables of strings, keyed by identifiers assigned during @bind + * and language IDs provided in control requests + * @max_speed: Highest speed the driver supports. + * @needs_serial: set to 1 if the gadget needs userspace to provide + * a serial number. If one is not provided, warning will be printed. + * @bind: (REQUIRED) Used to allocate resources that are shared across the + * whole device, such as string IDs, and add its configurations using + * @usb_add_config(). This may fail by returning a negative errno + * value; it should return zero on successful initialization. + * @unbind: Reverses @bind; called as a side effect of unregistering + * this driver. + * @disconnect: optional driver disconnect method + * @suspend: Notifies when the host stops sending USB traffic, + * after function notifications + * @resume: Notifies configuration when the host restarts USB traffic, + * before function notifications + * + * Devices default to reporting self powered operation. Devices which rely + * on bus powered operation should report this in their @bind method. + * + * Before returning from @bind, various fields in the template descriptor + * may be overridden. These include the idVendor/idProduct/bcdDevice values + * normally to bind the appropriate host side driver, and the three strings + * (iManufacturer, iProduct, iSerialNumber) normally used to provide user + * meaningful device identifiers. (The strings will not be defined unless + * they are defined in @dev and @strings.) The correct ep0 maxpacket size + * is also reported, as defined by the underlying controller driver. + */ +struct usb_composite_driver { + const char *name; + const char *iProduct; + const char *iManufacturer; + const char *iSerialNumber; + const struct usb_device_descriptor *dev; + struct usb_gadget_strings **strings; + enum usb_device_speed max_speed; + unsigned needs_serial:1; + + int (*bind)(struct usb_composite_dev *cdev); + int (*unbind)(struct usb_composite_dev *); + + void (*disconnect)(struct usb_composite_dev *); + + /* global suspend hooks */ + void (*suspend)(struct usb_composite_dev *); + void (*resume)(struct usb_composite_dev *); +}; + +extern int usb_composite_probe(struct usb_composite_driver *driver); +extern void usb_composite_unregister(struct usb_composite_driver *driver); +extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); + + +/** + * struct usb_composite_device - represents one composite usb gadget + * @gadget: read-only, abstracts the gadget's usb peripheral controller + * @req: used for control responses; buffer is pre-allocated + * @bufsiz: size of buffer pre-allocated in @req + * @config: the currently active configuration + * + * One of these devices is allocated and initialized before the + * associated device driver's bind() is called. + * + * OPEN ISSUE: it appears that some WUSB devices will need to be + * built by combining a normal (wired) gadget with a wireless one. + * This revision of the gadget framework should probably try to make + * sure doing that won't hurt too much. + * + * One notion for how to handle Wireless USB devices involves: + * (a) a second gadget here, discovery mechanism TBD, but likely + * needing separate "register/unregister WUSB gadget" calls; + * (b) updates to usb_gadget to include flags "is it wireless", + * "is it wired", plus (presumably in a wrapper structure) + * bandgroup and PHY info; + * (c) presumably a wireless_ep wrapping a usb_ep, and reporting + * wireless-specific parameters like maxburst and maxsequence; + * (d) configurations that are specific to wireless links; + * (e) function drivers that understand wireless configs and will + * support wireless for (additional) function instances; + * (f) a function to support association setup (like CBAF), not + * necessarily requiring a wireless adapter; + * (g) composite device setup that can create one or more wireless + * configs, including appropriate association setup support; + * (h) more, TBD. + */ +struct usb_composite_dev { + struct usb_gadget *gadget; + struct usb_request *req; + unsigned bufsiz; + + struct usb_configuration *config; + + /* private: */ + /* internals */ + unsigned int suspended:1; + struct usb_device_descriptor desc; + struct list_head configs; + struct usb_composite_driver *driver; + u8 next_string_id; + u8 manufacturer_override; + u8 product_override; + u8 serial_override; + + /* the gadget driver won't enable the data pullup + * while the deactivation count is nonzero. + */ + unsigned deactivations; + + /* the composite driver won't complete the control transfer's + * data/status stages till delayed_status is zero. + */ + int delayed_status; + + /* protects deactivations and delayed_status counts*/ + spinlock_t lock; +}; + +extern int usb_string_id(struct usb_composite_dev *c); +extern int usb_string_ids_tab(struct usb_composite_dev *c, + struct usb_string *str); +extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); + + +/* messaging utils */ +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARNING(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + +#endif /* __LINUX_USB_COMPOSITE_H */ diff --git a/drivers/staging/ccg/config.c b/drivers/staging/ccg/config.c new file mode 100644 index 0000000..7542a72 --- /dev/null +++ b/drivers/staging/ccg/config.c @@ -0,0 +1,158 @@ +/* + * usb/gadget/config.c -- simplify building config descriptors + * + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/string.h> +#include <linux/device.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + + +/** + * usb_descriptor_fillbuf - fill buffer with descriptors + * @buf: Buffer to be filled + * @buflen: Size of buf + * @src: Array of descriptor pointers, terminated by null pointer. + * + * Copies descriptors into the buffer, returning the length or a + * negative error code if they can't all be copied. Useful when + * assembling descriptors for an associated set of interfaces used + * as part of configuring a composite device; or in other cases where + * sets of descriptors need to be marshaled. + */ +int +usb_descriptor_fillbuf(void *buf, unsigned buflen, + const struct usb_descriptor_header **src) +{ + u8 *dest = buf; + + if (!src) + return -EINVAL; + + /* fill buffer from src[] until null descriptor ptr */ + for (; NULL != *src; src++) { + unsigned len = (*src)->bLength; + + if (len > buflen) + return -EINVAL; + memcpy(dest, *src, len); + buflen -= len; + dest += len; + } + return dest - (u8 *)buf; +} + + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} + +/** + * usb_copy_descriptors - copy a vector of USB descriptors + * @src: null-terminated vector to copy + * Context: initialization code, which may sleep + * + * This makes a copy of a vector of USB descriptors. Its primary use + * is to support usb_function objects which can have multiple copies, + * each needing different descriptors. Functions may have static + * tables of descriptors, which are used as templates and customized + * with identifiers (for interfaces, strings, endpoints, and more) + * as needed by a given function instance. + */ +struct usb_descriptor_header ** +usb_copy_descriptors(struct usb_descriptor_header **src) +{ + struct usb_descriptor_header **tmp; + unsigned bytes; + unsigned n_desc; + void *mem; + struct usb_descriptor_header **ret; + + /* count descriptors and their sizes; then add vector size */ + for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) + bytes += (*tmp)->bLength; + bytes += (n_desc + 1) * sizeof(*tmp); + + mem = kmalloc(bytes, GFP_KERNEL); + if (!mem) + return NULL; + + /* fill in pointers starting at "tmp", + * to descriptors copied starting at "mem"; + * and return "ret" + */ + tmp = mem; + ret = mem; + mem += (n_desc + 1) * sizeof(*tmp); + while (*src) { + memcpy(mem, *src, (*src)->bLength); + *tmp = mem; + tmp++; + mem += (*src)->bLength; + src++; + } + *tmp = NULL; + + return ret; +} + diff --git a/drivers/staging/ccg/epautoconf.c b/drivers/staging/ccg/epautoconf.c new file mode 100644 index 0000000..51f3d42 --- /dev/null +++ b/drivers/staging/ccg/epautoconf.c @@ -0,0 +1,393 @@ +/* + * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers + * + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/device.h> + +#include <linux/ctype.h> +#include <linux/string.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include "gadget_chips.h" + + +/* we must assign addresses for configurable endpoints (like net2280) */ +static unsigned epnum; + +// #define MANY_ENDPOINTS +#ifdef MANY_ENDPOINTS +/* more than 15 configurable endpoints */ +static unsigned in_epnum; +#endif + + +/* + * This should work with endpoints from controller drivers sharing the + * same endpoint naming convention. By example: + * + * - ep1, ep2, ... address is fixed, not direction or type + * - ep1in, ep2out, ... address and direction are fixed, not type + * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction + * - ep1in-bulk, ep2out-iso, ... all three are fixed + * - ep-* ... no functionality restrictions + * + * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. + * Less common restrictions are implied by gadget_is_*(). + * + * NOTE: each endpoint is unidirectional, as specified by its USB + * descriptor; and isn't specific to a configuration or altsetting. + */ +static int +ep_matches ( + struct usb_gadget *gadget, + struct usb_ep *ep, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp +) +{ + u8 type; + const char *tmp; + u16 max; + + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (NULL != ep->driver_data) + return 0; + + /* only support ep0 for portable CONTROL traffic */ + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (USB_ENDPOINT_XFER_CONTROL == type) + return 0; + + /* some other naming convention */ + if ('e' != ep->name[0]) + return 0; + + /* type-restriction: "-iso", "-bulk", or "-int". + * direction-restriction: "in", "out". + */ + if ('-' != ep->name[2]) { + tmp = strrchr (ep->name, '-'); + if (tmp) { + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if ('s' == tmp[2]) // == "-iso" + return 0; + /* for now, avoid PXA "interrupt-in"; + * it's documented as never using DATA1. + */ + if (gadget_is_pxa (gadget) + && 'i' == tmp [1]) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if ('b' != tmp[1]) // != "-bulk" + return 0; + break; + case USB_ENDPOINT_XFER_ISOC: + if ('s' != tmp[2]) // != "-iso" + return 0; + } + } else { + tmp = ep->name + strlen (ep->name); + } + + /* direction-restriction: "..in-..", "out-.." */ + tmp--; + if (!isdigit (*tmp)) { + if (desc->bEndpointAddress & USB_DIR_IN) { + if ('n' != *tmp) + return 0; + } else { + if ('t' != *tmp) + return 0; + } + } + } + + /* + * Get the number of required streams from the EP companion + * descriptor and see if the EP matches it + */ + if (usb_endpoint_xfer_bulk(desc)) { + if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) { + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + + } + + /* + * If the protocol driver hasn't yet decided on wMaxPacketSize + * and wants to know the maximum possible, provide the info. + */ + if (desc->wMaxPacketSize == 0) + desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); + + /* endpoint maxpacket size is an input parameter, except for bulk + * where it's an output parameter representing the full speed limit. + * the usb spec fixes high speed bulk maxpacket at 512 bytes. + */ + max = 0x7ff & usb_endpoint_maxp(desc); + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + /* FALLTHROUGH */ + + case USB_ENDPOINT_XFER_ISOC: + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (ep->maxpacket < max) + return 0; + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + + /* BOTH: "high bandwidth" works only at high speed */ + if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { + if (!gadget_is_dualspeed(gadget)) + return 0; + /* configure your hardware with enough buffering!! */ + } + break; + } + + /* MATCH!! */ + + /* report address */ + desc->bEndpointAddress &= USB_DIR_IN; + if (isdigit (ep->name [2])) { + u8 num = simple_strtoul (&ep->name [2], NULL, 10); + desc->bEndpointAddress |= num; +#ifdef MANY_ENDPOINTS + } else if (desc->bEndpointAddress & USB_DIR_IN) { + if (++in_epnum > 15) + return 0; + desc->bEndpointAddress = USB_DIR_IN | in_epnum; +#endif + } else { + if (++epnum > 15) + return 0; + desc->bEndpointAddress |= epnum; + } + + /* report (variable) full speed bulk maxpacket */ + if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { + int size = ep->maxpacket; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + ep->address = desc->bEndpointAddress; + return 1; +} + +static struct usb_ep * +find_ep (struct usb_gadget *gadget, const char *name) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (0 == strcmp (ep->name, name)) + return ep; + } + return NULL; +} + +/** + * usb_ep_autoconfig_ss() - choose an endpoint matching the ep + * descriptor and ep companion descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on + * success. + * @ep_comp: Endpoint companion descriptor, with the required + * number of streams. Will be modified when the chosen EP + * supports a different number of streams. + * + * This routine replaces the usb_ep_autoconfig when needed + * superspeed enhancments. If such enhancemnets are required, + * the FD should call usb_ep_autoconfig_ss directly and provide + * the additional ep_comp parameter. + * + * By choosing an endpoint to use with the specified descriptor, + * this routine simplifies writing gadget drivers that work with + * multiple USB device controllers. The endpoint would be + * passed later to usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration + * on your hardware. This code may not make the best choices + * about how to use the USB controller, and it can't know all + * the restrictions that may apply. Some combinations of driver + * and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed and + * the bmAttribute field in the ep companion descriptor is + * updated with the assigned number of streams if it is + * different from the original value. To prevent the endpoint + * from being returned by a later autoconfig call, claim it by + * assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep *usb_ep_autoconfig_ss( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp +) +{ + struct usb_ep *ep; + u8 type; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* First, apply chip-specific "best usage" knowledge. + * This might make a good usb_gadget_ops hook ... + */ + if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = find_ep (gadget, "ep-e"); + if (ep && ep_matches(gadget, ep, desc, ep_comp)) + goto found_ep; + ep = find_ep (gadget, "ep-f"); + if (ep && ep_matches(gadget, ep, desc, ep_comp)) + goto found_ep; + + } else if (gadget_is_goku (gadget)) { + if (USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough */ + ep = find_ep(gadget, "ep3-bulk"); + if (ep && ep_matches(gadget, ep, desc, ep_comp)) + goto found_ep; + } else if (USB_ENDPOINT_XFER_BULK == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + ep = find_ep(gadget, "ep2-bulk"); + if (ep && ep_matches(gadget, ep, desc, + ep_comp)) + goto found_ep; + } + +#ifdef CONFIG_BLACKFIN + } else if (gadget_is_musbhdrc(gadget)) { + if ((USB_ENDPOINT_XFER_BULK == type) || + (USB_ENDPOINT_XFER_ISOC == type)) { + if (USB_DIR_IN & desc->bEndpointAddress) + ep = find_ep (gadget, "ep5in"); + else + ep = find_ep (gadget, "ep6out"); + } else if (USB_ENDPOINT_XFER_INT == type) { + if (USB_DIR_IN & desc->bEndpointAddress) + ep = find_ep(gadget, "ep1in"); + else + ep = find_ep(gadget, "ep2out"); + } else + ep = NULL; + if (ep && ep_matches(gadget, ep, desc, ep_comp)) + goto found_ep; +#endif + } + + /* Second, look at endpoints until an unclaimed one looks usable */ + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (ep_matches(gadget, ep, desc, ep_comp)) + goto found_ep; + } + + /* Fail */ + return NULL; +found_ep: + ep->desc = NULL; + ep->comp_desc = NULL; + return ep; +} + +/** + * usb_ep_autoconfig() - choose an endpoint matching the + * descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on success. + * + * By choosing an endpoint to use with the specified descriptor, this + * routine simplifies writing gadget drivers that work with multiple + * USB device controllers. The endpoint would be passed later to + * usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration on your + * hardware. This code may not make the best choices about how to use the + * USB controller, and it can't know all the restrictions that may apply. + * Some combinations of driver and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed. To prevent + * the endpoint from being returned by a later autoconfig call, claim it + * by assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep *usb_ep_autoconfig( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc +) +{ + return usb_ep_autoconfig_ss(gadget, desc, NULL); +} + + +/** + * usb_ep_autoconfig_reset - reset endpoint autoconfig state + * @gadget: device for which autoconfig state will be reset + * + * Use this for devices where one configuration may need to assign + * endpoint resources very differently from the next one. It clears + * state such as ep->driver_data and the record of assigned endpoints + * used by usb_ep_autoconfig(). + */ +void usb_ep_autoconfig_reset (struct usb_gadget *gadget) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + ep->driver_data = NULL; + } +#ifdef MANY_ENDPOINTS + in_epnum = 0; +#endif + epnum = 0; +} + diff --git a/drivers/staging/ccg/f_acm.c b/drivers/staging/ccg/f_acm.c new file mode 100644 index 0000000..d672250a --- /dev/null +++ b/drivers/staging/ccg/f_acm.c @@ -0,0 +1,814 @@ +/* + * f_acm.c -- USB CDC serial (ACM) function driver + * + * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) + * Copyright (C) 2008 by David Brownell + * Copyright (C) 2008 by Nokia Corporation + * Copyright (C) 2009 by Samsung Electronics + * Author: Michal Nazarewicz (mina86@mina86.com) + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of that License or (at your option) any later version. + */ + +/* #define VERBOSE_DEBUG */ + +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/device.h> + +#include "u_serial.h" +#include "gadget_chips.h" + + +/* + * This CDC ACM function support just wraps control functions and + * notifications around the generic serial-over-usb code. + * + * Because CDC ACM is standardized by the USB-IF, many host operating + * systems have drivers for it. Accordingly, ACM is the preferred + * interop solution for serial-port type connections. The control + * models are often not necessary, and in any case don't do much in + * this bare-bones implementation. + * + * Note that even MS-Windows has some support for ACM. However, that + * support is somewhat broken because when you use ACM in a composite + * device, having multiple interfaces confuses the poor OS. It doesn't + * seem to understand CDC Union descriptors. The new "association" + * descriptors (roughly equivalent to CDC Unions) may sometimes help. + */ + +struct f_acm { + struct gserial port; + u8 ctrl_id, data_id; + u8 port_num; + + u8 pending; + + /* lock is mostly for pending and notify_req ... they get accessed + * by callbacks both from tty (open/close/break) under its spinlock, + * and notify_req.complete() which can't use that lock. + */ + spinlock_t lock; + + struct usb_ep *notify; + struct usb_request *notify_req; + + struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ + + /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */ + u16 port_handshake_bits; +#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ +#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ + + /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */ + u16 serial_state; +#define ACM_CTRL_OVERRUN (1 << 6) +#define ACM_CTRL_PARITY (1 << 5) +#define ACM_CTRL_FRAMING (1 << 4) +#define ACM_CTRL_RI (1 << 3) +#define ACM_CTRL_BRK (1 << 2) +#define ACM_CTRL_DSR (1 << 1) +#define ACM_CTRL_DCD (1 << 0) +}; + +static inline struct f_acm *func_to_acm(struct usb_function *f) +{ + return container_of(f, struct f_acm, port.func); +} + +static inline struct f_acm *port_to_acm(struct gserial *p) +{ + return container_of(p, struct f_acm, port); +} + +/*-------------------------------------------------------------------------*/ + +/* notification endpoint uses smallish and infrequent fixed-size messages */ + +#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ +#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ + +/* interface and class descriptors: */ + +static struct usb_interface_assoc_descriptor +acm_iad_descriptor = { + .bLength = sizeof acm_iad_descriptor, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + + /* .bFirstInterface = DYNAMIC, */ + .bInterfaceCount = 2, // control + data + .bFunctionClass = USB_CLASS_COMM, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + /* .iFunction = DYNAMIC */ +}; + + +static struct usb_interface_descriptor acm_control_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + /* .bInterfaceNumber = DYNAMIC */ + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + /* .iInterface = DYNAMIC */ +}; + +static struct usb_interface_descriptor acm_data_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + /* .bInterfaceNumber = DYNAMIC */ + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + /* .iInterface = DYNAMIC */ +}; + +static struct usb_cdc_header_desc acm_header_desc = { + .bLength = sizeof(acm_header_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = cpu_to_le16(0x0110), +}; + +static struct usb_cdc_call_mgmt_descriptor +acm_call_mgmt_descriptor = { + .bLength = sizeof(acm_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + /* .bDataInterface = DYNAMIC */ +}; + +static struct usb_cdc_acm_descriptor acm_descriptor = { + .bLength = sizeof(acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = USB_CDC_CAP_LINE, +}; + +static struct usb_cdc_union_desc acm_union_desc = { + .bLength = sizeof(acm_union_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + /* .bMasterInterface0 = DYNAMIC */ + /* .bSlaveInterface0 = DYNAMIC */ +}; + +/* full speed support: */ + +static struct usb_endpoint_descriptor acm_fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, +}; + +static struct usb_endpoint_descriptor acm_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 acm_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 *acm_fs_function[] = { + (struct usb_descriptor_header *) &acm_iad_descriptor, + (struct usb_descriptor_header *) &acm_control_interface_desc, + (struct usb_descriptor_header *) &acm_header_desc, + (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, + (struct usb_descriptor_header *) &acm_union_desc, + (struct usb_descriptor_header *) &acm_fs_notify_desc, + (struct usb_descriptor_header *) &acm_data_interface_desc, + (struct usb_descriptor_header *) &acm_fs_in_desc, + (struct usb_descriptor_header *) &acm_fs_out_desc, + NULL, +}; + +/* high speed support: */ + +static struct usb_endpoint_descriptor acm_hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, +}; + +static struct usb_endpoint_descriptor acm_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 acm_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 *acm_hs_function[] = { + (struct usb_descriptor_header *) &acm_iad_descriptor, + (struct usb_descriptor_header *) &acm_control_interface_desc, + (struct usb_descriptor_header *) &acm_header_desc, + (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, + (struct usb_descriptor_header *) &acm_union_desc, + (struct usb_descriptor_header *) &acm_hs_notify_desc, + (struct usb_descriptor_header *) &acm_data_interface_desc, + (struct usb_descriptor_header *) &acm_hs_in_desc, + (struct usb_descriptor_header *) &acm_hs_out_desc, + NULL, +}; + +static struct usb_endpoint_descriptor acm_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 acm_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 acm_ss_bulk_comp_desc = { + .bLength = sizeof acm_ss_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *acm_ss_function[] = { + (struct usb_descriptor_header *) &acm_iad_descriptor, + (struct usb_descriptor_header *) &acm_control_interface_desc, + (struct usb_descriptor_header *) &acm_header_desc, + (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, + (struct usb_descriptor_header *) &acm_union_desc, + (struct usb_descriptor_header *) &acm_hs_notify_desc, + (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, + (struct usb_descriptor_header *) &acm_data_interface_desc, + (struct usb_descriptor_header *) &acm_ss_in_desc, + (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, + (struct usb_descriptor_header *) &acm_ss_out_desc, + (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, + NULL, +}; + +/* string descriptors: */ + +#define ACM_CTRL_IDX 0 +#define ACM_DATA_IDX 1 +#define ACM_IAD_IDX 2 + +/* static strings, in UTF-8 */ +static struct usb_string acm_string_defs[] = { + [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", + [ACM_DATA_IDX].s = "CDC ACM Data", + [ACM_IAD_IDX ].s = "CDC Serial", + { /* ZEROES END LIST */ }, +}; + +static struct usb_gadget_strings acm_string_table = { + .language = 0x0409, /* en-us */ + .strings = acm_string_defs, +}; + +static struct usb_gadget_strings *acm_strings[] = { + &acm_string_table, + NULL, +}; + +/*-------------------------------------------------------------------------*/ + +/* ACM control ... data handling is delegated to tty library code. + * The main task of this function is to activate and deactivate + * that code based on device state; track parameters like line + * speed, handshake state, and so on; and issue notifications. + */ + +static void acm_complete_set_line_coding(struct usb_ep *ep, + struct usb_request *req) +{ + struct f_acm *acm = ep->driver_data; + struct usb_composite_dev *cdev = acm->port.func.config->cdev; + + if (req->status != 0) { + DBG(cdev, "acm ttyGS%d completion, err %d\n", + acm->port_num, req->status); + return; + } + + /* normal completion */ + if (req->actual != sizeof(acm->port_line_coding)) { + DBG(cdev, "acm ttyGS%d short resp, len %d\n", + acm->port_num, req->actual); + usb_ep_set_halt(ep); + } else { + struct usb_cdc_line_coding *value = req->buf; + + /* REVISIT: we currently just remember this data. + * If we change that, (a) validate it first, then + * (b) update whatever hardware needs updating, + * (c) worry about locking. This is information on + * the order of 9600-8-N-1 ... most of which means + * nothing unless we control a real RS232 line. + */ + acm->port_line_coding = *value; + } +} + +static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct f_acm *acm = func_to_acm(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + /* composite driver infrastructure handles everything except + * CDC class messages; interface activation uses set_alt(). + * + * Note CDC spec table 4 lists the ACM request profile. It requires + * encapsulated command support ... we don't handle any, and respond + * to them by stalling. Options include get/set/clear comm features + * (not that useful) and SEND_BREAK. + */ + switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { + + /* SET_LINE_CODING ... just read and save what the host sends */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_LINE_CODING: + if (w_length != sizeof(struct usb_cdc_line_coding) + || w_index != acm->ctrl_id) + goto invalid; + + value = w_length; + cdev->gadget->ep0->driver_data = acm; + req->complete = acm_complete_set_line_coding; + break; + + /* GET_LINE_CODING ... return what host sent, or initial value */ + case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_GET_LINE_CODING: + if (w_index != acm->ctrl_id) + goto invalid; + + value = min_t(unsigned, w_length, + sizeof(struct usb_cdc_line_coding)); + memcpy(req->buf, &acm->port_line_coding, value); + break; + + /* SET_CONTROL_LINE_STATE ... save what the host sent */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_CONTROL_LINE_STATE: + if (w_index != acm->ctrl_id) + goto invalid; + + value = 0; + + /* FIXME we should not allow data to flow until the + * host sets the ACM_CTRL_DTR bit; and when it clears + * that bit, we should return to that no-flow state. + */ + acm->port_handshake_bits = w_value; + break; + + default: +invalid: + VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n", + acm->port_num, ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + req->zero = 0; + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + ERROR(cdev, "acm response on ttyGS%d, err %d\n", + acm->port_num, value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_acm *acm = func_to_acm(f); + struct usb_composite_dev *cdev = f->config->cdev; + + /* we know alt == 0, so this is an activation or a reset */ + + if (intf == acm->ctrl_id) { + if (acm->notify->driver_data) { + VDBG(cdev, "reset acm control interface %d\n", intf); + usb_ep_disable(acm->notify); + } else { + VDBG(cdev, "init acm ctrl interface %d\n", intf); + if (config_ep_by_speed(cdev->gadget, f, acm->notify)) + return -EINVAL; + } + usb_ep_enable(acm->notify); + acm->notify->driver_data = acm; + + } else if (intf == acm->data_id) { + if (acm->port.in->driver_data) { + DBG(cdev, "reset acm ttyGS%d\n", acm->port_num); + gserial_disconnect(&acm->port); + } + if (!acm->port.in->desc || !acm->port.out->desc) { + DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); + if (config_ep_by_speed(cdev->gadget, f, + acm->port.in) || + config_ep_by_speed(cdev->gadget, f, + acm->port.out)) { + acm->port.in->desc = NULL; + acm->port.out->desc = NULL; + return -EINVAL; + } + } + gserial_connect(&acm->port, acm->port_num); + + } else + return -EINVAL; + + return 0; +} + +static void acm_disable(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + struct usb_composite_dev *cdev = f->config->cdev; + + DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num); + gserial_disconnect(&acm->port); + usb_ep_disable(acm->notify); + acm->notify->driver_data = NULL; +} + +/*-------------------------------------------------------------------------*/ + +/** + * acm_cdc_notify - issue CDC notification to host + * @acm: wraps host to be notified + * @type: notification type + * @value: Refer to cdc specs, wValue field. + * @data: data to be sent + * @length: size of data + * Context: irqs blocked, acm->lock held, acm_notify_req non-null + * + * Returns zero on success or a negative errno. + * + * See section 6.3.5 of the CDC 1.1 specification for information + * about the only notification we issue: SerialState change. + */ +static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value, + void *data, unsigned length) +{ + struct usb_ep *ep = acm->notify; + struct usb_request *req; + struct usb_cdc_notification *notify; + const unsigned len = sizeof(*notify) + length; + void *buf; + int status; + + req = acm->notify_req; + acm->notify_req = NULL; + acm->pending = false; + + req->length = len; + notify = req->buf; + buf = notify + 1; + + notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS + | USB_RECIP_INTERFACE; + notify->bNotificationType = type; + notify->wValue = cpu_to_le16(value); + notify->wIndex = cpu_to_le16(acm->ctrl_id); + notify->wLength = cpu_to_le16(length); + memcpy(buf, data, length); + + /* ep_queue() can complete immediately if it fills the fifo... */ + spin_unlock(&acm->lock); + status = usb_ep_queue(ep, req, GFP_ATOMIC); + spin_lock(&acm->lock); + + if (status < 0) { + ERROR(acm->port.func.config->cdev, + "acm ttyGS%d can't notify serial state, %d\n", + acm->port_num, status); + acm->notify_req = req; + } + + return status; +} + +static int acm_notify_serial_state(struct f_acm *acm) +{ + struct usb_composite_dev *cdev = acm->port.func.config->cdev; + int status; + + spin_lock(&acm->lock); + if (acm->notify_req) { + DBG(cdev, "acm ttyGS%d serial state %04x\n", + acm->port_num, acm->serial_state); + status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE, + 0, &acm->serial_state, sizeof(acm->serial_state)); + } else { + acm->pending = true; + status = 0; + } + spin_unlock(&acm->lock); + return status; +} + +static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_acm *acm = req->context; + u8 doit = false; + + /* on this call path we do NOT hold the port spinlock, + * which is why ACM needs its own spinlock + */ + spin_lock(&acm->lock); + if (req->status != -ESHUTDOWN) + doit = acm->pending; + acm->notify_req = req; + spin_unlock(&acm->lock); + + if (doit) + acm_notify_serial_state(acm); +} + +/* connect == the TTY link is open */ + +static void acm_connect(struct gserial *port) +{ + struct f_acm *acm = port_to_acm(port); + + acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; + acm_notify_serial_state(acm); +} + +static void acm_disconnect(struct gserial *port) +{ + struct f_acm *acm = port_to_acm(port); + + acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); + acm_notify_serial_state(acm); +} + +static int acm_send_break(struct gserial *port, int duration) +{ + struct f_acm *acm = port_to_acm(port); + u16 state; + + state = acm->serial_state; + state &= ~ACM_CTRL_BRK; + if (duration) + state |= ACM_CTRL_BRK; + + acm->serial_state = state; + return acm_notify_serial_state(acm); +} + +/*-------------------------------------------------------------------------*/ + +/* ACM function driver setup/binding */ +static int +acm_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct f_acm *acm = func_to_acm(f); + int status; + struct usb_ep *ep; + + /* allocate instance-specific interface IDs, and patch descriptors */ + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + acm->ctrl_id = status; + acm_iad_descriptor.bFirstInterface = status; + + acm_control_interface_desc.bInterfaceNumber = status; + acm_union_desc .bMasterInterface0 = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + acm->data_id = status; + + acm_data_interface_desc.bInterfaceNumber = status; + acm_union_desc.bSlaveInterface0 = status; + acm_call_mgmt_descriptor.bDataInterface = status; + + status = -ENODEV; + + /* allocate instance-specific endpoints */ + ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc); + if (!ep) + goto fail; + acm->port.in = ep; + ep->driver_data = cdev; /* claim */ + + ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc); + if (!ep) + goto fail; + acm->port.out = ep; + ep->driver_data = cdev; /* claim */ + + ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc); + if (!ep) + goto fail; + acm->notify = ep; + ep->driver_data = cdev; /* claim */ + + /* allocate notification */ + acm->notify_req = gs_alloc_req(ep, + sizeof(struct usb_cdc_notification) + 2, + GFP_KERNEL); + if (!acm->notify_req) + goto fail; + + acm->notify_req->complete = acm_cdc_notify_complete; + acm->notify_req->context = acm; + + /* copy descriptors */ + f->descriptors = usb_copy_descriptors(acm_fs_function); + if (!f->descriptors) + goto fail; + + /* support all relevant hardware speeds... we expect that when + * hardware is dual speed, all bulk-capable endpoints work at + * both speeds + */ + if (gadget_is_dualspeed(c->cdev->gadget)) { + acm_hs_in_desc.bEndpointAddress = + acm_fs_in_desc.bEndpointAddress; + acm_hs_out_desc.bEndpointAddress = + acm_fs_out_desc.bEndpointAddress; + acm_hs_notify_desc.bEndpointAddress = + acm_fs_notify_desc.bEndpointAddress; + + /* copy descriptors */ + f->hs_descriptors = usb_copy_descriptors(acm_hs_function); + } + if (gadget_is_superspeed(c->cdev->gadget)) { + acm_ss_in_desc.bEndpointAddress = + acm_fs_in_desc.bEndpointAddress; + acm_ss_out_desc.bEndpointAddress = + acm_fs_out_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(acm_ss_function); + if (!f->ss_descriptors) + goto fail; + } + + DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", + acm->port_num, + gadget_is_superspeed(c->cdev->gadget) ? "super" : + gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", + acm->port.in->name, acm->port.out->name, + acm->notify->name); + return 0; + +fail: + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); + + /* we might as well release our claims on endpoints */ + if (acm->notify) + acm->notify->driver_data = NULL; + if (acm->port.out) + acm->port.out->driver_data = NULL; + if (acm->port.in) + acm->port.in->driver_data = NULL; + + ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); + + return status; +} + +static void +acm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + if (gadget_is_dualspeed(c->cdev->gadget)) + usb_free_descriptors(f->hs_descriptors); + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); + usb_free_descriptors(f->descriptors); + gs_free_req(acm->notify, acm->notify_req); + kfree(acm); +} + +/* Some controllers can't support CDC ACM ... */ +static inline bool can_support_cdc(struct usb_configuration *c) +{ + /* everything else is *probably* fine ... */ + return true; +} + +/** + * acm_bind_config - add a CDC ACM function to a configuration + * @c: the configuration to support the CDC ACM instance + * @port_num: /dev/ttyGS* port this interface will use + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + * + * Caller must have called @gserial_setup() with enough ports to + * handle all the ones it binds. Caller is also responsible + * for calling @gserial_cleanup() before module unload. + */ +int acm_bind_config(struct usb_configuration *c, u8 port_num) +{ + struct f_acm *acm; + int status; + + if (!can_support_cdc(c)) + return -EINVAL; + + /* REVISIT might want instance-specific strings to help + * distinguish instances ... + */ + + /* maybe allocate device-global string IDs, and patch descriptors */ + if (acm_string_defs[ACM_CTRL_IDX].id == 0) { + status = usb_string_id(c->cdev); + if (status < 0) + return status; + acm_string_defs[ACM_CTRL_IDX].id = status; + + acm_control_interface_desc.iInterface = status; + + status = usb_string_id(c->cdev); + if (status < 0) + return status; + acm_string_defs[ACM_DATA_IDX].id = status; + + acm_data_interface_desc.iInterface = status; + + status = usb_string_id(c->cdev); + if (status < 0) + return status; + acm_string_defs[ACM_IAD_IDX].id = status; + + acm_iad_descriptor.iFunction = status; + } + + /* allocate and initialize one new instance */ + acm = kzalloc(sizeof *acm, GFP_KERNEL); + if (!acm) + return -ENOMEM; + + spin_lock_init(&acm->lock); + + acm->port_num = port_num; + + acm->port.connect = acm_connect; + acm->port.disconnect = acm_disconnect; + acm->port.send_break = acm_send_break; + + acm->port.func.name = "acm"; + acm->port.func.strings = acm_strings; + /* descriptors are per-instance copies */ + acm->port.func.bind = acm_bind; + acm->port.func.unbind = acm_unbind; + acm->port.func.set_alt = acm_set_alt; + acm->port.func.setup = acm_setup; + acm->port.func.disable = acm_disable; + + status = usb_add_function(c, &acm->port.func); + if (status) + kfree(acm); + return status; +} diff --git a/drivers/staging/ccg/f_fs.c b/drivers/staging/ccg/f_fs.c new file mode 100644 index 0000000..8adc79d --- /dev/null +++ b/drivers/staging/ccg/f_fs.c @@ -0,0 +1,2455 @@ +/* + * f_fs.c -- user mode file system API for USB composite function controllers + * + * Copyright (C) 2010 Samsung Electronics + * Author: Michal Nazarewicz <mina86@mina86.com> + * + * Based on inode.c (GadgetFS) which was: + * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003 Agilent Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#include <linux/blkdev.h> +#include <linux/pagemap.h> +#include <linux/export.h> +#include <linux/hid.h> +#include <asm/unaligned.h> + +#include <linux/usb/composite.h> +#include <linux/usb/functionfs.h> + + +#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ + + +/* Debugging ****************************************************************/ + +#ifdef VERBOSE_DEBUG +# define pr_vdebug pr_debug +# define ffs_dump_mem(prefix, ptr, len) \ + print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) +#else +# define pr_vdebug(...) do { } while (0) +# define ffs_dump_mem(prefix, ptr, len) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define ENTER() pr_vdebug("%s()\n", __func__) + + +/* The data structure and setup file ****************************************/ + +enum ffs_state { + /* + * Waiting for descriptors and strings. + * + * In this state no open(2), read(2) or write(2) on epfiles + * may succeed (which should not be the problem as there + * should be no such files opened in the first place). + */ + FFS_READ_DESCRIPTORS, + FFS_READ_STRINGS, + + /* + * We've got descriptors and strings. We are or have called + * functionfs_ready_callback(). functionfs_bind() may have + * been called but we don't know. + * + * This is the only state in which operations on epfiles may + * succeed. + */ + FFS_ACTIVE, + + /* + * All endpoints have been closed. This state is also set if + * we encounter an unrecoverable error. The only + * unrecoverable error is situation when after reading strings + * from user space we fail to initialise epfiles or + * functionfs_ready_callback() returns with error (<0). + * + * In this state no open(2), read(2) or write(2) (both on ep0 + * as well as epfile) may succeed (at this point epfiles are + * unlinked and all closed so this is not a problem; ep0 is + * also closed but ep0 file exists and so open(2) on ep0 must + * fail). + */ + FFS_CLOSING +}; + + +enum ffs_setup_state { + /* There is no setup request pending. */ + FFS_NO_SETUP, + /* + * User has read events and there was a setup request event + * there. The next read/write on ep0 will handle the + * request. + */ + FFS_SETUP_PENDING, + /* + * There was event pending but before user space handled it + * some other event was introduced which canceled existing + * setup. If this state is set read/write on ep0 return + * -EIDRM. This state is only set when adding event. + */ + FFS_SETUP_CANCELED +}; + + + +struct ffs_epfile; +struct ffs_function; + +struct ffs_data { + struct usb_gadget *gadget; + + /* + * Protect access read/write operations, only one read/write + * at a time. As a consequence protects ep0req and company. + * While setup request is being processed (queued) this is + * held. + */ + struct mutex mutex; + + /* + * Protect access to endpoint related structures (basically + * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for + * endpoint zero. + */ + spinlock_t eps_lock; + + /* + * XXX REVISIT do we need our own request? Since we are not + * handling setup requests immediately user space may be so + * slow that another setup will be sent to the gadget but this + * time not to us but another function and then there could be + * a race. Is that the case? Or maybe we can use cdev->req + * after all, maybe we just need some spinlock for that? + */ + struct usb_request *ep0req; /* P: mutex */ + struct completion ep0req_completion; /* P: mutex */ + int ep0req_status; /* P: mutex */ + + /* reference counter */ + atomic_t ref; + /* how many files are opened (EP0 and others) */ + atomic_t opened; + + /* EP0 state */ + enum ffs_state state; + + /* + * Possible transitions: + * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock + * happens only in ep0 read which is P: mutex + * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock + * happens only in ep0 i/o which is P: mutex + * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock + * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg + */ + enum ffs_setup_state setup_state; + +#define FFS_SETUP_STATE(ffs) \ + ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ + FFS_SETUP_CANCELED, FFS_NO_SETUP)) + + /* Events & such. */ + struct { + u8 types[4]; + unsigned short count; + /* XXX REVISIT need to update it in some places, or do we? */ + unsigned short can_stall; + struct usb_ctrlrequest setup; + + wait_queue_head_t waitq; + } ev; /* the whole structure, P: ev.waitq.lock */ + + /* Flags */ + unsigned long flags; +#define FFS_FL_CALL_CLOSED_CALLBACK 0 +#define FFS_FL_BOUND 1 + + /* Active function */ + struct ffs_function *func; + + /* + * Device name, write once when file system is mounted. + * Intended for user to read if she wants. + */ + const char *dev_name; + /* Private data for our user (ie. gadget). Managed by user. */ + void *private_data; + + /* filled by __ffs_data_got_descs() */ + /* + * Real descriptors are 16 bytes after raw_descs (so you need + * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the + * first full speed descriptor). raw_descs_length and + * raw_fs_descs_length do not have those 16 bytes added. + */ + const void *raw_descs; + unsigned raw_descs_length; + unsigned raw_fs_descs_length; + unsigned fs_descs_count; + unsigned hs_descs_count; + + unsigned short strings_count; + unsigned short interfaces_count; + unsigned short eps_count; + unsigned short _pad1; + + /* filled by __ffs_data_got_strings() */ + /* ids in stringtabs are set in functionfs_bind() */ + const void *raw_strings; + struct usb_gadget_strings **stringtabs; + + /* + * File system's super block, write once when file system is + * mounted. + */ + struct super_block *sb; + + /* File permissions, written once when fs is mounted */ + struct ffs_file_perms { + umode_t mode; + uid_t uid; + gid_t gid; + } file_perms; + + /* + * The endpoint files, filled by ffs_epfiles_create(), + * destroyed by ffs_epfiles_destroy(). + */ + struct ffs_epfile *epfiles; +}; + +/* Reference counter handling */ +static void ffs_data_get(struct ffs_data *ffs); +static void ffs_data_put(struct ffs_data *ffs); +/* Creates new ffs_data object. */ +static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc)); + +/* Opened counter handling. */ +static void ffs_data_opened(struct ffs_data *ffs); +static void ffs_data_closed(struct ffs_data *ffs); + +/* Called with ffs->mutex held; take over ownership of data. */ +static int __must_check +__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); +static int __must_check +__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); + + +/* The function structure ***************************************************/ + +struct ffs_ep; + +struct ffs_function { + struct usb_configuration *conf; + struct usb_gadget *gadget; + struct ffs_data *ffs; + + struct ffs_ep *eps; + u8 eps_revmap[16]; + short *interfaces_nums; + + struct usb_function function; +}; + + +static struct ffs_function *ffs_func_from_usb(struct usb_function *f) +{ + return container_of(f, struct ffs_function, function); +} + +static void ffs_func_free(struct ffs_function *func); + +static void ffs_func_eps_disable(struct ffs_function *func); +static int __must_check ffs_func_eps_enable(struct ffs_function *func); + +static int ffs_func_bind(struct usb_configuration *, + struct usb_function *); +static void ffs_func_unbind(struct usb_configuration *, + struct usb_function *); +static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); +static void ffs_func_disable(struct usb_function *); +static int ffs_func_setup(struct usb_function *, + const struct usb_ctrlrequest *); +static void ffs_func_suspend(struct usb_function *); +static void ffs_func_resume(struct usb_function *); + + +static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); +static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); + + +/* The endpoints structures *************************************************/ + +struct ffs_ep { + struct usb_ep *ep; /* P: ffs->eps_lock */ + struct usb_request *req; /* P: epfile->mutex */ + + /* [0]: full speed, [1]: high speed */ + struct usb_endpoint_descriptor *descs[2]; + + u8 num; + + int status; /* P: epfile->mutex */ +}; + +struct ffs_epfile { + /* Protects ep->ep and ep->req. */ + struct mutex mutex; + wait_queue_head_t wait; + + struct ffs_data *ffs; + struct ffs_ep *ep; /* P: ffs->eps_lock */ + + struct dentry *dentry; + + char name[5]; + + unsigned char in; /* P: ffs->eps_lock */ + unsigned char isoc; /* P: ffs->eps_lock */ + + unsigned char _pad; +}; + +static int __must_check ffs_epfiles_create(struct ffs_data *ffs); +static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); + +static struct inode *__must_check +ffs_sb_create_file(struct super_block *sb, const char *name, void *data, + const struct file_operations *fops, + struct dentry **dentry_p); + + +/* Misc helper functions ****************************************************/ + +static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) + __attribute__((warn_unused_result, nonnull)); +static char *ffs_prepare_buffer(const char * __user buf, size_t len) + __attribute__((warn_unused_result, nonnull)); + + +/* Control file aka ep0 *****************************************************/ + +static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct ffs_data *ffs = req->context; + + complete_all(&ffs->ep0req_completion); +} + +static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) +{ + struct usb_request *req = ffs->ep0req; + int ret; + + req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); + + spin_unlock_irq(&ffs->ev.waitq.lock); + + req->buf = data; + req->length = len; + + /* + * UDC layer requires to provide a buffer even for ZLP, but should + * not use it at all. Let's provide some poisoned pointer to catch + * possible bug in the driver. + */ + if (req->buf == NULL) + req->buf = (void *)0xDEADBABE; + + INIT_COMPLETION(ffs->ep0req_completion); + + ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); + if (unlikely(ret < 0)) + return ret; + + ret = wait_for_completion_interruptible(&ffs->ep0req_completion); + if (unlikely(ret)) { + usb_ep_dequeue(ffs->gadget->ep0, req); + return -EINTR; + } + + ffs->setup_state = FFS_NO_SETUP; + return ffs->ep0req_status; +} + +static int __ffs_ep0_stall(struct ffs_data *ffs) +{ + if (ffs->ev.can_stall) { + pr_vdebug("ep0 stall\n"); + usb_ep_set_halt(ffs->gadget->ep0); + ffs->setup_state = FFS_NO_SETUP; + return -EL2HLT; + } else { + pr_debug("bogus ep0 stall!\n"); + return -ESRCH; + } +} + +static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + size_t len, loff_t *ptr) +{ + struct ffs_data *ffs = file->private_data; + ssize_t ret; + char *data; + + ENTER(); + + /* Fast check if setup was canceled */ + if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) + return -EIDRM; + + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); + if (unlikely(ret < 0)) + return ret; + + /* Check state */ + switch (ffs->state) { + case FFS_READ_DESCRIPTORS: + case FFS_READ_STRINGS: + /* Copy data */ + if (unlikely(len < 16)) { + ret = -EINVAL; + break; + } + + data = ffs_prepare_buffer(buf, len); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + break; + } + + /* Handle data */ + if (ffs->state == FFS_READ_DESCRIPTORS) { + pr_info("read descriptors\n"); + ret = __ffs_data_got_descs(ffs, data, len); + if (unlikely(ret < 0)) + break; + + ffs->state = FFS_READ_STRINGS; + ret = len; + } else { + pr_info("read strings\n"); + ret = __ffs_data_got_strings(ffs, data, len); + if (unlikely(ret < 0)) + break; + + ret = ffs_epfiles_create(ffs); + if (unlikely(ret)) { + ffs->state = FFS_CLOSING; + break; + } + + ffs->state = FFS_ACTIVE; + mutex_unlock(&ffs->mutex); + + ret = functionfs_ready_callback(ffs); + if (unlikely(ret < 0)) { + ffs->state = FFS_CLOSING; + return ret; + } + + set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); + return len; + } + break; + + case FFS_ACTIVE: + data = NULL; + /* + * We're called from user space, we can use _irq + * rather then _irqsave + */ + spin_lock_irq(&ffs->ev.waitq.lock); + switch (FFS_SETUP_STATE(ffs)) { + case FFS_SETUP_CANCELED: + ret = -EIDRM; + goto done_spin; + + case FFS_NO_SETUP: + ret = -ESRCH; + goto done_spin; + + case FFS_SETUP_PENDING: + break; + } + + /* FFS_SETUP_PENDING */ + if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { + spin_unlock_irq(&ffs->ev.waitq.lock); + ret = __ffs_ep0_stall(ffs); + break; + } + + /* FFS_SETUP_PENDING and not stall */ + len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); + + spin_unlock_irq(&ffs->ev.waitq.lock); + + data = ffs_prepare_buffer(buf, len); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + break; + } + + spin_lock_irq(&ffs->ev.waitq.lock); + + /* + * We are guaranteed to be still in FFS_ACTIVE state + * but the state of setup could have changed from + * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need + * to check for that. If that happened we copied data + * from user space in vain but it's unlikely. + * + * For sure we are not in FFS_NO_SETUP since this is + * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP + * transition can be performed and it's protected by + * mutex. + */ + if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { + ret = -EIDRM; +done_spin: + spin_unlock_irq(&ffs->ev.waitq.lock); + } else { + /* unlocks spinlock */ + ret = __ffs_ep0_queue_wait(ffs, data, len); + } + kfree(data); + break; + + default: + ret = -EBADFD; + break; + } + + mutex_unlock(&ffs->mutex); + return ret; +} + +static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, + size_t n) +{ + /* + * We are holding ffs->ev.waitq.lock and ffs->mutex and we need + * to release them. + */ + struct usb_functionfs_event events[n]; + unsigned i = 0; + + memset(events, 0, sizeof events); + + do { + events[i].type = ffs->ev.types[i]; + if (events[i].type == FUNCTIONFS_SETUP) { + events[i].u.setup = ffs->ev.setup; + ffs->setup_state = FFS_SETUP_PENDING; + } + } while (++i < n); + + if (n < ffs->ev.count) { + ffs->ev.count -= n; + memmove(ffs->ev.types, ffs->ev.types + n, + ffs->ev.count * sizeof *ffs->ev.types); + } else { + ffs->ev.count = 0; + } + + spin_unlock_irq(&ffs->ev.waitq.lock); + mutex_unlock(&ffs->mutex); + + return unlikely(__copy_to_user(buf, events, sizeof events)) + ? -EFAULT : sizeof events; +} + +static ssize_t ffs_ep0_read(struct file *file, char __user *buf, + size_t len, loff_t *ptr) +{ + struct ffs_data *ffs = file->private_data; + char *data = NULL; + size_t n; + int ret; + + ENTER(); + + /* Fast check if setup was canceled */ + if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) + return -EIDRM; + + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); + if (unlikely(ret < 0)) + return ret; + + /* Check state */ + if (ffs->state != FFS_ACTIVE) { + ret = -EBADFD; + goto done_mutex; + } + + /* + * We're called from user space, we can use _irq rather then + * _irqsave + */ + spin_lock_irq(&ffs->ev.waitq.lock); + + switch (FFS_SETUP_STATE(ffs)) { + case FFS_SETUP_CANCELED: + ret = -EIDRM; + break; + + case FFS_NO_SETUP: + n = len / sizeof(struct usb_functionfs_event); + if (unlikely(!n)) { + ret = -EINVAL; + break; + } + + if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) { + ret = -EAGAIN; + break; + } + + if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, + ffs->ev.count)) { + ret = -EINTR; + break; + } + + return __ffs_ep0_read_events(ffs, buf, + min(n, (size_t)ffs->ev.count)); + + case FFS_SETUP_PENDING: + if (ffs->ev.setup.bRequestType & USB_DIR_IN) { + spin_unlock_irq(&ffs->ev.waitq.lock); + ret = __ffs_ep0_stall(ffs); + goto done_mutex; + } + + len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); + + spin_unlock_irq(&ffs->ev.waitq.lock); + + if (likely(len)) { + data = kmalloc(len, GFP_KERNEL); + if (unlikely(!data)) { + ret = -ENOMEM; + goto done_mutex; + } + } + + spin_lock_irq(&ffs->ev.waitq.lock); + + /* See ffs_ep0_write() */ + if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { + ret = -EIDRM; + break; + } + + /* unlocks spinlock */ + ret = __ffs_ep0_queue_wait(ffs, data, len); + if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len))) + ret = -EFAULT; + goto done_mutex; + + default: + ret = -EBADFD; + break; + } + + spin_unlock_irq(&ffs->ev.waitq.lock); +done_mutex: + mutex_unlock(&ffs->mutex); + kfree(data); + return ret; +} + +static int ffs_ep0_open(struct inode *inode, struct file *file) +{ + struct ffs_data *ffs = inode->i_private; + + ENTER(); + + if (unlikely(ffs->state == FFS_CLOSING)) + return -EBUSY; + + file->private_data = ffs; + ffs_data_opened(ffs); + + return 0; +} + +static int ffs_ep0_release(struct inode *inode, struct file *file) +{ + struct ffs_data *ffs = file->private_data; + + ENTER(); + + ffs_data_closed(ffs); + + return 0; +} + +static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) +{ + struct ffs_data *ffs = file->private_data; + struct usb_gadget *gadget = ffs->gadget; + long ret; + + ENTER(); + + if (code == FUNCTIONFS_INTERFACE_REVMAP) { + struct ffs_function *func = ffs->func; + ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; + } else if (gadget && gadget->ops->ioctl) { + ret = gadget->ops->ioctl(gadget, code, value); + } else { + ret = -ENOTTY; + } + + return ret; +} + +static const struct file_operations ffs_ep0_operations = { + .owner = THIS_MODULE, + .llseek = no_llseek, + + .open = ffs_ep0_open, + .write = ffs_ep0_write, + .read = ffs_ep0_read, + .release = ffs_ep0_release, + .unlocked_ioctl = ffs_ep0_ioctl, +}; + + +/* "Normal" endpoints operations ********************************************/ + +static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) +{ + ENTER(); + if (likely(req->context)) { + struct ffs_ep *ep = _ep->driver_data; + ep->status = req->status ? req->status : req->actual; + complete(req->context); + } +} + +static ssize_t ffs_epfile_io(struct file *file, + char __user *buf, size_t len, int read) +{ + struct ffs_epfile *epfile = file->private_data; + struct ffs_ep *ep; + char *data = NULL; + ssize_t ret; + int halt; + + goto first_try; + do { + spin_unlock_irq(&epfile->ffs->eps_lock); + mutex_unlock(&epfile->mutex); + +first_try: + /* Are we still active? */ + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { + ret = -ENODEV; + goto error; + } + + /* Wait for endpoint to be enabled */ + ep = epfile->ep; + if (!ep) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto error; + } + + if (wait_event_interruptible(epfile->wait, + (ep = epfile->ep))) { + ret = -EINTR; + goto error; + } + } + + /* Do we halt? */ + halt = !read == !epfile->in; + if (halt && epfile->isoc) { + ret = -EINVAL; + goto error; + } + + /* Allocate & copy */ + if (!halt && !data) { + data = kzalloc(len, GFP_KERNEL); + if (unlikely(!data)) + return -ENOMEM; + + if (!read && + unlikely(__copy_from_user(data, buf, len))) { + ret = -EFAULT; + goto error; + } + } + + /* We will be using request */ + ret = ffs_mutex_lock(&epfile->mutex, + file->f_flags & O_NONBLOCK); + if (unlikely(ret)) + goto error; + + /* + * We're called from user space, we can use _irq rather then + * _irqsave + */ + spin_lock_irq(&epfile->ffs->eps_lock); + + /* + * While we were acquiring mutex endpoint got disabled + * or changed? + */ + } while (unlikely(epfile->ep != ep)); + + /* Halt */ + if (unlikely(halt)) { + if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) + usb_ep_set_halt(ep->ep); + spin_unlock_irq(&epfile->ffs->eps_lock); + ret = -EBADMSG; + } else { + /* Fire the request */ + DECLARE_COMPLETION_ONSTACK(done); + + struct usb_request *req = ep->req; + req->context = &done; + req->complete = ffs_epfile_io_complete; + req->buf = data; + req->length = len; + + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + + spin_unlock_irq(&epfile->ffs->eps_lock); + + if (unlikely(ret < 0)) { + /* nop */ + } else if (unlikely(wait_for_completion_interruptible(&done))) { + ret = -EINTR; + usb_ep_dequeue(ep->ep, req); + } else { + ret = ep->status; + if (read && ret > 0 && + unlikely(copy_to_user(buf, data, ret))) + ret = -EFAULT; + } + } + + mutex_unlock(&epfile->mutex); +error: + kfree(data); + return ret; +} + +static ssize_t +ffs_epfile_write(struct file *file, const char __user *buf, size_t len, + loff_t *ptr) +{ + ENTER(); + + return ffs_epfile_io(file, (char __user *)buf, len, 0); +} + +static ssize_t +ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) +{ + ENTER(); + + return ffs_epfile_io(file, buf, len, 1); +} + +static int +ffs_epfile_open(struct inode *inode, struct file *file) +{ + struct ffs_epfile *epfile = inode->i_private; + + ENTER(); + + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) + return -ENODEV; + + file->private_data = epfile; + ffs_data_opened(epfile->ffs); + + return 0; +} + +static int +ffs_epfile_release(struct inode *inode, struct file *file) +{ + struct ffs_epfile *epfile = inode->i_private; + + ENTER(); + + ffs_data_closed(epfile->ffs); + + return 0; +} + +static long ffs_epfile_ioctl(struct file *file, unsigned code, + unsigned long value) +{ + struct ffs_epfile *epfile = file->private_data; + int ret; + + ENTER(); + + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) + return -ENODEV; + + spin_lock_irq(&epfile->ffs->eps_lock); + if (likely(epfile->ep)) { + switch (code) { + case FUNCTIONFS_FIFO_STATUS: + ret = usb_ep_fifo_status(epfile->ep->ep); + break; + case FUNCTIONFS_FIFO_FLUSH: + usb_ep_fifo_flush(epfile->ep->ep); + ret = 0; + break; + case FUNCTIONFS_CLEAR_HALT: + ret = usb_ep_clear_halt(epfile->ep->ep); + break; + case FUNCTIONFS_ENDPOINT_REVMAP: + ret = epfile->ep->num; + break; + default: + ret = -ENOTTY; + } + } else { + ret = -ENODEV; + } + spin_unlock_irq(&epfile->ffs->eps_lock); + + return ret; +} + +static const struct file_operations ffs_epfile_operations = { + .owner = THIS_MODULE, + .llseek = no_llseek, + + .open = ffs_epfile_open, + .write = ffs_epfile_write, + .read = ffs_epfile_read, + .release = ffs_epfile_release, + .unlocked_ioctl = ffs_epfile_ioctl, +}; + + +/* File system and super block operations ***********************************/ + +/* + * Mounting the file system creates a controller file, used first for + * function configuration then later for event monitoring. + */ + +static struct inode *__must_check +ffs_sb_make_inode(struct super_block *sb, void *data, + const struct file_operations *fops, + const struct inode_operations *iops, + struct ffs_file_perms *perms) +{ + struct inode *inode; + + ENTER(); + + inode = new_inode(sb); + + if (likely(inode)) { + struct timespec current_time = CURRENT_TIME; + + inode->i_ino = get_next_ino(); + inode->i_mode = perms->mode; + inode->i_uid = perms->uid; + inode->i_gid = perms->gid; + inode->i_atime = current_time; + inode->i_mtime = current_time; + inode->i_ctime = current_time; + inode->i_private = data; + if (fops) + inode->i_fop = fops; + if (iops) + inode->i_op = iops; + } + + return inode; +} + +/* Create "regular" file */ +static struct inode *ffs_sb_create_file(struct super_block *sb, + const char *name, void *data, + const struct file_operations *fops, + struct dentry **dentry_p) +{ + struct ffs_data *ffs = sb->s_fs_info; + struct dentry *dentry; + struct inode *inode; + + ENTER(); + + dentry = d_alloc_name(sb->s_root, name); + if (unlikely(!dentry)) + return NULL; + + inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); + if (unlikely(!inode)) { + dput(dentry); + return NULL; + } + + d_add(dentry, inode); + if (dentry_p) + *dentry_p = dentry; + + return inode; +} + +/* Super block */ +static const struct super_operations ffs_sb_operations = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +struct ffs_sb_fill_data { + struct ffs_file_perms perms; + umode_t root_mode; + const char *dev_name; + union { + /* set by ffs_fs_mount(), read by ffs_sb_fill() */ + void *private_data; + /* set by ffs_sb_fill(), read by ffs_fs_mount */ + struct ffs_data *ffs_data; + }; +}; + +static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) +{ + struct ffs_sb_fill_data *data = _data; + struct inode *inode; + struct ffs_data *ffs; + + ENTER(); + + /* Initialise data */ + ffs = ffs_data_new(); + if (unlikely(!ffs)) + goto Enomem; + + ffs->sb = sb; + ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL); + if (unlikely(!ffs->dev_name)) + goto Enomem; + ffs->file_perms = data->perms; + ffs->private_data = data->private_data; + + /* used by the caller of this function */ + data->ffs_data = ffs; + + sb->s_fs_info = ffs; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = FUNCTIONFS_MAGIC; + sb->s_op = &ffs_sb_operations; + sb->s_time_gran = 1; + + /* Root inode */ + data->perms.mode = data->root_mode; + inode = ffs_sb_make_inode(sb, NULL, + &simple_dir_operations, + &simple_dir_inode_operations, + &data->perms); + sb->s_root = d_make_root(inode); + if (unlikely(!sb->s_root)) + goto Enomem; + + /* EP0 file */ + if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, + &ffs_ep0_operations, NULL))) + goto Enomem; + + return 0; + +Enomem: + return -ENOMEM; +} + +static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) +{ + ENTER(); + + if (!opts || !*opts) + return 0; + + for (;;) { + char *end, *eq, *comma; + unsigned long value; + + /* Option limit */ + comma = strchr(opts, ','); + if (comma) + *comma = 0; + + /* Value limit */ + eq = strchr(opts, '='); + if (unlikely(!eq)) { + pr_err("'=' missing in %s\n", opts); + return -EINVAL; + } + *eq = 0; + + /* Parse value */ + value = simple_strtoul(eq + 1, &end, 0); + if (unlikely(*end != ',' && *end != 0)) { + pr_err("%s: invalid value: %s\n", opts, eq + 1); + return -EINVAL; + } + + /* Interpret option */ + switch (eq - opts) { + case 5: + if (!memcmp(opts, "rmode", 5)) + data->root_mode = (value & 0555) | S_IFDIR; + else if (!memcmp(opts, "fmode", 5)) + data->perms.mode = (value & 0666) | S_IFREG; + else + goto invalid; + break; + + case 4: + if (!memcmp(opts, "mode", 4)) { + data->root_mode = (value & 0555) | S_IFDIR; + data->perms.mode = (value & 0666) | S_IFREG; + } else { + goto invalid; + } + break; + + case 3: + if (!memcmp(opts, "uid", 3)) + data->perms.uid = value; + else if (!memcmp(opts, "gid", 3)) + data->perms.gid = value; + else + goto invalid; + break; + + default: +invalid: + pr_err("%s: invalid option\n", opts); + return -EINVAL; + } + + /* Next iteration */ + if (!comma) + break; + opts = comma + 1; + } + + return 0; +} + +/* "mount -t functionfs dev_name /dev/function" ends up here */ + +static struct dentry * +ffs_fs_mount(struct file_system_type *t, int flags, + const char *dev_name, void *opts) +{ + struct ffs_sb_fill_data data = { + .perms = { + .mode = S_IFREG | 0600, + .uid = 0, + .gid = 0 + }, + .root_mode = S_IFDIR | 0500, + }; + struct dentry *rv; + int ret; + void *ffs_dev; + + ENTER(); + + ret = ffs_fs_parse_opts(&data, opts); + if (unlikely(ret < 0)) + return ERR_PTR(ret); + + ffs_dev = functionfs_acquire_dev_callback(dev_name); + if (IS_ERR(ffs_dev)) + return ffs_dev; + + data.dev_name = dev_name; + data.private_data = ffs_dev; + rv = mount_nodev(t, flags, &data, ffs_sb_fill); + + /* data.ffs_data is set by ffs_sb_fill */ + if (IS_ERR(rv)) + functionfs_release_dev_callback(data.ffs_data); + + return rv; +} + +static void +ffs_fs_kill_sb(struct super_block *sb) +{ + ENTER(); + + kill_litter_super(sb); + if (sb->s_fs_info) { + functionfs_release_dev_callback(sb->s_fs_info); + ffs_data_put(sb->s_fs_info); + } +} + +static struct file_system_type ffs_fs_type = { + .owner = THIS_MODULE, + .name = "functionfs", + .mount = ffs_fs_mount, + .kill_sb = ffs_fs_kill_sb, +}; + + +/* Driver's main init/cleanup functions *************************************/ + +static int functionfs_init(void) +{ + int ret; + + ENTER(); + + ret = register_filesystem(&ffs_fs_type); + if (likely(!ret)) + pr_info("file system registered\n"); + else + pr_err("failed registering file system (%d)\n", ret); + + return ret; +} + +static void functionfs_cleanup(void) +{ + ENTER(); + + pr_info("unloading\n"); + unregister_filesystem(&ffs_fs_type); +} + + +/* ffs_data and ffs_function construction and destruction code **************/ + +static void ffs_data_clear(struct ffs_data *ffs); +static void ffs_data_reset(struct ffs_data *ffs); + +static void ffs_data_get(struct ffs_data *ffs) +{ + ENTER(); + + atomic_inc(&ffs->ref); +} + +static void ffs_data_opened(struct ffs_data *ffs) +{ + ENTER(); + + atomic_inc(&ffs->ref); + atomic_inc(&ffs->opened); +} + +static void ffs_data_put(struct ffs_data *ffs) +{ + ENTER(); + + if (unlikely(atomic_dec_and_test(&ffs->ref))) { + pr_info("%s(): freeing\n", __func__); + ffs_data_clear(ffs); + BUG_ON(waitqueue_active(&ffs->ev.waitq) || + waitqueue_active(&ffs->ep0req_completion.wait)); + kfree(ffs->dev_name); + kfree(ffs); + } +} + +static void ffs_data_closed(struct ffs_data *ffs) +{ + ENTER(); + + if (atomic_dec_and_test(&ffs->opened)) { + ffs->state = FFS_CLOSING; + ffs_data_reset(ffs); + } + + ffs_data_put(ffs); +} + +static struct ffs_data *ffs_data_new(void) +{ + struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); + if (unlikely(!ffs)) + return 0; + + ENTER(); + + atomic_set(&ffs->ref, 1); + atomic_set(&ffs->opened, 0); + ffs->state = FFS_READ_DESCRIPTORS; + mutex_init(&ffs->mutex); + spin_lock_init(&ffs->eps_lock); + init_waitqueue_head(&ffs->ev.waitq); + init_completion(&ffs->ep0req_completion); + + /* XXX REVISIT need to update it in some places, or do we? */ + ffs->ev.can_stall = 1; + + return ffs; +} + +static void ffs_data_clear(struct ffs_data *ffs) +{ + ENTER(); + + if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) + functionfs_closed_callback(ffs); + + BUG_ON(ffs->gadget); + + if (ffs->epfiles) + ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); + + kfree(ffs->raw_descs); + kfree(ffs->raw_strings); + kfree(ffs->stringtabs); +} + +static void ffs_data_reset(struct ffs_data *ffs) +{ + ENTER(); + + ffs_data_clear(ffs); + + ffs->epfiles = NULL; + ffs->raw_descs = NULL; + ffs->raw_strings = NULL; + ffs->stringtabs = NULL; + + ffs->raw_descs_length = 0; + ffs->raw_fs_descs_length = 0; + ffs->fs_descs_count = 0; + ffs->hs_descs_count = 0; + + ffs->strings_count = 0; + ffs->interfaces_count = 0; + ffs->eps_count = 0; + + ffs->ev.count = 0; + + ffs->state = FFS_READ_DESCRIPTORS; + ffs->setup_state = FFS_NO_SETUP; + ffs->flags = 0; +} + + +static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) +{ + struct usb_gadget_strings **lang; + int first_id; + + ENTER(); + + if (WARN_ON(ffs->state != FFS_ACTIVE + || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) + return -EBADFD; + + first_id = usb_string_ids_n(cdev, ffs->strings_count); + if (unlikely(first_id < 0)) + return first_id; + + ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); + if (unlikely(!ffs->ep0req)) + return -ENOMEM; + ffs->ep0req->complete = ffs_ep0_complete; + ffs->ep0req->context = ffs; + + lang = ffs->stringtabs; + for (lang = ffs->stringtabs; *lang; ++lang) { + struct usb_string *str = (*lang)->strings; + int id = first_id; + for (; str->s; ++id, ++str) + str->id = id; + } + + ffs->gadget = cdev->gadget; + ffs_data_get(ffs); + return 0; +} + +static void functionfs_unbind(struct ffs_data *ffs) +{ + ENTER(); + + if (!WARN_ON(!ffs->gadget)) { + usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); + ffs->ep0req = NULL; + ffs->gadget = NULL; + ffs_data_put(ffs); + clear_bit(FFS_FL_BOUND, &ffs->flags); + } +} + +static int ffs_epfiles_create(struct ffs_data *ffs) +{ + struct ffs_epfile *epfile, *epfiles; + unsigned i, count; + + ENTER(); + + count = ffs->eps_count; + epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); + if (!epfiles) + return -ENOMEM; + + epfile = epfiles; + for (i = 1; i <= count; ++i, ++epfile) { + epfile->ffs = ffs; + mutex_init(&epfile->mutex); + init_waitqueue_head(&epfile->wait); + sprintf(epfiles->name, "ep%u", i); + if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile, + &ffs_epfile_operations, + &epfile->dentry))) { + ffs_epfiles_destroy(epfiles, i - 1); + return -ENOMEM; + } + } + + ffs->epfiles = epfiles; + return 0; +} + +static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) +{ + struct ffs_epfile *epfile = epfiles; + + ENTER(); + + for (; count; --count, ++epfile) { + BUG_ON(mutex_is_locked(&epfile->mutex) || + waitqueue_active(&epfile->wait)); + if (epfile->dentry) { + d_delete(epfile->dentry); + dput(epfile->dentry); + epfile->dentry = NULL; + } + } + + kfree(epfiles); +} + +static int functionfs_bind_config(struct usb_composite_dev *cdev, + struct usb_configuration *c, + struct ffs_data *ffs) +{ + struct ffs_function *func; + int ret; + + ENTER(); + + func = kzalloc(sizeof *func, GFP_KERNEL); + if (unlikely(!func)) + return -ENOMEM; + + func->function.name = "Function FS Gadget"; + func->function.strings = ffs->stringtabs; + + func->function.bind = ffs_func_bind; + func->function.unbind = ffs_func_unbind; + func->function.set_alt = ffs_func_set_alt; + func->function.disable = ffs_func_disable; + func->function.setup = ffs_func_setup; + func->function.suspend = ffs_func_suspend; + func->function.resume = ffs_func_resume; + + func->conf = c; + func->gadget = cdev->gadget; + func->ffs = ffs; + ffs_data_get(ffs); + + ret = usb_add_function(c, &func->function); + if (unlikely(ret)) + ffs_func_free(func); + + return ret; +} + +static void ffs_func_free(struct ffs_function *func) +{ + struct ffs_ep *ep = func->eps; + unsigned count = func->ffs->eps_count; + unsigned long flags; + + ENTER(); + + /* cleanup after autoconfig */ + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + if (ep->ep && ep->req) + usb_ep_free_request(ep->ep, ep->req); + ep->req = NULL; + ++ep; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + + ffs_data_put(func->ffs); + + kfree(func->eps); + /* + * eps and interfaces_nums are allocated in the same chunk so + * only one free is required. Descriptors are also allocated + * in the same chunk. + */ + + kfree(func); +} + +static void ffs_func_eps_disable(struct ffs_function *func) +{ + struct ffs_ep *ep = func->eps; + struct ffs_epfile *epfile = func->ffs->epfiles; + unsigned count = func->ffs->eps_count; + unsigned long flags; + + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + /* pending requests get nuked */ + if (likely(ep->ep)) + usb_ep_disable(ep->ep); + epfile->ep = NULL; + + ++ep; + ++epfile; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); +} + +static int ffs_func_eps_enable(struct ffs_function *func) +{ + struct ffs_data *ffs = func->ffs; + struct ffs_ep *ep = func->eps; + struct ffs_epfile *epfile = ffs->epfiles; + unsigned count = ffs->eps_count; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + struct usb_endpoint_descriptor *ds; + ds = ep->descs[ep->descs[1] ? 1 : 0]; + + ep->ep->driver_data = ep; + ep->ep->desc = ds; + ret = usb_ep_enable(ep->ep); + if (likely(!ret)) { + epfile->ep = ep; + epfile->in = usb_endpoint_dir_in(ds); + epfile->isoc = usb_endpoint_xfer_isoc(ds); + } else { + break; + } + + wake_up(&epfile->wait); + + ++ep; + ++epfile; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + + return ret; +} + + +/* Parsing and building descriptors and strings *****************************/ + +/* + * This validates if data pointed by data is a valid USB descriptor as + * well as record how many interfaces, endpoints and strings are + * required by given configuration. Returns address after the + * descriptor or NULL if data is invalid. + */ + +enum ffs_entity_type { + FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT +}; + +typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, + u8 *valuep, + struct usb_descriptor_header *desc, + void *priv); + +static int __must_check ffs_do_desc(char *data, unsigned len, + ffs_entity_callback entity, void *priv) +{ + struct usb_descriptor_header *_ds = (void *)data; + u8 length; + int ret; + + ENTER(); + + /* At least two bytes are required: length and type */ + if (len < 2) { + pr_vdebug("descriptor too short\n"); + return -EINVAL; + } + + /* If we have at least as many bytes as the descriptor takes? */ + length = _ds->bLength; + if (len < length) { + pr_vdebug("descriptor longer then available data\n"); + return -EINVAL; + } + +#define __entity_check_INTERFACE(val) 1 +#define __entity_check_STRING(val) (val) +#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK) +#define __entity(type, val) do { \ + pr_vdebug("entity " #type "(%02x)\n", (val)); \ + if (unlikely(!__entity_check_ ##type(val))) { \ + pr_vdebug("invalid entity's value\n"); \ + return -EINVAL; \ + } \ + ret = entity(FFS_ ##type, &val, _ds, priv); \ + if (unlikely(ret < 0)) { \ + pr_debug("entity " #type "(%02x); ret = %d\n", \ + (val), ret); \ + return ret; \ + } \ + } while (0) + + /* Parse descriptor depending on type. */ + switch (_ds->bDescriptorType) { + case USB_DT_DEVICE: + case USB_DT_CONFIG: + case USB_DT_STRING: + case USB_DT_DEVICE_QUALIFIER: + /* function can't have any of those */ + pr_vdebug("descriptor reserved for gadget: %d\n", + _ds->bDescriptorType); + return -EINVAL; + + case USB_DT_INTERFACE: { + struct usb_interface_descriptor *ds = (void *)_ds; + pr_vdebug("interface descriptor\n"); + if (length != sizeof *ds) + goto inv_length; + + __entity(INTERFACE, ds->bInterfaceNumber); + if (ds->iInterface) + __entity(STRING, ds->iInterface); + } + break; + + case USB_DT_ENDPOINT: { + struct usb_endpoint_descriptor *ds = (void *)_ds; + pr_vdebug("endpoint descriptor\n"); + if (length != USB_DT_ENDPOINT_SIZE && + length != USB_DT_ENDPOINT_AUDIO_SIZE) + goto inv_length; + __entity(ENDPOINT, ds->bEndpointAddress); + } + break; + + case HID_DT_HID: + pr_vdebug("hid descriptor\n"); + if (length != sizeof(struct hid_descriptor)) + goto inv_length; + break; + + case USB_DT_OTG: + if (length != sizeof(struct usb_otg_descriptor)) + goto inv_length; + break; + + case USB_DT_INTERFACE_ASSOCIATION: { + struct usb_interface_assoc_descriptor *ds = (void *)_ds; + pr_vdebug("interface association descriptor\n"); + if (length != sizeof *ds) + goto inv_length; + if (ds->iFunction) + __entity(STRING, ds->iFunction); + } + break; + + case USB_DT_OTHER_SPEED_CONFIG: + case USB_DT_INTERFACE_POWER: + case USB_DT_DEBUG: + case USB_DT_SECURITY: + case USB_DT_CS_RADIO_CONTROL: + /* TODO */ + pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); + return -EINVAL; + + default: + /* We should never be here */ + pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); + return -EINVAL; + +inv_length: + pr_vdebug("invalid length: %d (descriptor %d)\n", + _ds->bLength, _ds->bDescriptorType); + return -EINVAL; + } + +#undef __entity +#undef __entity_check_DESCRIPTOR +#undef __entity_check_INTERFACE +#undef __entity_check_STRING +#undef __entity_check_ENDPOINT + + return length; +} + +static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, + ffs_entity_callback entity, void *priv) +{ + const unsigned _len = len; + unsigned long num = 0; + + ENTER(); + + for (;;) { + int ret; + + if (num == count) + data = NULL; + + /* Record "descriptor" entity */ + ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); + if (unlikely(ret < 0)) { + pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", + num, ret); + return ret; + } + + if (!data) + return _len - len; + + ret = ffs_do_desc(data, len, entity, priv); + if (unlikely(ret < 0)) { + pr_debug("%s returns %d\n", __func__, ret); + return ret; + } + + len -= ret; + data += ret; + ++num; + } +} + +static int __ffs_data_do_entity(enum ffs_entity_type type, + u8 *valuep, struct usb_descriptor_header *desc, + void *priv) +{ + struct ffs_data *ffs = priv; + + ENTER(); + + switch (type) { + case FFS_DESCRIPTOR: + break; + + case FFS_INTERFACE: + /* + * Interfaces are indexed from zero so if we + * encountered interface "n" then there are at least + * "n+1" interfaces. + */ + if (*valuep >= ffs->interfaces_count) + ffs->interfaces_count = *valuep + 1; + break; + + case FFS_STRING: + /* + * Strings are indexed from 1 (0 is magic ;) reserved + * for languages list or some such) + */ + if (*valuep > ffs->strings_count) + ffs->strings_count = *valuep; + break; + + case FFS_ENDPOINT: + /* Endpoints are indexed from 1 as well. */ + if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count) + ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK); + break; + } + + return 0; +} + +static int __ffs_data_got_descs(struct ffs_data *ffs, + char *const _data, size_t len) +{ + unsigned fs_count, hs_count; + int fs_len, ret = -EINVAL; + char *data = _data; + + ENTER(); + + if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || + get_unaligned_le32(data + 4) != len)) + goto error; + fs_count = get_unaligned_le32(data + 8); + hs_count = get_unaligned_le32(data + 12); + + if (!fs_count && !hs_count) + goto einval; + + data += 16; + len -= 16; + + if (likely(fs_count)) { + fs_len = ffs_do_descs(fs_count, data, len, + __ffs_data_do_entity, ffs); + if (unlikely(fs_len < 0)) { + ret = fs_len; + goto error; + } + + data += fs_len; + len -= fs_len; + } else { + fs_len = 0; + } + + if (likely(hs_count)) { + ret = ffs_do_descs(hs_count, data, len, + __ffs_data_do_entity, ffs); + if (unlikely(ret < 0)) + goto error; + } else { + ret = 0; + } + + if (unlikely(len != ret)) + goto einval; + + ffs->raw_fs_descs_length = fs_len; + ffs->raw_descs_length = fs_len + ret; + ffs->raw_descs = _data; + ffs->fs_descs_count = fs_count; + ffs->hs_descs_count = hs_count; + + return 0; + +einval: + ret = -EINVAL; +error: + kfree(_data); + return ret; +} + +static int __ffs_data_got_strings(struct ffs_data *ffs, + char *const _data, size_t len) +{ + u32 str_count, needed_count, lang_count; + struct usb_gadget_strings **stringtabs, *t; + struct usb_string *strings, *s; + const char *data = _data; + + ENTER(); + + if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || + get_unaligned_le32(data + 4) != len)) + goto error; + str_count = get_unaligned_le32(data + 8); + lang_count = get_unaligned_le32(data + 12); + + /* if one is zero the other must be zero */ + if (unlikely(!str_count != !lang_count)) + goto error; + + /* Do we have at least as many strings as descriptors need? */ + needed_count = ffs->strings_count; + if (unlikely(str_count < needed_count)) + goto error; + + /* + * If we don't need any strings just return and free all + * memory. + */ + if (!needed_count) { + kfree(_data); + return 0; + } + + /* Allocate everything in one chunk so there's less maintenance. */ + { + struct { + struct usb_gadget_strings *stringtabs[lang_count + 1]; + struct usb_gadget_strings stringtab[lang_count]; + struct usb_string strings[lang_count*(needed_count+1)]; + } *d; + unsigned i = 0; + + d = kmalloc(sizeof *d, GFP_KERNEL); + if (unlikely(!d)) { + kfree(_data); + return -ENOMEM; + } + + stringtabs = d->stringtabs; + t = d->stringtab; + i = lang_count; + do { + *stringtabs++ = t++; + } while (--i); + *stringtabs = NULL; + + stringtabs = d->stringtabs; + t = d->stringtab; + s = d->strings; + strings = s; + } + + /* For each language */ + data += 16; + len -= 16; + + do { /* lang_count > 0 so we can use do-while */ + unsigned needed = needed_count; + + if (unlikely(len < 3)) + goto error_free; + t->language = get_unaligned_le16(data); + t->strings = s; + ++t; + + data += 2; + len -= 2; + + /* For each string */ + do { /* str_count > 0 so we can use do-while */ + size_t length = strnlen(data, len); + + if (unlikely(length == len)) + goto error_free; + + /* + * User may provide more strings then we need, + * if that's the case we simply ignore the + * rest + */ + if (likely(needed)) { + /* + * s->id will be set while adding + * function to configuration so for + * now just leave garbage here. + */ + s->s = data; + --needed; + ++s; + } + + data += length + 1; + len -= length + 1; + } while (--str_count); + + s->id = 0; /* terminator */ + s->s = NULL; + ++s; + + } while (--lang_count); + + /* Some garbage left? */ + if (unlikely(len)) + goto error_free; + + /* Done! */ + ffs->stringtabs = stringtabs; + ffs->raw_strings = _data; + + return 0; + +error_free: + kfree(stringtabs); +error: + kfree(_data); + return -EINVAL; +} + + +/* Events handling and management *******************************************/ + +static void __ffs_event_add(struct ffs_data *ffs, + enum usb_functionfs_event_type type) +{ + enum usb_functionfs_event_type rem_type1, rem_type2 = type; + int neg = 0; + + /* + * Abort any unhandled setup + * + * We do not need to worry about some cmpxchg() changing value + * of ffs->setup_state without holding the lock because when + * state is FFS_SETUP_PENDING cmpxchg() in several places in + * the source does nothing. + */ + if (ffs->setup_state == FFS_SETUP_PENDING) + ffs->setup_state = FFS_SETUP_CANCELED; + + switch (type) { + case FUNCTIONFS_RESUME: + rem_type2 = FUNCTIONFS_SUSPEND; + /* FALL THROUGH */ + case FUNCTIONFS_SUSPEND: + case FUNCTIONFS_SETUP: + rem_type1 = type; + /* Discard all similar events */ + break; + + case FUNCTIONFS_BIND: + case FUNCTIONFS_UNBIND: + case FUNCTIONFS_DISABLE: + case FUNCTIONFS_ENABLE: + /* Discard everything other then power management. */ + rem_type1 = FUNCTIONFS_SUSPEND; + rem_type2 = FUNCTIONFS_RESUME; + neg = 1; + break; + + default: + BUG(); + } + + { + u8 *ev = ffs->ev.types, *out = ev; + unsigned n = ffs->ev.count; + for (; n; --n, ++ev) + if ((*ev == rem_type1 || *ev == rem_type2) == neg) + *out++ = *ev; + else + pr_vdebug("purging event %d\n", *ev); + ffs->ev.count = out - ffs->ev.types; + } + + pr_vdebug("adding event %d\n", type); + ffs->ev.types[ffs->ev.count++] = type; + wake_up_locked(&ffs->ev.waitq); +} + +static void ffs_event_add(struct ffs_data *ffs, + enum usb_functionfs_event_type type) +{ + unsigned long flags; + spin_lock_irqsave(&ffs->ev.waitq.lock, flags); + __ffs_event_add(ffs, type); + spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); +} + + +/* Bind/unbind USB function hooks *******************************************/ + +static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, + struct usb_descriptor_header *desc, + void *priv) +{ + struct usb_endpoint_descriptor *ds = (void *)desc; + struct ffs_function *func = priv; + struct ffs_ep *ffs_ep; + + /* + * If hs_descriptors is not NULL then we are reading hs + * descriptors now + */ + const int isHS = func->function.hs_descriptors != NULL; + unsigned idx; + + if (type != FFS_DESCRIPTOR) + return 0; + + if (isHS) + func->function.hs_descriptors[(long)valuep] = desc; + else + func->function.descriptors[(long)valuep] = desc; + + if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) + return 0; + + idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; + ffs_ep = func->eps + idx; + + if (unlikely(ffs_ep->descs[isHS])) { + pr_vdebug("two %sspeed descriptors for EP %d\n", + isHS ? "high" : "full", + ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + return -EINVAL; + } + ffs_ep->descs[isHS] = ds; + + ffs_dump_mem(": Original ep desc", ds, ds->bLength); + if (ffs_ep->ep) { + ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; + if (!ds->wMaxPacketSize) + ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize; + } else { + struct usb_request *req; + struct usb_ep *ep; + + pr_vdebug("autoconfig\n"); + ep = usb_ep_autoconfig(func->gadget, ds); + if (unlikely(!ep)) + return -ENOTSUPP; + ep->driver_data = func->eps + idx; + + req = usb_ep_alloc_request(ep, GFP_KERNEL); + if (unlikely(!req)) + return -ENOMEM; + + ffs_ep->ep = ep; + ffs_ep->req = req; + func->eps_revmap[ds->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK] = idx + 1; + } + ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); + + return 0; +} + +static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, + struct usb_descriptor_header *desc, + void *priv) +{ + struct ffs_function *func = priv; + unsigned idx; + u8 newValue; + + switch (type) { + default: + case FFS_DESCRIPTOR: + /* Handled in previous pass by __ffs_func_bind_do_descs() */ + return 0; + + case FFS_INTERFACE: + idx = *valuep; + if (func->interfaces_nums[idx] < 0) { + int id = usb_interface_id(func->conf, &func->function); + if (unlikely(id < 0)) + return id; + func->interfaces_nums[idx] = id; + } + newValue = func->interfaces_nums[idx]; + break; + + case FFS_STRING: + /* String' IDs are allocated when fsf_data is bound to cdev */ + newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; + break; + + case FFS_ENDPOINT: + /* + * USB_DT_ENDPOINT are handled in + * __ffs_func_bind_do_descs(). + */ + if (desc->bDescriptorType == USB_DT_ENDPOINT) + return 0; + + idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; + if (unlikely(!func->eps[idx].ep)) + return -EINVAL; + + { + struct usb_endpoint_descriptor **descs; + descs = func->eps[idx].descs; + newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress; + } + break; + } + + pr_vdebug("%02x -> %02x\n", *valuep, newValue); + *valuep = newValue; + return 0; +} + +static int ffs_func_bind(struct usb_configuration *c, + struct usb_function *f) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; + + const int full = !!func->ffs->fs_descs_count; + const int high = gadget_is_dualspeed(func->gadget) && + func->ffs->hs_descs_count; + + int ret; + + /* Make it a single chunk, less management later on */ + struct { + struct ffs_ep eps[ffs->eps_count]; + struct usb_descriptor_header + *fs_descs[full ? ffs->fs_descs_count + 1 : 0]; + struct usb_descriptor_header + *hs_descs[high ? ffs->hs_descs_count + 1 : 0]; + short inums[ffs->interfaces_count]; + char raw_descs[high ? ffs->raw_descs_length + : ffs->raw_fs_descs_length]; + } *data; + + ENTER(); + + /* Only high speed but not supported by gadget? */ + if (unlikely(!(full | high))) + return -ENOTSUPP; + + /* Allocate */ + data = kmalloc(sizeof *data, GFP_KERNEL); + if (unlikely(!data)) + return -ENOMEM; + + /* Zero */ + memset(data->eps, 0, sizeof data->eps); + memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs); + memset(data->inums, 0xff, sizeof data->inums); + for (ret = ffs->eps_count; ret; --ret) + data->eps[ret].num = -1; + + /* Save pointers */ + func->eps = data->eps; + func->interfaces_nums = data->inums; + + /* + * Go through all the endpoint descriptors and allocate + * endpoints first, so that later we can rewrite the endpoint + * numbers without worrying that it may be described later on. + */ + if (likely(full)) { + func->function.descriptors = data->fs_descs; + ret = ffs_do_descs(ffs->fs_descs_count, + data->raw_descs, + sizeof data->raw_descs, + __ffs_func_bind_do_descs, func); + if (unlikely(ret < 0)) + goto error; + } else { + ret = 0; + } + + if (likely(high)) { + func->function.hs_descriptors = data->hs_descs; + ret = ffs_do_descs(ffs->hs_descs_count, + data->raw_descs + ret, + (sizeof data->raw_descs) - ret, + __ffs_func_bind_do_descs, func); + } + + /* + * Now handle interface numbers allocation and interface and + * endpoint numbers rewriting. We can do that in one go + * now. + */ + ret = ffs_do_descs(ffs->fs_descs_count + + (high ? ffs->hs_descs_count : 0), + data->raw_descs, sizeof data->raw_descs, + __ffs_func_bind_do_nums, func); + if (unlikely(ret < 0)) + goto error; + + /* And we're done */ + ffs_event_add(ffs, FUNCTIONFS_BIND); + return 0; + +error: + /* XXX Do we need to release all claimed endpoints here? */ + return ret; +} + + +/* Other USB function hooks *************************************************/ + +static void ffs_func_unbind(struct usb_configuration *c, + struct usb_function *f) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; + + ENTER(); + + if (ffs->func == func) { + ffs_func_eps_disable(func); + ffs->func = NULL; + } + + ffs_event_add(ffs, FUNCTIONFS_UNBIND); + + ffs_func_free(func); +} + +static int ffs_func_set_alt(struct usb_function *f, + unsigned interface, unsigned alt) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; + int ret = 0, intf; + + if (alt != (unsigned)-1) { + intf = ffs_func_revmap_intf(func, interface); + if (unlikely(intf < 0)) + return intf; + } + + if (ffs->func) + ffs_func_eps_disable(ffs->func); + + if (ffs->state != FFS_ACTIVE) + return -ENODEV; + + if (alt == (unsigned)-1) { + ffs->func = NULL; + ffs_event_add(ffs, FUNCTIONFS_DISABLE); + return 0; + } + + ffs->func = func; + ret = ffs_func_eps_enable(func); + if (likely(ret >= 0)) + ffs_event_add(ffs, FUNCTIONFS_ENABLE); + return ret; +} + +static void ffs_func_disable(struct usb_function *f) +{ + ffs_func_set_alt(f, 0, (unsigned)-1); +} + +static int ffs_func_setup(struct usb_function *f, + const struct usb_ctrlrequest *creq) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; + unsigned long flags; + int ret; + + ENTER(); + + pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); + pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); + pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); + pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex)); + pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength)); + + /* + * Most requests directed to interface go through here + * (notable exceptions are set/get interface) so we need to + * handle them. All other either handled by composite or + * passed to usb_configuration->setup() (if one is set). No + * matter, we will handle requests directed to endpoint here + * as well (as it's straightforward) but what to do with any + * other request? + */ + if (ffs->state != FFS_ACTIVE) + return -ENODEV; + + switch (creq->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); + if (unlikely(ret < 0)) + return ret; + break; + + case USB_RECIP_ENDPOINT: + ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); + if (unlikely(ret < 0)) + return ret; + break; + + default: + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&ffs->ev.waitq.lock, flags); + ffs->ev.setup = *creq; + ffs->ev.setup.wIndex = cpu_to_le16(ret); + __ffs_event_add(ffs, FUNCTIONFS_SETUP); + spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); + + return 0; +} + +static void ffs_func_suspend(struct usb_function *f) +{ + ENTER(); + ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); +} + +static void ffs_func_resume(struct usb_function *f) +{ + ENTER(); + ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); +} + + +/* Endpoint and interface numbers reverse mapping ***************************/ + +static int ffs_func_revmap_ep(struct ffs_function *func, u8 num) +{ + num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK]; + return num ? num : -EDOM; +} + +static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) +{ + short *nums = func->interfaces_nums; + unsigned count = func->ffs->interfaces_count; + + for (; count; --count, ++nums) { + if (*nums >= 0 && *nums == intf) + return nums - func->interfaces_nums; + } + + return -EDOM; +} + + +/* Misc helper functions ****************************************************/ + +static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) +{ + return nonblock + ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN + : mutex_lock_interruptible(mutex); +} + +static char *ffs_prepare_buffer(const char * __user buf, size_t len) +{ + char *data; + + if (unlikely(!len)) + return NULL; + + data = kmalloc(len, GFP_KERNEL); + if (unlikely(!data)) + return ERR_PTR(-ENOMEM); + + if (unlikely(__copy_from_user(data, buf, len))) { + kfree(data); + return ERR_PTR(-EFAULT); + } + + pr_vdebug("Buffer from user space:\n"); + ffs_dump_mem("", data, len); + + return data; +} diff --git a/drivers/staging/ccg/f_mass_storage.c b/drivers/staging/ccg/f_mass_storage.c new file mode 100644 index 0000000..4f1142e --- /dev/null +++ b/drivers/staging/ccg/f_mass_storage.c @@ -0,0 +1,3135 @@ +/* + * f_mass_storage.c -- Mass Storage USB Composite Function + * + * Copyright (C) 2003-2008 Alan Stern + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz <mina86@mina86.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The Mass Storage Function acts as a USB Mass Storage device, + * appearing to the host as a disk drive or as a CD-ROM drive. In + * addition to providing an example of a genuinely useful composite + * function for a USB device, it also illustrates a technique of + * double-buffering for increased throughput. + * + * For more information about MSF and in particular its module + * parameters and sysfs interface read the + * <Documentation/usb/mass-storage.txt> file. + */ + +/* + * MSF is configured by specifying a fsg_config structure. It has the + * following fields: + * + * nluns Number of LUNs function have (anywhere from 1 + * to FSG_MAX_LUNS which is 8). + * luns An array of LUN configuration values. This + * should be filled for each LUN that + * function will include (ie. for "nluns" + * LUNs). Each element of the array has + * the following fields: + * ->filename The path to the backing file for the LUN. + * Required if LUN is not marked as + * removable. + * ->ro Flag specifying access to the LUN shall be + * read-only. This is implied if CD-ROM + * emulation is enabled as well as when + * it was impossible to open "filename" + * in R/W mode. + * ->removable Flag specifying that LUN shall be indicated as + * being removable. + * ->cdrom Flag specifying that LUN shall be reported as + * being a CD-ROM. + * ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12) + * commands for this LUN shall be ignored. + * + * vendor_name + * product_name + * release Information used as a reply to INQUIRY + * request. To use default set to NULL, + * NULL, 0xffff respectively. The first + * field should be 8 and the second 16 + * characters or less. + * + * can_stall Set to permit function to halt bulk endpoints. + * Disabled on some USB devices known not + * to work correctly. You should set it + * to true. + * + * If "removable" is not set for a LUN then a backing file must be + * specified. If it is set, then NULL filename means the LUN's medium + * is not loaded (an empty string as "filename" in the fsg_config + * structure causes error). The CD-ROM emulation includes a single + * data track and no audio tracks; hence there need be only one + * backing file per LUN. + * + * This function is heavily based on "File-backed Storage Gadget" by + * Alan Stern which in turn is heavily based on "Gadget Zero" by David + * Brownell. The driver's SCSI command interface was based on the + * "Information technology - Small Computer System Interface - 2" + * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93, + * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. + * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which + * was based on the "Universal Serial Bus Mass Storage Class UFI + * Command Specification" document, Revision 1.0, December 14, 1998, + * available at + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. + */ + +/* + * Driver Design + * + * The MSF is fairly straightforward. There is a main kernel + * thread that handles most of the work. Interrupt routines field + * callbacks from the controller driver: bulk- and interrupt-request + * completion notifications, endpoint-0 events, and disconnect events. + * Completion events are passed to the main thread by wakeup calls. Many + * ep0 requests are handled at interrupt time, but SetInterface, + * SetConfiguration, and device reset requests are forwarded to the + * thread in the form of "exceptions" using SIGUSR1 signals (since they + * should interrupt any ongoing file I/O operations). + * + * The thread's main routine implements the standard command/data/status + * parts of a SCSI interaction. It and its subroutines are full of tests + * for pending signals/exceptions -- all this polling is necessary since + * the kernel has no setjmp/longjmp equivalents. (Maybe this is an + * indication that the driver really wants to be running in userspace.) + * An important point is that so long as the thread is alive it keeps an + * open reference to the backing file. This will prevent unmounting + * the backing file's underlying filesystem and could cause problems + * during system shutdown, for example. To prevent such problems, the + * thread catches INT, TERM, and KILL signals and converts them into + * an EXIT exception. + * + * In normal operation the main thread is started during the gadget's + * fsg_bind() callback and stopped during fsg_unbind(). But it can + * also exit when it receives a signal, and there's no point leaving + * the gadget running when the thread is dead. As of this moment, MSF + * provides no way to deregister the gadget when thread dies -- maybe + * a callback functions is needed. + * + * To provide maximum throughput, the driver uses a circular pipeline of + * buffer heads (struct fsg_buffhd). In principle the pipeline can be + * arbitrarily long; in practice the benefits don't justify having more + * than 2 stages (i.e., double buffering). But it helps to think of the + * pipeline as being a long one. Each buffer head contains a bulk-in and + * a bulk-out request pointer (since the buffer can be used for both + * output and input -- directions always are given from the host's + * point of view) as well as a pointer to the buffer and various state + * variables. + * + * Use of the pipeline follows a simple protocol. There is a variable + * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. + * At any time that buffer head may still be in use from an earlier + * request, so each buffer head has a state variable indicating whether + * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the + * buffer head to be EMPTY, filling the buffer either by file I/O or by + * USB I/O (during which the buffer head is BUSY), and marking the buffer + * head FULL when the I/O is complete. Then the buffer will be emptied + * (again possibly by USB I/O, during which it is marked BUSY) and + * finally marked EMPTY again (possibly by a completion routine). + * + * A module parameter tells the driver to avoid stalling the bulk + * endpoints wherever the transport specification allows. This is + * necessary for some UDCs like the SuperH, which cannot reliably clear a + * halt on a bulk endpoint. However, under certain circumstances the + * Bulk-only specification requires a stall. In such cases the driver + * will halt the endpoint and set a flag indicating that it should clear + * the halt in software during the next device reset. Hopefully this + * will permit everything to work correctly. Furthermore, although the + * specification allows the bulk-out endpoint to halt when the host sends + * too much data, implementing this would cause an unavoidable race. + * The driver will always use the "no-stall" approach for OUT transfers. + * + * One subtle point concerns sending status-stage responses for ep0 + * requests. Some of these requests, such as device reset, can involve + * interrupting an ongoing file I/O operation, which might take an + * arbitrarily long time. During that delay the host might give up on + * the original ep0 request and issue a new one. When that happens the + * driver should not notify the host about completion of the original + * request, as the host will no longer be waiting for it. So the driver + * assigns to each ep0 request a unique tag, and it keeps track of the + * tag value of the request associated with a long-running exception + * (device-reset, interface-change, or configuration-change). When the + * exception handler is finished, the status-stage response is submitted + * only if the current ep0 request tag is equal to the exception request + * tag. Thus only the most recently received ep0 request will get a + * status-stage response. + * + * Warning: This driver source file is too long. It ought to be split up + * into a header file plus about 3 separate .c files, to handle the details + * of the Gadget, USB Mass Storage, and SCSI protocols. + */ + + +/* #define VERBOSE_DEBUG */ +/* #define DUMP_MSGS */ + +#include <linux/blkdev.h> +#include <linux/completion.h> +#include <linux/dcache.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/fcntl.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/kref.h> +#include <linux/kthread.h> +#include <linux/limits.h> +#include <linux/rwsem.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/freezer.h> +#include <linux/utsname.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> + +#include "gadget_chips.h" + + +/*------------------------------------------------------------------------*/ + +#define FSG_DRIVER_DESC "Mass Storage Function" +#define FSG_DRIVER_VERSION "2009/09/11" + +static const char fsg_string_interface[] = "Mass Storage"; + +#define FSG_NO_DEVICE_STRINGS 1 +#define FSG_NO_OTG 1 +#define FSG_NO_INTR_EP 1 + +#include "storage_common.c" + + +/*-------------------------------------------------------------------------*/ + +struct fsg_dev; +struct fsg_common; + +/* FSF callback functions */ +struct fsg_operations { + /* + * Callback function to call when thread exits. If no + * callback is set or it returns value lower then zero MSF + * will force eject all LUNs it operates on (including those + * marked as non-removable or with prevent_medium_removal flag + * set). + */ + int (*thread_exits)(struct fsg_common *common); + + /* + * Called prior to ejection. Negative return means error, + * zero means to continue with ejection, positive means not to + * eject. + */ + int (*pre_eject)(struct fsg_common *common, + struct fsg_lun *lun, int num); + /* + * Called after ejection. Negative return means error, zero + * or positive is just a success. + */ + int (*post_eject)(struct fsg_common *common, + struct fsg_lun *lun, int num); +}; + +/* Data shared by all the FSG instances. */ +struct fsg_common { + struct usb_gadget *gadget; + struct usb_composite_dev *cdev; + struct fsg_dev *fsg, *new_fsg; + wait_queue_head_t fsg_wait; + + /* filesem protects: backing files in use */ + struct rw_semaphore filesem; + + /* lock protects: state, all the req_busy's */ + spinlock_t lock; + + struct usb_ep *ep0; /* Copy of gadget->ep0 */ + struct usb_request *ep0req; /* Copy of cdev->req */ + unsigned int ep0_req_tag; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd *buffhds; + + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + + unsigned int nluns; + unsigned int lun; + struct fsg_lun *luns; + struct fsg_lun *curlun; + + unsigned int bulk_out_maxpacket; + enum fsg_state state; /* For exception handling */ + unsigned int exception_req_tag; + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + + unsigned int can_stall:1; + unsigned int free_storage_on_release:1; + unsigned int phase_error:1; + unsigned int short_packet_received:1; + unsigned int bad_lun_okay:1; + unsigned int running:1; + + int thread_wakeup_needed; + struct completion thread_notifier; + struct task_struct *thread_task; + + /* Callback functions. */ + const struct fsg_operations *ops; + /* Gadget's private data. */ + void *private_data; + + /* + * Vendor (8 chars), product (16 chars), release (4 + * hexadecimal digits) and NUL byte + */ + char inquiry_string[8 + 16 + 4 + 1]; + + struct kref ref; +}; + +struct fsg_config { + unsigned nluns; + struct fsg_lun_config { + const char *filename; + char ro; + char removable; + char cdrom; + char nofua; + } luns[FSG_MAX_LUNS]; + + /* Callback functions. */ + const struct fsg_operations *ops; + /* Gadget's private data. */ + void *private_data; + + const char *vendor_name; /* 8 characters or less */ + const char *product_name; /* 16 characters or less */ + u16 release; + + char can_stall; +}; + +struct fsg_dev { + struct usb_function function; + struct usb_gadget *gadget; /* Copy of cdev->gadget */ + struct fsg_common *common; + + u16 interface_number; + + unsigned int bulk_in_enabled:1; + unsigned int bulk_out_enabled:1; + + unsigned long atomic_bitflags; +#define IGNORE_BULK_OUT 0 + + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; +}; + +static inline int __fsg_is_set(struct fsg_common *common, + const char *func, unsigned line) +{ + if (common->fsg) + return 1; + ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); + WARN_ON(1); + return 0; +} + +#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__)) + +static inline struct fsg_dev *fsg_from_func(struct usb_function *f) +{ + return container_of(f, struct fsg_dev, function); +} + +typedef void (*fsg_routine_t)(struct fsg_dev *); + +static int exception_in_progress(struct fsg_common *common) +{ + return common->state > FSG_STATE_IDLE; +} + +/* Make bulk-out requests be divisible by the maxpacket size */ +static void set_bulk_out_req_length(struct fsg_common *common, + struct fsg_buffhd *bh, unsigned int length) +{ + unsigned int rem; + + bh->bulk_out_intended_length = length; + rem = length % common->bulk_out_maxpacket; + if (rem > 0) + length += common->bulk_out_maxpacket - rem; + bh->outreq->length = length; +} + + +/*-------------------------------------------------------------------------*/ + +static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) +{ + const char *name; + + if (ep == fsg->bulk_in) + name = "bulk-in"; + else if (ep == fsg->bulk_out) + name = "bulk-out"; + else + name = ep->name; + DBG(fsg, "%s set halt\n", name); + return usb_ep_set_halt(ep); +} + + +/*-------------------------------------------------------------------------*/ + +/* These routines may be called in process context or in_irq */ + +/* Caller must hold fsg->lock */ +static void wakeup_thread(struct fsg_common *common) +{ + /* Tell the main thread that something has happened */ + common->thread_wakeup_needed = 1; + if (common->thread_task) + wake_up_process(common->thread_task); +} + +static void raise_exception(struct fsg_common *common, enum fsg_state new_state) +{ + unsigned long flags; + + /* + * Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. + */ + spin_lock_irqsave(&common->lock, flags); + if (common->state <= new_state) { + common->exception_req_tag = common->ep0_req_tag; + common->state = new_state; + if (common->thread_task) + send_sig_info(SIGUSR1, SEND_SIG_FORCED, + common->thread_task); + } + spin_unlock_irqrestore(&common->lock, flags); +} + + +/*-------------------------------------------------------------------------*/ + +static int ep0_queue(struct fsg_common *common) +{ + int rc; + + rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC); + common->ep0->driver_data = common; + if (rc != 0 && rc != -ESHUTDOWN) { + /* We can't do much more than wait for a reset */ + WARNING(common, "error in submission: %s --> %d\n", + common->ep0->name, rc); + } + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +/* Completion handlers. These always run in_irq. */ + +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_common *common = ep->driver_data; + struct fsg_buffhd *bh = req->context; + + if (req->status || req->actual != req->length) + DBG(common, "%s --> %d, %u/%u\n", __func__, + req->status, req->actual, req->length); + if (req->status == -ECONNRESET) /* Request was cancelled */ + usb_ep_fifo_flush(ep); + + /* Hold the lock while we update the request and buffer states */ + smp_wmb(); + spin_lock(&common->lock); + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + wakeup_thread(common); + spin_unlock(&common->lock); +} + +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_common *common = ep->driver_data; + struct fsg_buffhd *bh = req->context; + + dump_msg(common, "bulk-out", req->buf, req->actual); + if (req->status || req->actual != bh->bulk_out_intended_length) + DBG(common, "%s --> %d, %u/%u\n", __func__, + req->status, req->actual, bh->bulk_out_intended_length); + if (req->status == -ECONNRESET) /* Request was cancelled */ + usb_ep_fifo_flush(ep); + + /* Hold the lock while we update the request and buffer states */ + smp_wmb(); + spin_lock(&common->lock); + bh->outreq_busy = 0; + bh->state = BUF_STATE_FULL; + wakeup_thread(common); + spin_unlock(&common->lock); +} + +static int fsg_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct fsg_dev *fsg = fsg_from_func(f); + struct usb_request *req = fsg->common->ep0req; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + if (!fsg_is_set(fsg->common)) + return -EOPNOTSUPP; + + ++fsg->common->ep0_req_tag; /* Record arrival of a new request */ + req->context = NULL; + req->length = 0; + dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); + + switch (ctrl->bRequest) { + + case US_BULK_RESET_REQUEST: + if (ctrl->bRequestType != + (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 0) + return -EDOM; + + /* + * Raise an exception to stop the current operation + * and reinitialize our state. + */ + DBG(fsg, "bulk reset request\n"); + raise_exception(fsg->common, FSG_STATE_RESET); + return DELAYED_STATUS; + + case US_BULK_GET_MAX_LUN: + if (ctrl->bRequestType != + (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 1) + return -EDOM; + VDBG(fsg, "get max LUN\n"); + *(u8 *)req->buf = fsg->common->nluns - 1; + + /* Respond with data/status */ + req->length = min((u16)1, w_length); + return ep0_queue(fsg->common); + } + + VDBG(fsg, + "unknown class-specific control req %02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + le16_to_cpu(ctrl->wValue), w_index, w_length); + return -EOPNOTSUPP; +} + + +/*-------------------------------------------------------------------------*/ + +/* All the following routines run in process context */ + +/* Use this for bulk or interrupt transfers, not ep0 */ +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, + struct usb_request *req, int *pbusy, + enum fsg_buffer_state *state) +{ + int rc; + + if (ep == fsg->bulk_in) + dump_msg(fsg, "bulk-in", req->buf, req->length); + + spin_lock_irq(&fsg->common->lock); + *pbusy = 1; + *state = BUF_STATE_BUSY; + spin_unlock_irq(&fsg->common->lock); + rc = usb_ep_queue(ep, req, GFP_KERNEL); + if (rc != 0) { + *pbusy = 0; + *state = BUF_STATE_EMPTY; + + /* We can't do much more than wait for a reset */ + + /* + * Note: currently the net2280 driver fails zero-length + * submissions if DMA is enabled. + */ + if (rc != -ESHUTDOWN && + !(rc == -EOPNOTSUPP && req->length == 0)) + WARNING(fsg, "error in submission: %s --> %d\n", + ep->name, rc); + } +} + +static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh) +{ + if (!fsg_is_set(common)) + return false; + start_transfer(common->fsg, common->fsg->bulk_in, + bh->inreq, &bh->inreq_busy, &bh->state); + return true; +} + +static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh) +{ + if (!fsg_is_set(common)) + return false; + start_transfer(common->fsg, common->fsg->bulk_out, + bh->outreq, &bh->outreq_busy, &bh->state); + return true; +} + +static int sleep_thread(struct fsg_common *common) +{ + int rc = 0; + + /* Wait until a signal arrives or we are woken up */ + for (;;) { + try_to_freeze(); + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + if (common->thread_wakeup_needed) + break; + schedule(); + } + __set_current_state(TASK_RUNNING); + common->thread_wakeup_needed = 0; + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static int do_read(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; + u32 amount_left; + loff_t file_offset, file_offset_tmp; + unsigned int amount; + ssize_t nread; + + /* + * Get the starting Logical Block Address and check that it's + * not too big. + */ + if (common->cmnd[0] == READ_6) + lba = get_unaligned_be24(&common->cmnd[1]); + else { + lba = get_unaligned_be32(&common->cmnd[2]); + + /* + * We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = don't read from the + * cache), but we don't implement them. + */ + if ((common->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + file_offset = ((loff_t) lba) << curlun->blkbits; + + /* Carry out the file reads */ + amount_left = common->data_size_from_cmnd; + if (unlikely(amount_left == 0)) + return -EIO; /* No default reply */ + + for (;;) { + /* + * Figure out how much we need to read: + * Try to read the remaining amount. + * But don't read more than the buffer size. + * And don't try to read past the end of the file. + */ + amount = min(amount_left, FSG_BUFLEN); + amount = min((loff_t)amount, + curlun->file_length - file_offset); + + /* Wait for the next buffer to become available */ + bh = common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(common); + if (rc) + return rc; + } + + /* + * If we were asked to read past the end of file, + * end with an empty buffer. + */ + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + bh->inreq->length = 0; + bh->state = BUF_STATE_FULL; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; + nread = vfs_read(curlun->filp, + (char __user *)bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long)file_offset, (int)nread); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file read: %d\n", (int)nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file read: %d/%u\n", + (int)nread, amount); + nread = round_down(nread, curlun->blksize); + } + file_offset += nread; + amount_left -= nread; + common->residue -= nread; + + /* + * Except at the end of the transfer, nread will be + * equal to the buffer size, which is divisible by the + * bulk-in maxpacket size. + */ + bh->inreq->length = nread; + bh->state = BUF_STATE_FULL; + + /* If an error occurred, report it and its position */ + if (nread < amount) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + break; + } + + if (amount_left == 0) + break; /* No more left to read */ + + /* Send this buffer and go read some more */ + bh->inreq->zero = 0; + if (!start_in_transfer(common, bh)) + /* Don't know what to do if common->fsg is NULL */ + return -EIO; + common->next_buffhd_to_fill = bh->next; + } + + return -EIO; /* No default reply */ +} + + +/*-------------------------------------------------------------------------*/ + +static int do_write(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; + u32 amount_left_to_req, amount_left_to_write; + loff_t usb_offset, file_offset, file_offset_tmp; + unsigned int amount; + ssize_t nwritten; + int rc; + + if (curlun->ro) { + curlun->sense_data = SS_WRITE_PROTECTED; + return -EINVAL; + } + spin_lock(&curlun->filp->f_lock); + curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */ + spin_unlock(&curlun->filp->f_lock); + + /* + * Get the starting Logical Block Address and check that it's + * not too big + */ + if (common->cmnd[0] == WRITE_6) + lba = get_unaligned_be24(&common->cmnd[1]); + else { + lba = get_unaligned_be32(&common->cmnd[2]); + + /* + * We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = write directly to the + * medium). We don't implement DPO; we implement FUA by + * performing synchronous output. + */ + if (common->cmnd[1] & ~0x18) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */ + spin_lock(&curlun->filp->f_lock); + curlun->filp->f_flags |= O_SYNC; + spin_unlock(&curlun->filp->f_lock); + } + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* Carry out the file writes */ + get_some_more = 1; + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; + amount_left_to_req = common->data_size_from_cmnd; + amount_left_to_write = common->data_size_from_cmnd; + + while (amount_left_to_write > 0) { + + /* Queue a request for more data from the host */ + bh = common->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && get_some_more) { + + /* + * Figure out how much we want to get: + * Try to get the remaining amount, + * but not more than the buffer size. + */ + amount = min(amount_left_to_req, FSG_BUFLEN); + + /* Beyond the end of the backing file? */ + if (usb_offset >= curlun->file_length) { + get_some_more = 0; + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = + usb_offset >> curlun->blkbits; + curlun->info_valid = 1; + continue; + } + + /* Get the next buffer */ + usb_offset += amount; + common->usb_amount_left -= amount; + amount_left_to_req -= amount; + if (amount_left_to_req == 0) + get_some_more = 0; + + /* + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ + set_bulk_out_req_length(common, bh, amount); + if (!start_out_transfer(common, bh)) + /* Dunno what to do if common->fsg is NULL */ + return -EIO; + common->next_buffhd_to_fill = bh->next; + continue; + } + + /* Write the received data to the backing file */ + bh = common->next_buffhd_to_drain; + if (bh->state == BUF_STATE_EMPTY && !get_some_more) + break; /* We stopped early */ + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); + common->next_buffhd_to_drain = bh->next; + bh->state = BUF_STATE_EMPTY; + + /* Did something go wrong with the transfer? */ + if (bh->outreq->status != 0) { + curlun->sense_data = SS_COMMUNICATION_FAILURE; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + break; + } + + amount = bh->outreq->actual; + if (curlun->file_length - file_offset < amount) { + LERROR(curlun, + "write %u @ %llu beyond end %llu\n", + amount, (unsigned long long)file_offset, + (unsigned long long)curlun->file_length); + amount = curlun->file_length - file_offset; + } + + /* Don't accept excess data. The spec doesn't say + * what to do in this case. We'll ignore the error. + */ + amount = min(amount, bh->bulk_out_intended_length); + + /* Don't write a partial block */ + amount = round_down(amount, curlun->blksize); + if (amount == 0) + goto empty_write; + + /* Perform the write */ + file_offset_tmp = file_offset; + nwritten = vfs_write(curlun->filp, + (char __user *)bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, + (unsigned long long)file_offset, (int)nwritten); + if (signal_pending(current)) + return -EINTR; /* Interrupted! */ + + if (nwritten < 0) { + LDBG(curlun, "error in file write: %d\n", + (int)nwritten); + nwritten = 0; + } else if (nwritten < amount) { + LDBG(curlun, "partial file write: %d/%u\n", + (int)nwritten, amount); + nwritten = round_down(nwritten, curlun->blksize); + } + file_offset += nwritten; + amount_left_to_write -= nwritten; + common->residue -= nwritten; + + /* If an error occurred, report it and its position */ + if (nwritten < amount) { + curlun->sense_data = SS_WRITE_ERROR; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + break; + } + + empty_write: + /* Did the host decide to stop early? */ + if (bh->outreq->actual < bh->bulk_out_intended_length) { + common->short_packet_received = 1; + break; + } + continue; + } + + /* Wait for something to happen */ + rc = sleep_thread(common); + if (rc) + return rc; + } + + return -EIO; /* No default reply */ +} + + +/*-------------------------------------------------------------------------*/ + +static int do_synchronize_cache(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + int rc; + + /* We ignore the requested LBA and write out all file's + * dirty data buffers. */ + rc = fsg_lun_fsync_sub(curlun); + if (rc) + curlun->sense_data = SS_WRITE_ERROR; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static void invalidate_sub(struct fsg_lun *curlun) +{ + struct file *filp = curlun->filp; + struct inode *inode = filp->f_path.dentry->d_inode; + unsigned long rc; + + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); + VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); +} + +static int do_verify(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + u32 lba; + u32 verification_length; + struct fsg_buffhd *bh = common->next_buffhd_to_fill; + loff_t file_offset, file_offset_tmp; + u32 amount_left; + unsigned int amount; + ssize_t nread; + + /* + * Get the starting Logical Block Address and check that it's + * not too big. + */ + lba = get_unaligned_be32(&common->cmnd[2]); + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* + * We allow DPO (Disable Page Out = don't save data in the + * cache) but we don't implement it. + */ + if (common->cmnd[1] & ~0x10) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + verification_length = get_unaligned_be16(&common->cmnd[7]); + if (unlikely(verification_length == 0)) + return -EIO; /* No default reply */ + + /* Prepare to carry out the file verify */ + amount_left = verification_length << curlun->blkbits; + file_offset = ((loff_t) lba) << curlun->blkbits; + + /* Write out all the dirty buffers before invalidating them */ + fsg_lun_fsync_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + invalidate_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + /* Just try to read the requested blocks */ + while (amount_left > 0) { + /* + * Figure out how much we need to read: + * Try to read the remaining amount, but not more than + * the buffer size. + * And don't try to read past the end of the file. + */ + amount = min(amount_left, FSG_BUFLEN); + amount = min((loff_t)amount, + curlun->file_length - file_offset); + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; + nread = vfs_read(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file verify: %d\n", (int)nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file verify: %d/%u\n", + (int)nread, amount); + nread = round_down(nread, curlun->blksize); + } + if (nread == 0) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = + file_offset >> curlun->blkbits; + curlun->info_valid = 1; + break; + } + file_offset += nread; + amount_left -= nread; + } + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; + + if (!curlun) { /* Unsupported LUNs are okay */ + common->bad_lun_okay = 1; + memset(buf, 0, 36); + buf[0] = 0x7f; /* Unsupported, no device-type */ + buf[4] = 31; /* Additional length */ + return 36; + } + + buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK; + buf[1] = curlun->removable ? 0x80 : 0; + buf[2] = 2; /* ANSI SCSI level 2 */ + buf[3] = 2; /* SCSI-2 INQUIRY data format */ + buf[4] = 31; /* Additional length */ + buf[5] = 0; /* No special options */ + buf[6] = 0; + buf[7] = 0; + memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string); + return 36; +} + +static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + int valid; + + /* + * From the SCSI-2 spec., section 7.9 (Unit attention condition): + * + * If a REQUEST SENSE command is received from an initiator + * with a pending unit attention condition (before the target + * generates the contingent allegiance condition), then the + * target shall either: + * a) report any pending sense data and preserve the unit + * attention condition on the logical unit, or, + * b) report the unit attention condition, may discard any + * pending sense data, and clear the unit attention + * condition on the logical unit for that initiator. + * + * FSG normally uses option a); enable this code to use option b). + */ +#if 0 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + } +#endif + + if (!curlun) { /* Unsupported LUNs are okay */ + common->bad_lun_okay = 1; + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + sdinfo = 0; + valid = 0; + } else { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + valid = curlun->info_valid << 7; + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + + memset(buf, 0, 18); + buf[0] = valid | 0x70; /* Valid, current error */ + buf[2] = SK(sd); + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ + buf[7] = 18 - 8; /* Additional sense length */ + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + return 18; +} + +static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u32 lba = get_unaligned_be32(&common->cmnd[2]); + int pmi = common->cmnd[8]; + u8 *buf = (u8 *)bh->buf; + + /* Check the PMI and LBA fields */ + if (pmi > 1 || (pmi == 0 && lba != 0)) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); + /* Max logical block */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ + return 8; +} + +static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + int msf = common->cmnd[1] & 0x02; + u32 lba = get_unaligned_be32(&common->cmnd[2]); + u8 *buf = (u8 *)bh->buf; + + if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + memset(buf, 0, 8); + buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ + store_cdrom_address(&buf[4], msf, lba); + return 8; +} + +static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + int msf = common->cmnd[1] & 0x02; + int start_track = common->cmnd[6]; + u8 *buf = (u8 *)bh->buf; + + if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ + start_track > 1) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + memset(buf, 0, 20); + buf[1] = (20-2); /* TOC data length */ + buf[2] = 1; /* First track number */ + buf[3] = 1; /* Last track number */ + buf[5] = 0x16; /* Data track, copying allowed */ + buf[6] = 0x01; /* Only track is number 1 */ + store_cdrom_address(&buf[8], msf, 0); + + buf[13] = 0x16; /* Lead-out track is data */ + buf[14] = 0xAA; /* Lead-out track number */ + store_cdrom_address(&buf[16], msf, curlun->num_sectors); + return 20; +} + +static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + int mscmnd = common->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; + int pc, page_code; + int changeable_values, all_pages; + int valid_page = 0; + int len, limit; + + if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + pc = common->cmnd[2] >> 6; + page_code = common->cmnd[2] & 0x3f; + if (pc == 3) { + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + return -EINVAL; + } + changeable_values = (pc == 1); + all_pages = (page_code == 0x3f); + + /* + * Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. + */ + memset(buf, 0, 8); + if (mscmnd == MODE_SENSE) { + buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + buf += 4; + limit = 255; + } else { /* MODE_SENSE_10 */ + buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + buf += 8; + limit = 65535; /* Should really be FSG_BUFLEN */ + } + + /* No block descriptors */ + + /* + * The mode pages, in numerical order. The only page we support + * is the Caching page. + */ + if (page_code == 0x08 || all_pages) { + valid_page = 1; + buf[0] = 0x08; /* Page code */ + buf[1] = 10; /* Page length */ + memset(buf+2, 0, 10); /* None of the fields are changeable */ + + if (!changeable_values) { + buf[2] = 0x04; /* Write cache enable, */ + /* Read cache not disabled */ + /* No cache retention priorities */ + put_unaligned_be16(0xffff, &buf[4]); + /* Don't disable prefetch */ + /* Minimum prefetch = 0 */ + put_unaligned_be16(0xffff, &buf[8]); + /* Maximum prefetch */ + put_unaligned_be16(0xffff, &buf[10]); + /* Maximum prefetch ceiling */ + } + buf += 12; + } + + /* + * Check that a valid page was requested and the mode data length + * isn't too long. + */ + len = buf - buf0; + if (!valid_page || len > limit) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + /* Store the mode data length */ + if (mscmnd == MODE_SENSE) + buf0[0] = len - 1; + else + put_unaligned_be16(len - 2, buf0); + return len; +} + +static int do_start_stop(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + int loej, start; + + if (!curlun) { + return -EINVAL; + } else if (!curlun->removable) { + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ + (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + loej = common->cmnd[4] & 0x02; + start = common->cmnd[4] & 0x01; + + /* + * Our emulation doesn't support mounting; the medium is + * available for use as soon as it is loaded. + */ + if (start) { + if (!fsg_lun_is_open(curlun)) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } + return 0; + } + + /* Are we allowed to unload the media? */ + if (curlun->prevent_medium_removal) { + LDBG(curlun, "unload attempt prevented\n"); + curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; + return -EINVAL; + } + + if (!loej) + return 0; + + /* Simulate an unload/eject */ + if (common->ops && common->ops->pre_eject) { + int r = common->ops->pre_eject(common, curlun, + curlun - common->luns); + if (unlikely(r < 0)) + return r; + else if (r) + return 0; + } + + up_read(&common->filesem); + down_write(&common->filesem); + fsg_lun_close(curlun); + up_write(&common->filesem); + down_read(&common->filesem); + + return common->ops && common->ops->post_eject + ? min(0, common->ops->post_eject(common, curlun, + curlun - common->luns)) + : 0; +} + +static int do_prevent_allow(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + int prevent; + + if (!common->curlun) { + return -EINVAL; + } else if (!common->curlun->removable) { + common->curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } + + prevent = common->cmnd[4] & 0x01; + if ((common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + if (curlun->prevent_medium_removal && !prevent) + fsg_lun_fsync_sub(curlun); + curlun->prevent_medium_removal = prevent; + return 0; +} + +static int do_read_format_capacities(struct fsg_common *common, + struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ + buf += 4; + + put_unaligned_be32(curlun->num_sectors, &buf[0]); + /* Number of blocks */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ + buf[4] = 0x02; /* Current capacity */ + return 12; +} + +static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + + /* We don't support MODE SELECT */ + if (curlun) + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; +} + + +/*-------------------------------------------------------------------------*/ + +static int halt_bulk_in_endpoint(struct fsg_dev *fsg) +{ + int rc; + + rc = fsg_set_halt(fsg, fsg->bulk_in); + if (rc == -EAGAIN) + VDBG(fsg, "delayed bulk-in endpoint halt\n"); + while (rc != 0) { + if (rc != -EAGAIN) { + WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); + rc = 0; + break; + } + + /* Wait for a short time and then try again */ + if (msleep_interruptible(100) != 0) + return -EINTR; + rc = usb_ep_set_halt(fsg->bulk_in); + } + return rc; +} + +static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) +{ + int rc; + + DBG(fsg, "bulk-in set wedge\n"); + rc = usb_ep_set_wedge(fsg->bulk_in); + if (rc == -EAGAIN) + VDBG(fsg, "delayed bulk-in endpoint wedge\n"); + while (rc != 0) { + if (rc != -EAGAIN) { + WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); + rc = 0; + break; + } + + /* Wait for a short time and then try again */ + if (msleep_interruptible(100) != 0) + return -EINTR; + rc = usb_ep_set_wedge(fsg->bulk_in); + } + return rc; +} + +static int throw_away_data(struct fsg_common *common) +{ + struct fsg_buffhd *bh; + u32 amount; + int rc; + + for (bh = common->next_buffhd_to_drain; + bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0; + bh = common->next_buffhd_to_drain) { + + /* Throw away the data in a filled buffer */ + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); + bh->state = BUF_STATE_EMPTY; + common->next_buffhd_to_drain = bh->next; + + /* A short packet or an error ends everything */ + if (bh->outreq->actual < bh->bulk_out_intended_length || + bh->outreq->status != 0) { + raise_exception(common, + FSG_STATE_ABORT_BULK_OUT); + return -EINTR; + } + continue; + } + + /* Try to submit another request if we need one */ + bh = common->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY + && common->usb_amount_left > 0) { + amount = min(common->usb_amount_left, FSG_BUFLEN); + + /* + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ + set_bulk_out_req_length(common, bh, amount); + if (!start_out_transfer(common, bh)) + /* Dunno what to do if common->fsg is NULL */ + return -EIO; + common->next_buffhd_to_fill = bh->next; + common->usb_amount_left -= amount; + continue; + } + + /* Otherwise wait for something to happen */ + rc = sleep_thread(common); + if (rc) + return rc; + } + return 0; +} + +static int finish_reply(struct fsg_common *common) +{ + struct fsg_buffhd *bh = common->next_buffhd_to_fill; + int rc = 0; + + switch (common->data_dir) { + case DATA_DIR_NONE: + break; /* Nothing to send */ + + /* + * If we don't know whether the host wants to read or write, + * this must be CB or CBI with an unknown command. We mustn't + * try to send or receive any data. So stall both bulk pipes + * if we can and wait for a reset. + */ + case DATA_DIR_UNKNOWN: + if (!common->can_stall) { + /* Nothing */ + } else if (fsg_is_set(common)) { + fsg_set_halt(common->fsg, common->fsg->bulk_out); + rc = halt_bulk_in_endpoint(common->fsg); + } else { + /* Don't know what to do if common->fsg is NULL */ + rc = -EIO; + } + break; + + /* All but the last buffer of data must have already been sent */ + case DATA_DIR_TO_HOST: + if (common->data_size == 0) { + /* Nothing to send */ + + /* Don't know what to do if common->fsg is NULL */ + } else if (!fsg_is_set(common)) { + rc = -EIO; + + /* If there's no residue, simply send the last buffer */ + } else if (common->residue == 0) { + bh->inreq->zero = 0; + if (!start_in_transfer(common, bh)) + return -EIO; + common->next_buffhd_to_fill = bh->next; + + /* + * For Bulk-only, mark the end of the data with a short + * packet. If we are allowed to stall, halt the bulk-in + * endpoint. (Note: This violates the Bulk-Only Transport + * specification, which requires us to pad the data if we + * don't halt the endpoint. Presumably nobody will mind.) + */ + } else { + bh->inreq->zero = 1; + if (!start_in_transfer(common, bh)) + rc = -EIO; + common->next_buffhd_to_fill = bh->next; + if (common->can_stall) + rc = halt_bulk_in_endpoint(common->fsg); + } + break; + + /* + * We have processed all we want from the data the host has sent. + * There may still be outstanding bulk-out requests. + */ + case DATA_DIR_FROM_HOST: + if (common->residue == 0) { + /* Nothing to receive */ + + /* Did the host stop sending unexpectedly early? */ + } else if (common->short_packet_received) { + raise_exception(common, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; + + /* + * We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. + */ +#if 0 + } else if (common->can_stall) { + if (fsg_is_set(common)) + fsg_set_halt(common->fsg, + common->fsg->bulk_out); + raise_exception(common, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; +#endif + + /* + * We can't stall. Read in the excess data and throw it + * all away. + */ + } else { + rc = throw_away_data(common); + } + break; + } + return rc; +} + +static int send_status(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + struct fsg_buffhd *bh; + struct bulk_cs_wrap *csw; + int rc; + u8 status = US_BULK_STAT_OK; + u32 sd, sdinfo = 0; + + /* Wait for the next buffer to become available */ + bh = common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(common); + if (rc) + return rc; + } + + if (curlun) { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + } else if (common->bad_lun_okay) + sd = SS_NO_SENSE; + else + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + + if (common->phase_error) { + DBG(common, "sending phase-error status\n"); + status = US_BULK_STAT_PHASE; + sd = SS_INVALID_COMMAND; + } else if (sd != SS_NO_SENSE) { + DBG(common, "sending command-failure status\n"); + status = US_BULK_STAT_FAIL; + VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" + " info x%x\n", + SK(sd), ASC(sd), ASCQ(sd), sdinfo); + } + + /* Store and send the Bulk-only CSW */ + csw = (void *)bh->buf; + + csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); + csw->Tag = common->tag; + csw->Residue = cpu_to_le32(common->residue); + csw->Status = status; + + bh->inreq->length = US_BULK_CS_WRAP_LEN; + bh->inreq->zero = 0; + if (!start_in_transfer(common, bh)) + /* Don't know what to do if common->fsg is NULL */ + return -EIO; + + common->next_buffhd_to_fill = bh->next; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* + * Check whether the command is properly formed and whether its data size + * and direction agree with the values we already have. + */ +static int check_command(struct fsg_common *common, int cmnd_size, + enum data_direction data_dir, unsigned int mask, + int needs_medium, const char *name) +{ + int i; + int lun = common->cmnd[1] >> 5; + static const char dirletter[4] = {'u', 'o', 'i', 'n'}; + char hdlen[20]; + struct fsg_lun *curlun; + + hdlen[0] = 0; + if (common->data_dir != DATA_DIR_UNKNOWN) + sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir], + common->data_size); + VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], + common->data_size_from_cmnd, common->cmnd_size, hdlen); + + /* + * We can't reply at all until we know the correct data direction + * and size. + */ + if (common->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + if (common->data_size < common->data_size_from_cmnd) { + /* + * Host data size < Device data size is a phase error. + * Carry out the command, but only transfer as much as + * we are allowed. + */ + common->data_size_from_cmnd = common->data_size; + common->phase_error = 1; + } + common->residue = common->data_size; + common->usb_amount_left = common->data_size; + + /* Conflicting data directions is a phase error */ + if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) { + common->phase_error = 1; + return -EINVAL; + } + + /* Verify the length of the command itself */ + if (cmnd_size != common->cmnd_size) { + + /* + * Special case workaround: There are plenty of buggy SCSI + * implementations. Many have issues with cbw->Length + * field passing a wrong command size. For those cases we + * always try to work around the problem by using the length + * sent by the host side provided it is at least as large + * as the correct command length. + * Examples of such cases would be MS-Windows, which issues + * REQUEST SENSE with cbw->Length == 12 where it should + * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and + * REQUEST SENSE with cbw->Length == 10 where it should + * be 6 as well. + */ + if (cmnd_size <= common->cmnd_size) { + DBG(common, "%s is buggy! Expected length %d " + "but we got %d\n", name, + cmnd_size, common->cmnd_size); + cmnd_size = common->cmnd_size; + } else { + common->phase_error = 1; + return -EINVAL; + } + } + + /* Check that the LUN values are consistent */ + if (common->lun != lun) + DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n", + common->lun, lun); + + /* Check the LUN */ + curlun = common->curlun; + if (curlun) { + if (common->cmnd[0] != REQUEST_SENSE) { + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + } else { + common->bad_lun_okay = 0; + + /* + * INQUIRY and REQUEST SENSE commands are explicitly allowed + * to use unsupported LUNs; all others may not. + */ + if (common->cmnd[0] != INQUIRY && + common->cmnd[0] != REQUEST_SENSE) { + DBG(common, "unsupported LUN %d\n", common->lun); + return -EINVAL; + } + } + + /* + * If a unit attention condition exists, only INQUIRY and + * REQUEST SENSE commands are allowed; anything else must fail. + */ + if (curlun && curlun->unit_attention_data != SS_NO_SENSE && + common->cmnd[0] != INQUIRY && + common->cmnd[0] != REQUEST_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + return -EINVAL; + } + + /* Check that only command bytes listed in the mask are non-zero */ + common->cmnd[1] &= 0x1f; /* Mask away the LUN */ + for (i = 1; i < cmnd_size; ++i) { + if (common->cmnd[i] && !(mask & (1 << i))) { + if (curlun) + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + } + + /* If the medium isn't mounted and the command needs to access + * it, return an error. */ + if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } + + return 0; +} + +/* wrapper of check_command for data size in blocks handling */ +static int check_command_size_in_blocks(struct fsg_common *common, + int cmnd_size, enum data_direction data_dir, + unsigned int mask, int needs_medium, const char *name) +{ + if (common->curlun) + common->data_size_from_cmnd <<= common->curlun->blkbits; + return check_command(common, cmnd_size, data_dir, + mask, needs_medium, name); +} + +static int do_scsi_command(struct fsg_common *common) +{ + struct fsg_buffhd *bh; + int rc; + int reply = -EINVAL; + int i; + static char unknown[16]; + + dump_cdb(common); + + /* Wait for the next buffer to become available for data or status */ + bh = common->next_buffhd_to_fill; + common->next_buffhd_to_drain = bh; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(common); + if (rc) + return rc; + } + common->phase_error = 0; + common->short_packet_received = 0; + + down_read(&common->filesem); /* We're using the backing file */ + switch (common->cmnd[0]) { + + case INQUIRY: + common->data_size_from_cmnd = common->cmnd[4]; + reply = check_command(common, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "INQUIRY"); + if (reply == 0) + reply = do_inquiry(common, bh); + break; + + case MODE_SELECT: + common->data_size_from_cmnd = common->cmnd[4]; + reply = check_command(common, 6, DATA_DIR_FROM_HOST, + (1<<1) | (1<<4), 0, + "MODE SELECT(6)"); + if (reply == 0) + reply = do_mode_select(common, bh); + break; + + case MODE_SELECT_10: + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command(common, 10, DATA_DIR_FROM_HOST, + (1<<1) | (3<<7), 0, + "MODE SELECT(10)"); + if (reply == 0) + reply = do_mode_select(common, bh); + break; + + case MODE_SENSE: + common->data_size_from_cmnd = common->cmnd[4]; + reply = check_command(common, 6, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (1<<4), 0, + "MODE SENSE(6)"); + if (reply == 0) + reply = do_mode_sense(common, bh); + break; + + case MODE_SENSE_10: + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command(common, 10, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (3<<7), 0, + "MODE SENSE(10)"); + if (reply == 0) + reply = do_mode_sense(common, bh); + break; + + case ALLOW_MEDIUM_REMOVAL: + common->data_size_from_cmnd = 0; + reply = check_command(common, 6, DATA_DIR_NONE, + (1<<4), 0, + "PREVENT-ALLOW MEDIUM REMOVAL"); + if (reply == 0) + reply = do_prevent_allow(common); + break; + + case READ_6: + i = common->cmnd[4]; + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_TO_HOST, + (7<<1) | (1<<4), 1, + "READ(6)"); + if (reply == 0) + reply = do_read(common); + break; + + case READ_10: + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "READ(10)"); + if (reply == 0) + reply = do_read(common); + break; + + case READ_12: + common->data_size_from_cmnd = + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "READ(12)"); + if (reply == 0) + reply = do_read(common); + break; + + case READ_CAPACITY: + common->data_size_from_cmnd = 8; + reply = check_command(common, 10, DATA_DIR_TO_HOST, + (0xf<<2) | (1<<8), 1, + "READ CAPACITY"); + if (reply == 0) + reply = do_read_capacity(common, bh); + break; + + case READ_HEADER: + if (!common->curlun || !common->curlun->cdrom) + goto unknown_cmnd; + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command(common, 10, DATA_DIR_TO_HOST, + (3<<7) | (0x1f<<1), 1, + "READ HEADER"); + if (reply == 0) + reply = do_read_header(common, bh); + break; + + case READ_TOC: + if (!common->curlun || !common->curlun->cdrom) + goto unknown_cmnd; + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command(common, 10, DATA_DIR_TO_HOST, + (7<<6) | (1<<1), 1, + "READ TOC"); + if (reply == 0) + reply = do_read_toc(common, bh); + break; + + case READ_FORMAT_CAPACITIES: + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command(common, 10, DATA_DIR_TO_HOST, + (3<<7), 1, + "READ FORMAT CAPACITIES"); + if (reply == 0) + reply = do_read_format_capacities(common, bh); + break; + + case REQUEST_SENSE: + common->data_size_from_cmnd = common->cmnd[4]; + reply = check_command(common, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "REQUEST SENSE"); + if (reply == 0) + reply = do_request_sense(common, bh); + break; + + case START_STOP: + common->data_size_from_cmnd = 0; + reply = check_command(common, 6, DATA_DIR_NONE, + (1<<1) | (1<<4), 0, + "START-STOP UNIT"); + if (reply == 0) + reply = do_start_stop(common); + break; + + case SYNCHRONIZE_CACHE: + common->data_size_from_cmnd = 0; + reply = check_command(common, 10, DATA_DIR_NONE, + (0xf<<2) | (3<<7), 1, + "SYNCHRONIZE CACHE"); + if (reply == 0) + reply = do_synchronize_cache(common); + break; + + case TEST_UNIT_READY: + common->data_size_from_cmnd = 0; + reply = check_command(common, 6, DATA_DIR_NONE, + 0, 1, + "TEST UNIT READY"); + break; + + /* + * Although optional, this command is used by MS-Windows. We + * support a minimal version: BytChk must be 0. + */ + case VERIFY: + common->data_size_from_cmnd = 0; + reply = check_command(common, 10, DATA_DIR_NONE, + (1<<1) | (0xf<<2) | (3<<7), 1, + "VERIFY"); + if (reply == 0) + reply = do_verify(common); + break; + + case WRITE_6: + i = common->cmnd[4]; + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_FROM_HOST, + (7<<1) | (1<<4), 1, + "WRITE(6)"); + if (reply == 0) + reply = do_write(common); + break; + + case WRITE_10: + common->data_size_from_cmnd = + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "WRITE(10)"); + if (reply == 0) + reply = do_write(common); + break; + + case WRITE_12: + common->data_size_from_cmnd = + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "WRITE(12)"); + if (reply == 0) + reply = do_write(common); + break; + + /* + * Some mandatory commands that we recognize but don't implement. + * They don't mean much in this setting. It's left as an exercise + * for anyone interested to implement RESERVE and RELEASE in terms + * of Posix locks. + */ + case FORMAT_UNIT: + case RELEASE: + case RESERVE: + case SEND_DIAGNOSTIC: + /* Fall through */ + + default: +unknown_cmnd: + common->data_size_from_cmnd = 0; + sprintf(unknown, "Unknown x%02x", common->cmnd[0]); + reply = check_command(common, common->cmnd_size, + DATA_DIR_UNKNOWN, ~0, 0, unknown); + if (reply == 0) { + common->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } + break; + } + up_read(&common->filesem); + + if (reply == -EINTR || signal_pending(current)) + return -EINTR; + + /* Set up the single reply buffer for finish_reply() */ + if (reply == -EINVAL) + reply = 0; /* Error reply length */ + if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) { + reply = min((u32)reply, common->data_size_from_cmnd); + bh->inreq->length = reply; + bh->state = BUF_STATE_FULL; + common->residue -= reply; + } /* Otherwise it's already set */ + + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct usb_request *req = bh->outreq; + struct bulk_cb_wrap *cbw = req->buf; + struct fsg_common *common = fsg->common; + + /* Was this a real packet? Should it be ignored? */ + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) + return -EINVAL; + + /* Is the CBW valid? */ + if (req->actual != US_BULK_CB_WRAP_LEN || + cbw->Signature != cpu_to_le32( + US_BULK_CB_SIGN)) { + DBG(fsg, "invalid CBW: len %u sig 0x%x\n", + req->actual, + le32_to_cpu(cbw->Signature)); + + /* + * The Bulk-only spec says we MUST stall the IN endpoint + * (6.6.1), so it's unavoidable. It also says we must + * retain this state until the next reset, but there's + * no way to tell the controller driver it should ignore + * Clear-Feature(HALT) requests. + * + * We aren't required to halt the OUT endpoint; instead + * we can simply accept and discard any data received + * until the next reset. + */ + wedge_bulk_in_endpoint(fsg); + set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + return -EINVAL; + } + + /* Is the CBW meaningful? */ + if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " + "cmdlen %u\n", + cbw->Lun, cbw->Flags, cbw->Length); + + /* + * We can do anything we want here, so let's stall the + * bulk pipes if we are allowed to. + */ + if (common->can_stall) { + fsg_set_halt(fsg, fsg->bulk_out); + halt_bulk_in_endpoint(fsg); + } + return -EINVAL; + } + + /* Save the command for later */ + common->cmnd_size = cbw->Length; + memcpy(common->cmnd, cbw->CDB, common->cmnd_size); + if (cbw->Flags & US_BULK_FLAG_IN) + common->data_dir = DATA_DIR_TO_HOST; + else + common->data_dir = DATA_DIR_FROM_HOST; + common->data_size = le32_to_cpu(cbw->DataTransferLength); + if (common->data_size == 0) + common->data_dir = DATA_DIR_NONE; + common->lun = cbw->Lun; + if (common->lun >= 0 && common->lun < common->nluns) + common->curlun = &common->luns[common->lun]; + else + common->curlun = NULL; + common->tag = cbw->Tag; + return 0; +} + +static int get_next_command(struct fsg_common *common) +{ + struct fsg_buffhd *bh; + int rc = 0; + + /* Wait for the next buffer to become available */ + bh = common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(common); + if (rc) + return rc; + } + + /* Queue a request to read a Bulk-only CBW */ + set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN); + if (!start_out_transfer(common, bh)) + /* Don't know what to do if common->fsg is NULL */ + return -EIO; + + /* + * We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. + */ + + /* Wait for the CBW to arrive */ + while (bh->state != BUF_STATE_FULL) { + rc = sleep_thread(common); + if (rc) + return rc; + } + smp_rmb(); + rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO; + bh->state = BUF_STATE_EMPTY; + + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static int alloc_request(struct fsg_common *common, struct usb_ep *ep, + struct usb_request **preq) +{ + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (*preq) + return 0; + ERROR(common, "can't allocate request for %s\n", ep->name); + return -ENOMEM; +} + +/* Reset interface setting and re-init endpoint state (toggle etc). */ +static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) +{ + struct fsg_dev *fsg; + int i, rc = 0; + + if (common->running) + DBG(common, "reset interface\n"); + +reset: + /* Deallocate the requests */ + if (common->fsg) { + fsg = common->fsg; + + for (i = 0; i < fsg_num_buffers; ++i) { + struct fsg_buffhd *bh = &common->buffhds[i]; + + if (bh->inreq) { + usb_ep_free_request(fsg->bulk_in, bh->inreq); + bh->inreq = NULL; + } + if (bh->outreq) { + usb_ep_free_request(fsg->bulk_out, bh->outreq); + bh->outreq = NULL; + } + } + + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + + common->fsg = NULL; + wake_up(&common->fsg_wait); + } + + common->running = 0; + if (!new_fsg || rc) + return rc; + + common->fsg = new_fsg; + fsg = common->fsg; + + /* Enable the endpoints */ + rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); + if (rc) + goto reset; + rc = usb_ep_enable(fsg->bulk_in); + if (rc) + goto reset; + fsg->bulk_in->driver_data = common; + fsg->bulk_in_enabled = 1; + + rc = config_ep_by_speed(common->gadget, &(fsg->function), + fsg->bulk_out); + if (rc) + goto reset; + rc = usb_ep_enable(fsg->bulk_out); + if (rc) + goto reset; + fsg->bulk_out->driver_data = common; + fsg->bulk_out_enabled = 1; + common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc); + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + + /* Allocate the requests */ + for (i = 0; i < fsg_num_buffers; ++i) { + struct fsg_buffhd *bh = &common->buffhds[i]; + + rc = alloc_request(common, fsg->bulk_in, &bh->inreq); + if (rc) + goto reset; + rc = alloc_request(common, fsg->bulk_out, &bh->outreq); + if (rc) + goto reset; + bh->inreq->buf = bh->outreq->buf = bh->buf; + bh->inreq->context = bh->outreq->context = bh; + bh->inreq->complete = bulk_in_complete; + bh->outreq->complete = bulk_out_complete; + } + + common->running = 1; + for (i = 0; i < common->nluns; ++i) + common->luns[i].unit_attention_data = SS_RESET_OCCURRED; + return rc; +} + + +/****************************** ALT CONFIGS ******************************/ + +static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct fsg_dev *fsg = fsg_from_func(f); + fsg->common->new_fsg = fsg; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + return USB_GADGET_DELAYED_STATUS; +} + +static void fsg_disable(struct usb_function *f) +{ + struct fsg_dev *fsg = fsg_from_func(f); + fsg->common->new_fsg = NULL; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); +} + + +/*-------------------------------------------------------------------------*/ + +static void handle_exception(struct fsg_common *common) +{ + siginfo_t info; + int i; + struct fsg_buffhd *bh; + enum fsg_state old_state; + struct fsg_lun *curlun; + unsigned int exception_req_tag; + + /* + * Clear the existing signals. Anything but SIGUSR1 is converted + * into a high-priority EXIT exception. + */ + for (;;) { + int sig = + dequeue_signal_lock(current, ¤t->blocked, &info); + if (!sig) + break; + if (sig != SIGUSR1) { + if (common->state < FSG_STATE_EXIT) + DBG(common, "Main thread exiting on signal\n"); + raise_exception(common, FSG_STATE_EXIT); + } + } + + /* Cancel all the pending transfers */ + if (likely(common->fsg)) { + for (i = 0; i < fsg_num_buffers; ++i) { + bh = &common->buffhds[i]; + if (bh->inreq_busy) + usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); + if (bh->outreq_busy) + usb_ep_dequeue(common->fsg->bulk_out, + bh->outreq); + } + + /* Wait until everything is idle */ + for (;;) { + int num_active = 0; + for (i = 0; i < fsg_num_buffers; ++i) { + bh = &common->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; + } + if (num_active == 0) + break; + if (sleep_thread(common)) + return; + } + + /* Clear out the controller's fifos */ + if (common->fsg->bulk_in_enabled) + usb_ep_fifo_flush(common->fsg->bulk_in); + if (common->fsg->bulk_out_enabled) + usb_ep_fifo_flush(common->fsg->bulk_out); + } + + /* + * Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. + */ + spin_lock_irq(&common->lock); + + for (i = 0; i < fsg_num_buffers; ++i) { + bh = &common->buffhds[i]; + bh->state = BUF_STATE_EMPTY; + } + common->next_buffhd_to_fill = &common->buffhds[0]; + common->next_buffhd_to_drain = &common->buffhds[0]; + exception_req_tag = common->exception_req_tag; + old_state = common->state; + + if (old_state == FSG_STATE_ABORT_BULK_OUT) + common->state = FSG_STATE_STATUS_PHASE; + else { + for (i = 0; i < common->nluns; ++i) { + curlun = &common->luns[i]; + curlun->prevent_medium_removal = 0; + curlun->sense_data = SS_NO_SENSE; + curlun->unit_attention_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + common->state = FSG_STATE_IDLE; + } + spin_unlock_irq(&common->lock); + + /* Carry out any extra actions required for the exception */ + switch (old_state) { + case FSG_STATE_ABORT_BULK_OUT: + send_status(common); + spin_lock_irq(&common->lock); + if (common->state == FSG_STATE_STATUS_PHASE) + common->state = FSG_STATE_IDLE; + spin_unlock_irq(&common->lock); + break; + + case FSG_STATE_RESET: + /* + * In case we were forced against our will to halt a + * bulk endpoint, clear the halt now. (The SuperH UDC + * requires this.) + */ + if (!fsg_is_set(common)) + break; + if (test_and_clear_bit(IGNORE_BULK_OUT, + &common->fsg->atomic_bitflags)) + usb_ep_clear_halt(common->fsg->bulk_in); + + if (common->ep0_req_tag == exception_req_tag) + ep0_queue(common); /* Complete the status stage */ + + /* + * Technically this should go here, but it would only be + * a waste of time. Ditto for the INTERFACE_CHANGE and + * CONFIG_CHANGE cases. + */ + /* for (i = 0; i < common->nluns; ++i) */ + /* common->luns[i].unit_attention_data = */ + /* SS_RESET_OCCURRED; */ + break; + + case FSG_STATE_CONFIG_CHANGE: + do_set_interface(common, common->new_fsg); + if (common->new_fsg) + usb_composite_setup_continue(common->cdev); + break; + + case FSG_STATE_EXIT: + case FSG_STATE_TERMINATED: + do_set_interface(common, NULL); /* Free resources */ + spin_lock_irq(&common->lock); + common->state = FSG_STATE_TERMINATED; /* Stop the thread */ + spin_unlock_irq(&common->lock); + break; + + case FSG_STATE_INTERFACE_CHANGE: + case FSG_STATE_DISCONNECT: + case FSG_STATE_COMMAND_PHASE: + case FSG_STATE_DATA_PHASE: + case FSG_STATE_STATUS_PHASE: + case FSG_STATE_IDLE: + break; + } +} + + +/*-------------------------------------------------------------------------*/ + +static int fsg_main_thread(void *common_) +{ + struct fsg_common *common = common_; + + /* + * Allow the thread to be killed by a signal, but set the signal mask + * to block everything but INT, TERM, KILL, and USR1. + */ + allow_signal(SIGINT); + allow_signal(SIGTERM); + allow_signal(SIGKILL); + allow_signal(SIGUSR1); + + /* Allow the thread to be frozen */ + set_freezable(); + + /* + * Arrange for userspace references to be interpreted as kernel + * pointers. That way we can pass a kernel pointer to a routine + * that expects a __user pointer and it will work okay. + */ + set_fs(get_ds()); + + /* The main loop */ + while (common->state != FSG_STATE_TERMINATED) { + if (exception_in_progress(common) || signal_pending(current)) { + handle_exception(common); + continue; + } + + if (!common->running) { + sleep_thread(common); + continue; + } + + if (get_next_command(common)) + continue; + + spin_lock_irq(&common->lock); + if (!exception_in_progress(common)) + common->state = FSG_STATE_DATA_PHASE; + spin_unlock_irq(&common->lock); + + if (do_scsi_command(common) || finish_reply(common)) + continue; + + spin_lock_irq(&common->lock); + if (!exception_in_progress(common)) + common->state = FSG_STATE_STATUS_PHASE; + spin_unlock_irq(&common->lock); + + if (send_status(common)) + continue; + + spin_lock_irq(&common->lock); + if (!exception_in_progress(common)) + common->state = FSG_STATE_IDLE; + spin_unlock_irq(&common->lock); + } + + spin_lock_irq(&common->lock); + common->thread_task = NULL; + spin_unlock_irq(&common->lock); + + if (!common->ops || !common->ops->thread_exits + || common->ops->thread_exits(common) < 0) { + struct fsg_lun *curlun = common->luns; + unsigned i = common->nluns; + + down_write(&common->filesem); + for (; i--; ++curlun) { + if (!fsg_lun_is_open(curlun)) + continue; + + fsg_lun_close(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + up_write(&common->filesem); + } + + /* Let fsg_unbind() know the thread has exited */ + complete_and_exit(&common->thread_notifier, 0); +} + + +/*************************** DEVICE ATTRIBUTES ***************************/ + +static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); +static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); + +static struct device_attribute dev_attr_ro_cdrom = + __ATTR(ro, 0444, fsg_show_ro, NULL); +static struct device_attribute dev_attr_file_nonremovable = + __ATTR(file, 0444, fsg_show_file, NULL); + + +/****************************** FSG COMMON ******************************/ + +static void fsg_common_release(struct kref *ref); + +static void fsg_lun_release(struct device *dev) +{ + /* Nothing needs to be done */ +} + +static inline void fsg_common_get(struct fsg_common *common) +{ + kref_get(&common->ref); +} + +static inline void fsg_common_put(struct fsg_common *common) +{ + kref_put(&common->ref, fsg_common_release); +} + +static struct fsg_common *fsg_common_init(struct fsg_common *common, + struct usb_composite_dev *cdev, + struct fsg_config *cfg) +{ + struct usb_gadget *gadget = cdev->gadget; + struct fsg_buffhd *bh; + struct fsg_lun *curlun; + struct fsg_lun_config *lcfg; + int nluns, i, rc; + char *pathbuf; + + rc = fsg_num_buffers_validate(); + if (rc != 0) + return ERR_PTR(rc); + + /* Find out how many LUNs there should be */ + nluns = cfg->nluns; + if (nluns < 1 || nluns > FSG_MAX_LUNS) { + dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); + return ERR_PTR(-EINVAL); + } + + /* Allocate? */ + if (!common) { + common = kzalloc(sizeof *common, GFP_KERNEL); + if (!common) + return ERR_PTR(-ENOMEM); + common->free_storage_on_release = 1; + } else { + memset(common, 0, sizeof *common); + common->free_storage_on_release = 0; + } + + common->buffhds = kcalloc(fsg_num_buffers, + sizeof *(common->buffhds), GFP_KERNEL); + if (!common->buffhds) { + if (common->free_storage_on_release) + kfree(common); + return ERR_PTR(-ENOMEM); + } + + common->ops = cfg->ops; + common->private_data = cfg->private_data; + + common->gadget = gadget; + common->ep0 = gadget->ep0; + common->ep0req = cdev->req; + common->cdev = cdev; + + /* Maybe allocate device-global string IDs, and patch descriptors */ + if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { + rc = usb_string_id(cdev); + if (unlikely(rc < 0)) + goto error_release; + fsg_strings[FSG_STRING_INTERFACE].id = rc; + fsg_intf_desc.iInterface = rc; + } + + /* + * Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. + */ + curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); + if (unlikely(!curlun)) { + rc = -ENOMEM; + goto error_release; + } + common->luns = curlun; + + init_rwsem(&common->filesem); + + for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { + curlun->cdrom = !!lcfg->cdrom; + curlun->ro = lcfg->cdrom || lcfg->ro; + curlun->initially_ro = curlun->ro; + curlun->removable = lcfg->removable; + curlun->dev.release = fsg_lun_release; + curlun->dev.parent = &gadget->dev; + /* curlun->dev.driver = &fsg_driver.driver; XXX */ + dev_set_drvdata(&curlun->dev, &common->filesem); + dev_set_name(&curlun->dev, "lun%d", i); + + rc = device_register(&curlun->dev); + if (rc) { + INFO(common, "failed to register LUN%d: %d\n", i, rc); + common->nluns = i; + put_device(&curlun->dev); + goto error_release; + } + + rc = device_create_file(&curlun->dev, + curlun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + if (rc) + goto error_luns; + rc = device_create_file(&curlun->dev, + curlun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + if (rc) + goto error_luns; + rc = device_create_file(&curlun->dev, &dev_attr_nofua); + if (rc) + goto error_luns; + + if (lcfg->filename) { + rc = fsg_lun_open(curlun, lcfg->filename); + if (rc) + goto error_luns; + } else if (!curlun->removable) { + ERROR(common, "no file given for LUN%d\n", i); + rc = -EINVAL; + goto error_luns; + } + } + common->nluns = nluns; + + /* Data buffers cyclic list */ + bh = common->buffhds; + i = fsg_num_buffers; + goto buffhds_first_it; + do { + bh->next = bh + 1; + ++bh; +buffhds_first_it: + bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); + if (unlikely(!bh->buf)) { + rc = -ENOMEM; + goto error_release; + } + } while (--i); + bh->next = common->buffhds; + + /* Prepare inquiryString */ + if (cfg->release != 0xffff) { + i = cfg->release; + } else { + i = usb_gadget_controller_number(gadget); + if (i >= 0) { + i = 0x0300 + i; + } else { + WARNING(common, "controller '%s' not recognized\n", + gadget->name); + i = 0x0399; + } + } + snprintf(common->inquiry_string, sizeof common->inquiry_string, + "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", + /* Assume product name dependent on the first LUN */ + cfg->product_name ?: (common->luns->cdrom + ? "File-Stor Gadget" + : "File-CD Gadget"), + i); + + /* + * Some peripheral controllers are known not to be able to + * halt bulk endpoints correctly. If one of them is present, + * disable stalls. + */ + common->can_stall = cfg->can_stall && + !(gadget_is_at91(common->gadget)); + + spin_lock_init(&common->lock); + kref_init(&common->ref); + + /* Tell the thread to start working */ + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + rc = PTR_ERR(common->thread_task); + goto error_release; + } + init_completion(&common->thread_notifier); + init_waitqueue_head(&common->fsg_wait); + + /* Information */ + INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); + INFO(common, "Number of LUNs=%d\n", common->nluns); + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + for (i = 0, nluns = common->nluns, curlun = common->luns; + i < nluns; + ++curlun, ++i) { + char *p = "(no medium)"; + if (fsg_lun_is_open(curlun)) { + p = "(error)"; + if (pathbuf) { + p = d_path(&curlun->filp->f_path, + pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = "(error)"; + } + } + LINFO(curlun, "LUN: %s%s%sfile: %s\n", + curlun->removable ? "removable " : "", + curlun->ro ? "read only " : "", + curlun->cdrom ? "CD-ROM " : "", + p); + } + kfree(pathbuf); + + DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); + + wake_up_process(common->thread_task); + + return common; + +error_luns: + common->nluns = i + 1; +error_release: + common->state = FSG_STATE_TERMINATED; /* The thread is dead */ + /* Call fsg_common_release() directly, ref might be not initialised. */ + fsg_common_release(&common->ref); + return ERR_PTR(rc); +} + +static void fsg_common_release(struct kref *ref) +{ + struct fsg_common *common = container_of(ref, struct fsg_common, ref); + + /* If the thread isn't already dead, tell it to exit now */ + if (common->state != FSG_STATE_TERMINATED) { + raise_exception(common, FSG_STATE_EXIT); + wait_for_completion(&common->thread_notifier); + } + + if (likely(common->luns)) { + struct fsg_lun *lun = common->luns; + unsigned i = common->nluns; + + /* In error recovery common->nluns may be zero. */ + for (; i; --i, ++lun) { + device_remove_file(&lun->dev, &dev_attr_nofua); + device_remove_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + device_remove_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + fsg_lun_close(lun); + device_unregister(&lun->dev); + } + + kfree(common->luns); + } + + { + struct fsg_buffhd *bh = common->buffhds; + unsigned i = fsg_num_buffers; + do { + kfree(bh->buf); + } while (++bh, --i); + } + + kfree(common->buffhds); + if (common->free_storage_on_release) + kfree(common); +} + + +/*-------------------------------------------------------------------------*/ + +static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; + + DBG(fsg, "unbind\n"); + if (fsg->common->fsg == fsg) { + fsg->common->new_fsg = NULL; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + /* FIXME: make interruptible or killable somehow? */ + wait_event(common->fsg_wait, common->fsg != fsg); + } + + fsg_common_put(common); + usb_free_descriptors(fsg->function.descriptors); + usb_free_descriptors(fsg->function.hs_descriptors); + usb_free_descriptors(fsg->function.ss_descriptors); + kfree(fsg); +} + +static int fsg_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct fsg_dev *fsg = fsg_from_func(f); + struct usb_gadget *gadget = c->cdev->gadget; + int i; + struct usb_ep *ep; + + fsg->gadget = gadget; + + /* New interface */ + i = usb_interface_id(c, f); + if (i < 0) + return i; + fsg_intf_desc.bInterfaceNumber = i; + fsg->interface_number = i; + + /* Find all the endpoints we will use */ + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg->common; /* claim the endpoint */ + fsg->bulk_in = ep; + + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg->common; /* claim the endpoint */ + fsg->bulk_out = ep; + + /* Copy descriptors */ + f->descriptors = usb_copy_descriptors(fsg_fs_function); + if (unlikely(!f->descriptors)) + return -ENOMEM; + + if (gadget_is_dualspeed(gadget)) { + /* Assume endpoint addresses are the same for both speeds */ + fsg_hs_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_hs_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); + if (unlikely(!f->hs_descriptors)) { + usb_free_descriptors(f->descriptors); + return -ENOMEM; + } + } + + if (gadget_is_superspeed(gadget)) { + unsigned max_burst; + + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); + + fsg_ss_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; + + fsg_ss_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; + + f->ss_descriptors = usb_copy_descriptors(fsg_ss_function); + if (unlikely(!f->ss_descriptors)) { + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->descriptors); + return -ENOMEM; + } + } + + return 0; + +autoconf_fail: + ERROR(fsg, "unable to autoconfigure all endpoints\n"); + return -ENOTSUPP; +} + + +/****************************** ADD FUNCTION ******************************/ + +static struct usb_gadget_strings *fsg_strings_array[] = { + &fsg_stringtab, + NULL, +}; + +static int fsg_bind_config(struct usb_composite_dev *cdev, + struct usb_configuration *c, + struct fsg_common *common) +{ + struct fsg_dev *fsg; + int rc; + + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + if (unlikely(!fsg)) + return -ENOMEM; + + fsg->function.name = FSG_DRIVER_DESC; + fsg->function.strings = fsg_strings_array; + fsg->function.bind = fsg_bind; + fsg->function.unbind = fsg_unbind; + fsg->function.setup = fsg_setup; + fsg->function.set_alt = fsg_set_alt; + fsg->function.disable = fsg_disable; + + fsg->common = common; + /* + * Our caller holds a reference to common structure so we + * don't have to be worry about it being freed until we return + * from this function. So instead of incrementing counter now + * and decrement in error recovery we increment it only when + * call to usb_add_function() was successful. + */ + + rc = usb_add_function(c, &fsg->function); + if (unlikely(rc)) + kfree(fsg); + else + fsg_common_get(fsg->common); + return rc; +} + + +/************************* Module parameters *************************/ + +struct fsg_module_parameters { + char *file[FSG_MAX_LUNS]; + bool ro[FSG_MAX_LUNS]; + bool removable[FSG_MAX_LUNS]; + bool cdrom[FSG_MAX_LUNS]; + bool nofua[FSG_MAX_LUNS]; + + unsigned int file_count, ro_count, removable_count, cdrom_count; + unsigned int nofua_count; + unsigned int luns; /* nluns */ + bool stall; /* can_stall */ +}; + +#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \ + module_param_array_named(prefix ## name, params.name, type, \ + &prefix ## params.name ## _count, \ + S_IRUGO); \ + MODULE_PARM_DESC(prefix ## name, desc) + +#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \ + module_param_named(prefix ## name, params.name, type, \ + S_IRUGO); \ + MODULE_PARM_DESC(prefix ## name, desc) + +#define FSG_MODULE_PARAMETERS(prefix, params) \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \ + "names of backing files or devices"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \ + "true to force read-only"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \ + "true to simulate removable media"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \ + "true to simulate CD-ROM instead of disk"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \ + "true to ignore SCSI WRITE(10,12) FUA bit"); \ + _FSG_MODULE_PARAM(prefix, params, luns, uint, \ + "number of LUNs"); \ + _FSG_MODULE_PARAM(prefix, params, stall, bool, \ + "false to prevent bulk stalls") + +static void +fsg_config_from_params(struct fsg_config *cfg, + const struct fsg_module_parameters *params) +{ + struct fsg_lun_config *lun; + unsigned i; + + /* Configure LUNs */ + cfg->nluns = + min(params->luns ?: (params->file_count ?: 1u), + (unsigned)FSG_MAX_LUNS); + for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) { + lun->ro = !!params->ro[i]; + lun->cdrom = !!params->cdrom[i]; + lun->removable = !!params->removable[i]; + lun->filename = + params->file_count > i && params->file[i][0] + ? params->file[i] + : 0; + } + + /* Let MSF use defaults */ + cfg->vendor_name = 0; + cfg->product_name = 0; + cfg->release = 0xffff; + + cfg->ops = NULL; + cfg->private_data = NULL; + + /* Finalise */ + cfg->can_stall = params->stall; +} + +static inline struct fsg_common * +fsg_common_from_params(struct fsg_common *common, + struct usb_composite_dev *cdev, + const struct fsg_module_parameters *params) + __attribute__((unused)); +static inline struct fsg_common * +fsg_common_from_params(struct fsg_common *common, + struct usb_composite_dev *cdev, + const struct fsg_module_parameters *params) +{ + struct fsg_config cfg; + fsg_config_from_params(&cfg, params); + return fsg_common_init(common, cdev, &cfg); +} diff --git a/drivers/staging/ccg/f_rndis.c b/drivers/staging/ccg/f_rndis.c new file mode 100644 index 0000000..b1681e4 --- /dev/null +++ b/drivers/staging/ccg/f_rndis.c @@ -0,0 +1,918 @@ +/* + * f_rndis.c -- RNDIS link function driver + * + * Copyright (C) 2003-2005,2008 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger + * Copyright (C) 2008 Nokia Corporation + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz (mina86@mina86.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* #define VERBOSE_DEBUG */ + +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/etherdevice.h> + +#include <linux/atomic.h> + +#include "u_ether.h" +#include "rndis.h" + + +/* + * This function is an RNDIS Ethernet port -- a Microsoft protocol that's + * been promoted instead of the standard CDC Ethernet. The published RNDIS + * spec is ambiguous, incomplete, and needlessly complex. Variants such as + * ActiveSync have even worse status in terms of specification. + * + * In short: it's a protocol controlled by (and for) Microsoft, not for an + * Open ecosystem or markets. Linux supports it *only* because Microsoft + * doesn't support the CDC Ethernet standard. + * + * The RNDIS data transfer model is complex, with multiple Ethernet packets + * per USB message, and out of band data. The control model is built around + * what's essentially an "RNDIS RPC" protocol. It's all wrapped in a CDC ACM + * (modem, not Ethernet) veneer, with those ACM descriptors being entirely + * useless (they're ignored). RNDIS expects to be the only function in its + * configuration, so it's no real help if you need composite devices; and + * it expects to be the first configuration too. + * + * There is a single technical advantage of RNDIS over CDC Ethernet, if you + * discount the fluff that its RPC can be made to deliver: it doesn't need + * a NOP altsetting for the data interface. That lets it work on some of the + * "so smart it's stupid" hardware which takes over configuration changes + * from the software, and adds restrictions like "no altsettings". + * + * Unfortunately MSFT's RNDIS drivers are buggy. They hang or oops, and + * have all sorts of contrary-to-specification oddities that can prevent + * them from working sanely. Since bugfixes (or accurate specs, letting + * Linux work around those bugs) are unlikely to ever come from MSFT, you + * may want to avoid using RNDIS on purely operational grounds. + * + * Omissions from the RNDIS 1.0 specification include: + * + * - Power management ... references data that's scattered around lots + * of other documentation, which is incorrect/incomplete there too. + * + * - There are various undocumented protocol requirements, like the need + * to send garbage in some control-OUT messages. + * + * - MS-Windows drivers sometimes emit undocumented requests. + */ + +struct f_rndis { + struct gether port; + u8 ctrl_id, data_id; + u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *manufacturer; + int config; + + struct usb_ep *notify; + struct usb_request *notify_req; + atomic_t notify_count; +}; + +static inline struct f_rndis *func_to_rndis(struct usb_function *f) +{ + return container_of(f, struct f_rndis, port.func); +} + +/* peak (theoretical) bulk transfer rate in bits-per-second */ +static unsigned int bitrate(struct usb_gadget *g) +{ + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return 13 * 1024 * 8 * 1000 * 8; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return 13 * 512 * 8 * 1000 * 8; + else + return 19 * 64 * 1 * 1000 * 8; +} + +/*-------------------------------------------------------------------------*/ + +/* + */ + +#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define STATUS_BYTECOUNT 8 /* 8 bytes data */ + + +/* interface descriptor: */ + +static struct usb_interface_descriptor rndis_control_intf = { + .bLength = sizeof rndis_control_intf, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC */ + /* status endpoint is optional; this could be patched later */ + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, + /* .iInterface = DYNAMIC */ +}; + +static struct usb_cdc_header_desc header_desc = { + .bLength = sizeof header_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + + .bcdCDC = cpu_to_le16(0x0110), +}; + +static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { + .bLength = sizeof call_mgmt_descriptor, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + + .bmCapabilities = 0x00, + .bDataInterface = 0x01, +}; + +static struct usb_cdc_acm_descriptor rndis_acm_descriptor = { + .bLength = sizeof rndis_acm_descriptor, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + + .bmCapabilities = 0x00, +}; + +static struct usb_cdc_union_desc rndis_union_desc = { + .bLength = sizeof(rndis_union_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + /* .bMasterInterface0 = DYNAMIC */ + /* .bSlaveInterface0 = DYNAMIC */ +}; + +/* the data interface has two bulk endpoints */ + +static struct usb_interface_descriptor rndis_data_intf = { + .bLength = sizeof rndis_data_intf, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC */ + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + /* .iInterface = DYNAMIC */ +}; + + +static struct usb_interface_assoc_descriptor +rndis_iad_descriptor = { + .bLength = sizeof rndis_iad_descriptor, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + + .bFirstInterface = 0, /* XXX, hardcoded */ + .bInterfaceCount = 2, // control + data + .bFunctionClass = USB_CLASS_COMM, + .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bFunctionProtocol = USB_CDC_PROTO_NONE, + /* .iFunction = DYNAMIC */ +}; + +/* full speed support: */ + +static struct usb_endpoint_descriptor fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, +}; + +static struct usb_endpoint_descriptor 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 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 *eth_fs_function[] = { + (struct usb_descriptor_header *) &rndis_iad_descriptor, + + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &fs_notify_desc, + + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &fs_in_desc, + (struct usb_descriptor_header *) &fs_out_desc, + NULL, +}; + +/* high speed support: */ + +static struct usb_endpoint_descriptor hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_endpoint_descriptor hs_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor hs_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_descriptor_header *eth_hs_function[] = { + (struct usb_descriptor_header *) &rndis_iad_descriptor, + + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &hs_notify_desc, + + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &hs_in_desc, + (struct usb_descriptor_header *) &hs_out_desc, + NULL, +}; + +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { + .bLength = sizeof ss_intr_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = { + .bLength = sizeof ss_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *eth_ss_function[] = { + (struct usb_descriptor_header *) &rndis_iad_descriptor, + + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &ss_notify_desc, + (struct usb_descriptor_header *) &ss_intr_comp_desc, + + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &ss_in_desc, + (struct usb_descriptor_header *) &ss_bulk_comp_desc, + (struct usb_descriptor_header *) &ss_out_desc, + (struct usb_descriptor_header *) &ss_bulk_comp_desc, + NULL, +}; + +/* string descriptors: */ + +static struct usb_string rndis_string_defs[] = { + [0].s = "RNDIS Communications Control", + [1].s = "RNDIS Ethernet Data", + [2].s = "RNDIS", + { } /* end of list */ +}; + +static struct usb_gadget_strings rndis_string_table = { + .language = 0x0409, /* en-us */ + .strings = rndis_string_defs, +}; + +static struct usb_gadget_strings *rndis_strings[] = { + &rndis_string_table, + NULL, +}; + +/*-------------------------------------------------------------------------*/ + +static struct sk_buff *rndis_add_header(struct gether *port, + struct sk_buff *skb) +{ + struct sk_buff *skb2; + + skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); + if (skb2) + rndis_add_hdr(skb2); + + dev_kfree_skb_any(skb); + return skb2; +} + +static void rndis_response_available(void *_rndis) +{ + struct f_rndis *rndis = _rndis; + struct usb_request *req = rndis->notify_req; + struct usb_composite_dev *cdev = rndis->port.func.config->cdev; + __le32 *data = req->buf; + int status; + + if (atomic_inc_return(&rndis->notify_count) != 1) + return; + + /* Send RNDIS RESPONSE_AVAILABLE notification; a + * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too + * + * This is the only notification defined by RNDIS. + */ + data[0] = cpu_to_le32(1); + data[1] = cpu_to_le32(0); + + status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); + if (status) { + atomic_dec(&rndis->notify_count); + DBG(cdev, "notify/0 --> %d\n", status); + } +} + +static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_rndis *rndis = req->context; + struct usb_composite_dev *cdev = rndis->port.func.config->cdev; + int status = req->status; + + /* after TX: + * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) + * - RNDIS_RESPONSE_AVAILABLE (status/irq) + */ + switch (status) { + case -ECONNRESET: + case -ESHUTDOWN: + /* connection gone */ + atomic_set(&rndis->notify_count, 0); + break; + default: + DBG(cdev, "RNDIS %s response error %d, %d/%d\n", + ep->name, status, + req->actual, req->length); + /* FALLTHROUGH */ + case 0: + if (ep != rndis->notify) + break; + + /* handle multiple pending RNDIS_RESPONSE_AVAILABLE + * notifications by resending until we're done + */ + if (atomic_dec_and_test(&rndis->notify_count)) + break; + status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); + if (status) { + atomic_dec(&rndis->notify_count); + DBG(cdev, "notify/1 --> %d\n", status); + } + break; + } +} + +static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_rndis *rndis = req->context; + struct usb_composite_dev *cdev = rndis->port.func.config->cdev; + int status; + + /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ +// spin_lock(&dev->lock); + status = rndis_msg_parser(rndis->config, (u8 *) req->buf); + if (status < 0) + ERROR(cdev, "RNDIS command error %d, %d/%d\n", + status, req->actual, req->length); +// spin_unlock(&dev->lock); +} + +static int +rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct f_rndis *rndis = func_to_rndis(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + /* composite driver infrastructure handles everything except + * CDC class messages; interface activation uses set_alt(). + */ + switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { + + /* RNDIS uses the CDC command encapsulation mechanism to implement + * an RPC scheme, with much getting/setting of attributes by OID. + */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_SEND_ENCAPSULATED_COMMAND: + if (w_value || w_index != rndis->ctrl_id) + goto invalid; + /* read the request; process it later */ + value = w_length; + req->complete = rndis_command_complete; + req->context = rndis; + /* later, rndis_response_available() sends a notification */ + break; + + case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_GET_ENCAPSULATED_RESPONSE: + if (w_value || w_index != rndis->ctrl_id) + goto invalid; + else { + u8 *buf; + u32 n; + + /* return the result */ + buf = rndis_get_next_response(rndis->config, &n); + if (buf) { + memcpy(req->buf, buf, n); + req->complete = rndis_response_complete; + req->context = rndis; + rndis_free_response(rndis->config, buf); + value = n; + } + /* else stalls ... spec says to avoid that */ + } + break; + + default: +invalid: + VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + req->zero = (value < w_length); + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + ERROR(cdev, "rndis response on err %d\n", value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + + +static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_rndis *rndis = func_to_rndis(f); + struct usb_composite_dev *cdev = f->config->cdev; + + /* we know alt == 0 */ + + if (intf == rndis->ctrl_id) { + if (rndis->notify->driver_data) { + VDBG(cdev, "reset rndis control %d\n", intf); + usb_ep_disable(rndis->notify); + } + if (!rndis->notify->desc) { + VDBG(cdev, "init rndis ctrl %d\n", intf); + if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) + goto fail; + } + usb_ep_enable(rndis->notify); + rndis->notify->driver_data = rndis; + + } else if (intf == rndis->data_id) { + struct net_device *net; + + if (rndis->port.in_ep->driver_data) { + DBG(cdev, "reset rndis\n"); + gether_disconnect(&rndis->port); + } + + if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { + DBG(cdev, "init rndis\n"); + if (config_ep_by_speed(cdev->gadget, f, + rndis->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, + rndis->port.out_ep)) { + rndis->port.in_ep->desc = NULL; + rndis->port.out_ep->desc = NULL; + goto fail; + } + } + + /* Avoid ZLPs; they can be troublesome. */ + rndis->port.is_zlp_ok = false; + + /* RNDIS should be in the "RNDIS uninitialized" state, + * either never activated or after rndis_uninit(). + * + * We don't want data to flow here until a nonzero packet + * filter is set, at which point it enters "RNDIS data + * initialized" state ... but we do want the endpoints + * to be activated. It's a strange little state. + * + * REVISIT the RNDIS gadget code has done this wrong for a + * very long time. We need another call to the link layer + * code -- gether_updown(...bool) maybe -- to do it right. + */ + rndis->port.cdc_filter = 0; + + DBG(cdev, "RNDIS RX/TX early activation ... \n"); + net = gether_connect(&rndis->port); + if (IS_ERR(net)) + return PTR_ERR(net); + + rndis_set_param_dev(rndis->config, net, + &rndis->port.cdc_filter); + } else + goto fail; + + return 0; +fail: + return -EINVAL; +} + +static void rndis_disable(struct usb_function *f) +{ + struct f_rndis *rndis = func_to_rndis(f); + struct usb_composite_dev *cdev = f->config->cdev; + + if (!rndis->notify->driver_data) + return; + + DBG(cdev, "rndis deactivated\n"); + + rndis_uninit(rndis->config); + gether_disconnect(&rndis->port); + + usb_ep_disable(rndis->notify); + rndis->notify->driver_data = NULL; +} + +/*-------------------------------------------------------------------------*/ + +/* + * This isn't quite the same mechanism as CDC Ethernet, since the + * notification scheme passes less data, but the same set of link + * states must be tested. A key difference is that altsettings are + * not used to tell whether the link should send packets or not. + */ + +static void rndis_open(struct gether *geth) +{ + struct f_rndis *rndis = func_to_rndis(&geth->func); + struct usb_composite_dev *cdev = geth->func.config->cdev; + + DBG(cdev, "%s\n", __func__); + + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, + bitrate(cdev->gadget) / 100); + rndis_signal_connect(rndis->config); +} + +static void rndis_close(struct gether *geth) +{ + struct f_rndis *rndis = func_to_rndis(&geth->func); + + DBG(geth->func.config->cdev, "%s\n", __func__); + + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); + rndis_signal_disconnect(rndis->config); +} + +/*-------------------------------------------------------------------------*/ + +/* ethernet function driver setup/binding */ + +static int +rndis_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct f_rndis *rndis = func_to_rndis(f); + int status; + struct usb_ep *ep; + + /* allocate instance-specific interface IDs */ + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + rndis->ctrl_id = status; + rndis_iad_descriptor.bFirstInterface = status; + + rndis_control_intf.bInterfaceNumber = status; + rndis_union_desc.bMasterInterface0 = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + rndis->data_id = status; + + rndis_data_intf.bInterfaceNumber = status; + rndis_union_desc.bSlaveInterface0 = status; + + status = -ENODEV; + + /* allocate instance-specific endpoints */ + ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc); + if (!ep) + goto fail; + rndis->port.in_ep = ep; + ep->driver_data = cdev; /* claim */ + + ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc); + if (!ep) + goto fail; + rndis->port.out_ep = ep; + ep->driver_data = cdev; /* claim */ + + /* NOTE: a status/notification endpoint is, strictly speaking, + * optional. We don't treat it that way though! It's simpler, + * and some newer profiles don't treat it as optional. + */ + ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc); + if (!ep) + goto fail; + rndis->notify = ep; + ep->driver_data = cdev; /* claim */ + + status = -ENOMEM; + + /* allocate notification request and buffer */ + rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!rndis->notify_req) + goto fail; + rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL); + if (!rndis->notify_req->buf) + goto fail; + rndis->notify_req->length = STATUS_BYTECOUNT; + rndis->notify_req->context = rndis; + rndis->notify_req->complete = rndis_response_complete; + + /* copy descriptors, and track endpoint copies */ + f->descriptors = usb_copy_descriptors(eth_fs_function); + if (!f->descriptors) + goto fail; + + /* support all relevant hardware speeds... we expect that when + * hardware is dual speed, all bulk-capable endpoints work at + * both speeds + */ + if (gadget_is_dualspeed(c->cdev->gadget)) { + hs_in_desc.bEndpointAddress = + fs_in_desc.bEndpointAddress; + hs_out_desc.bEndpointAddress = + fs_out_desc.bEndpointAddress; + hs_notify_desc.bEndpointAddress = + fs_notify_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->hs_descriptors = usb_copy_descriptors(eth_hs_function); + if (!f->hs_descriptors) + goto fail; + } + + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_in_desc.bEndpointAddress = + fs_in_desc.bEndpointAddress; + ss_out_desc.bEndpointAddress = + fs_out_desc.bEndpointAddress; + ss_notify_desc.bEndpointAddress = + fs_notify_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(eth_ss_function); + if (!f->ss_descriptors) + goto fail; + } + + rndis->port.open = rndis_open; + rndis->port.close = rndis_close; + + status = rndis_register(rndis_response_available, rndis); + if (status < 0) + goto fail; + rndis->config = status; + + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); + rndis_set_host_mac(rndis->config, rndis->ethaddr); + + if (rndis->manufacturer && rndis->vendorID && + rndis_set_param_vendor(rndis->config, rndis->vendorID, + rndis->manufacturer)) + goto fail; + + /* NOTE: all that is done without knowing or caring about + * the network link ... which is unavailable to this code + * until we're activated via set_alt(). + */ + + DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : + gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", + rndis->port.in_ep->name, rndis->port.out_ep->name, + rndis->notify->name); + return 0; + +fail: + if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) + usb_free_descriptors(f->ss_descriptors); + if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) + usb_free_descriptors(f->hs_descriptors); + if (f->descriptors) + usb_free_descriptors(f->descriptors); + + if (rndis->notify_req) { + kfree(rndis->notify_req->buf); + usb_ep_free_request(rndis->notify, rndis->notify_req); + } + + /* we might as well release our claims on endpoints */ + if (rndis->notify) + rndis->notify->driver_data = NULL; + if (rndis->port.out_ep->desc) + rndis->port.out_ep->driver_data = NULL; + if (rndis->port.in_ep->desc) + rndis->port.in_ep->driver_data = NULL; + + ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); + + return status; +} + +static void +rndis_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_rndis *rndis = func_to_rndis(f); + + rndis_deregister(rndis->config); + rndis_exit(); + rndis_string_defs[0].id = 0; + + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); + if (gadget_is_dualspeed(c->cdev->gadget)) + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->descriptors); + + kfree(rndis->notify_req->buf); + usb_ep_free_request(rndis->notify, rndis->notify_req); + + kfree(rndis); +} + +/* Some controllers can't support RNDIS ... */ +static inline bool can_support_rndis(struct usb_configuration *c) +{ + /* everything else is *presumably* fine */ + return true; +} + +int +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) +{ + struct f_rndis *rndis; + int status; + + if (!can_support_rndis(c) || !ethaddr) + return -EINVAL; + + /* maybe allocate device-global string IDs */ + if (rndis_string_defs[0].id == 0) { + + /* ... and setup RNDIS itself */ + status = rndis_init(); + if (status < 0) + return status; + + /* control interface label */ + status = usb_string_id(c->cdev); + if (status < 0) + return status; + rndis_string_defs[0].id = status; + rndis_control_intf.iInterface = status; + + /* data interface label */ + status = usb_string_id(c->cdev); + if (status < 0) + return status; + rndis_string_defs[1].id = status; + rndis_data_intf.iInterface = status; + + /* IAD iFunction label */ + status = usb_string_id(c->cdev); + if (status < 0) + return status; + rndis_string_defs[2].id = status; + rndis_iad_descriptor.iFunction = status; + } + + /* allocate and initialize one new instance */ + status = -ENOMEM; + rndis = kzalloc(sizeof *rndis, GFP_KERNEL); + if (!rndis) + goto fail; + + memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); + rndis->vendorID = vendorID; + rndis->manufacturer = manufacturer; + + /* RNDIS activates when the host changes this filter */ + rndis->port.cdc_filter = 0; + + /* RNDIS has special (and complex) framing */ + rndis->port.header_len = sizeof(struct rndis_packet_msg_type); + rndis->port.wrap = rndis_add_header; + rndis->port.unwrap = rndis_rm_hdr; + + rndis->port.func.name = "rndis"; + rndis->port.func.strings = rndis_strings; + /* descriptors are per-instance copies */ + rndis->port.func.bind = rndis_bind; + rndis->port.func.unbind = rndis_unbind; + rndis->port.func.set_alt = rndis_set_alt; + rndis->port.func.setup = rndis_setup; + rndis->port.func.disable = rndis_disable; + + status = usb_add_function(c, &rndis->port.func); + if (status) { + kfree(rndis); +fail: + rndis_exit(); + } + return status; +} diff --git a/drivers/staging/ccg/gadget_chips.h b/drivers/staging/ccg/gadget_chips.h new file mode 100644 index 0000000..0ccca58 --- /dev/null +++ b/drivers/staging/ccg/gadget_chips.h @@ -0,0 +1,150 @@ +/* + * USB device controllers have lots of quirks. Use these macros in + * gadget drivers or other code that needs to deal with them, and which + * autoconfigures instead of using early binding to the hardware. + * + * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by + * some config file that gets updated as new hardware is supported. + * (And avoiding all runtime comparisons in typical one-choice configs!) + * + * NOTE: some of these controller drivers may not be available yet. + * Some are available on 2.4 kernels; several are available, but not + * yet pushed in the 2.6 mainline tree. + */ + +#ifndef __GADGET_CHIPS_H +#define __GADGET_CHIPS_H + +/* + * NOTICE: the entries below are alphabetical and should be kept + * that way. + * + * Always be sure to add new entries to the correct position or + * accept the bashing later. + * + * If you have forgotten the alphabetical order let VIM/EMACS + * do that for you. + */ +#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) +#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) +#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) +#define gadget_is_bcm63xx(g) (!strcmp("bcm63xx_udc", (g)->name)) +#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) +#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) +#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) +#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name)) +#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name)) +#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) +#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) +#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) +#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) +#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name)) +#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) +#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) +#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) +#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) +#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) +#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name)) +#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) +#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) +#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name)) +#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) +#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) +#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) +#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) + +/** + * usb_gadget_controller_number - support bcdDevice id convention + * @gadget: the controller being driven + * + * Return a 2-digit BCD value associated with the peripheral controller, + * suitable for use as part of a bcdDevice value, or a negative error code. + * + * NOTE: this convention is purely optional, and has no meaning in terms of + * any USB specification. If you want to use a different convention in your + * gadget driver firmware -- maybe a more formal revision ID -- feel free. + * + * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) + * to change their behavior accordingly. For example it might help avoiding + * some chip bug. + */ +static inline int usb_gadget_controller_number(struct usb_gadget *gadget) +{ + if (gadget_is_net2280(gadget)) + return 0x01; + else if (gadget_is_dummy(gadget)) + return 0x02; + else if (gadget_is_pxa(gadget)) + return 0x03; + else if (gadget_is_goku(gadget)) + return 0x06; + else if (gadget_is_omap(gadget)) + return 0x08; + else if (gadget_is_pxa27x(gadget)) + return 0x11; + else if (gadget_is_s3c2410(gadget)) + return 0x12; + else if (gadget_is_at91(gadget)) + return 0x13; + else if (gadget_is_imx(gadget)) + return 0x14; + else if (gadget_is_musbhdrc(gadget)) + return 0x16; + else if (gadget_is_atmel_usba(gadget)) + return 0x18; + else if (gadget_is_fsl_usb2(gadget)) + return 0x19; + else if (gadget_is_amd5536udc(gadget)) + return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; + else if (gadget_is_fsl_qe(gadget)) + return 0x22; + else if (gadget_is_ci13xxx_pci(gadget)) + return 0x23; + else if (gadget_is_langwell(gadget)) + return 0x24; + else if (gadget_is_r8a66597(gadget)) + return 0x25; + else if (gadget_is_s3c_hsotg(gadget)) + return 0x26; + else if (gadget_is_pch(gadget)) + return 0x27; + else if (gadget_is_ci13xxx_msm(gadget)) + return 0x28; + else if (gadget_is_renesas_usbhs(gadget)) + return 0x29; + else if (gadget_is_s3c_hsudc(gadget)) + return 0x30; + else if (gadget_is_net2272(gadget)) + return 0x31; + else if (gadget_is_dwc3(gadget)) + return 0x32; + else if (gadget_is_lpc32xx(gadget)) + return 0x33; + else if (gadget_is_bcm63xx(gadget)) + return 0x34; + + return -ENOENT; +} + + +/** + * gadget_supports_altsettings - return true if altsettings work + * @gadget: the gadget in question + */ +static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) +{ + /* PXA 21x/25x/26x has no altsettings at all */ + if (gadget_is_pxa(gadget)) + return false; + + /* PXA 27x and 3xx have *broken* altsetting support */ + if (gadget_is_pxa27x(gadget)) + return false; + + /* Everything else is *presumably* fine ... */ + return true; +} + +#endif /* __GADGET_CHIPS_H */ diff --git a/drivers/staging/ccg/ndis.h b/drivers/staging/ccg/ndis.h new file mode 100644 index 0000000..a19f72d --- /dev/null +++ b/drivers/staging/ccg/ndis.h @@ -0,0 +1,47 @@ +/* + * ndis.h + * + * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de> + * + * Thanks to the cygwin development team, + * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net> + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + */ + +#ifndef _LINUX_NDIS_H +#define _LINUX_NDIS_H + +enum NDIS_DEVICE_POWER_STATE { + NdisDeviceStateUnspecified = 0, + NdisDeviceStateD0, + NdisDeviceStateD1, + NdisDeviceStateD2, + NdisDeviceStateD3, + NdisDeviceStateMaximum +}; + +struct NDIS_PM_WAKE_UP_CAPABILITIES { + enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp; + enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp; + enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp; +}; + +struct NDIS_PNP_CAPABILITIES { + __le32 Flags; + struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; +}; + +struct NDIS_PM_PACKET_PATTERN { + __le32 Priority; + __le32 Reserved; + __le32 MaskSize; + __le32 PatternOffset; + __le32 PatternSize; + __le32 PatternFlags; +}; + +#endif /* _LINUX_NDIS_H */ diff --git a/drivers/staging/ccg/rndis.c b/drivers/staging/ccg/rndis.c new file mode 100644 index 0000000..e4192b8 --- /dev/null +++ b/drivers/staging/ccg/rndis.c @@ -0,0 +1,1175 @@ +/* + * RNDIS MSG parser + * + * Authors: Benedikt Spranger, Pengutronix + * Robert Schwebel, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This software was originally developed in conformance with + * Microsoft's Remote NDIS Specification License Agreement. + * + * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de> + * Fixed message length bug in init_response + * + * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de> + * Fixed rndis_rm_hdr length bug. + * + * Copyright (C) 2004 by David Brownell + * updates to merge with Linux 2.6, better match RNDIS spec + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <linux/seq_file.h> +#include <linux/netdevice.h> + +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> + + +#undef VERBOSE_DEBUG + +#include "rndis.h" + + +/* The driver for your USB chip needs to support ep0 OUT to work with + * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). + * + * Windows hosts need an INF file like Documentation/usb/linux.inf + * and will be happier if you provide the host_addr module parameter. + */ + +#if 0 +static int rndis_debug = 0; +module_param (rndis_debug, int, 0); +MODULE_PARM_DESC (rndis_debug, "enable debugging"); +#else +#define rndis_debug 0 +#endif + +#define RNDIS_MAX_CONFIGS 1 + + +static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; + +/* Driver Version */ +static const __le32 rndis_driver_version = cpu_to_le32(1); + +/* Function Prototypes */ +static rndis_resp_t *rndis_add_response(int configNr, u32 length); + + +/* supported OIDs */ +static const u32 oid_supported_list[] = +{ + /* the general stuff */ + RNDIS_OID_GEN_SUPPORTED_LIST, + RNDIS_OID_GEN_HARDWARE_STATUS, + RNDIS_OID_GEN_MEDIA_SUPPORTED, + RNDIS_OID_GEN_MEDIA_IN_USE, + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, + RNDIS_OID_GEN_LINK_SPEED, + RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE, + RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE, + RNDIS_OID_GEN_VENDOR_ID, + RNDIS_OID_GEN_VENDOR_DESCRIPTION, + RNDIS_OID_GEN_VENDOR_DRIVER_VERSION, + RNDIS_OID_GEN_CURRENT_PACKET_FILTER, + RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE, + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, + + /* the statistical stuff */ + RNDIS_OID_GEN_XMIT_OK, + RNDIS_OID_GEN_RCV_OK, + RNDIS_OID_GEN_XMIT_ERROR, + RNDIS_OID_GEN_RCV_ERROR, + RNDIS_OID_GEN_RCV_NO_BUFFER, +#ifdef RNDIS_OPTIONAL_STATS + RNDIS_OID_GEN_DIRECTED_BYTES_XMIT, + RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT, + RNDIS_OID_GEN_MULTICAST_BYTES_XMIT, + RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT, + RNDIS_OID_GEN_BROADCAST_BYTES_XMIT, + RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT, + RNDIS_OID_GEN_DIRECTED_BYTES_RCV, + RNDIS_OID_GEN_DIRECTED_FRAMES_RCV, + RNDIS_OID_GEN_MULTICAST_BYTES_RCV, + RNDIS_OID_GEN_MULTICAST_FRAMES_RCV, + RNDIS_OID_GEN_BROADCAST_BYTES_RCV, + RNDIS_OID_GEN_BROADCAST_FRAMES_RCV, + RNDIS_OID_GEN_RCV_CRC_ERROR, + RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH, +#endif /* RNDIS_OPTIONAL_STATS */ + + /* mandatory 802.3 */ + /* the general stuff */ + RNDIS_OID_802_3_PERMANENT_ADDRESS, + RNDIS_OID_802_3_CURRENT_ADDRESS, + RNDIS_OID_802_3_MULTICAST_LIST, + RNDIS_OID_802_3_MAC_OPTIONS, + RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT, + RNDIS_OID_802_3_XMIT_ONE_COLLISION, + RNDIS_OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef RNDIS_OPTIONAL_STATS + RNDIS_OID_802_3_XMIT_DEFERRED, + RNDIS_OID_802_3_XMIT_MAX_COLLISIONS, + RNDIS_OID_802_3_RCV_OVERRUN, + RNDIS_OID_802_3_XMIT_UNDERRUN, + RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE, + RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST, + RNDIS_OID_802_3_XMIT_LATE_COLLISIONS, +#endif /* RNDIS_OPTIONAL_STATS */ + +#ifdef RNDIS_PM + /* PM and wakeup are "mandatory" for USB, but the RNDIS specs + * don't say what they mean ... and the NDIS specs are often + * confusing and/or ambiguous in this context. (That is, more + * so than their specs for the other OIDs.) + * + * FIXME someone who knows what these should do, please + * implement them! + */ + + /* power management */ + OID_PNP_CAPABILITIES, + OID_PNP_QUERY_POWER, + OID_PNP_SET_POWER, + +#ifdef RNDIS_WAKEUP + /* wake up host */ + OID_PNP_ENABLE_WAKE_UP, + OID_PNP_ADD_WAKE_UP_PATTERN, + OID_PNP_REMOVE_WAKE_UP_PATTERN, +#endif /* RNDIS_WAKEUP */ +#endif /* RNDIS_PM */ +}; + + +/* NDIS Functions */ +static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, + unsigned buf_len, rndis_resp_t *r) +{ + int retval = -ENOTSUPP; + u32 length = 4; /* usually */ + __le32 *outbuf; + int i, count; + rndis_query_cmplt_type *resp; + struct net_device *net; + struct rtnl_link_stats64 temp; + const struct rtnl_link_stats64 *stats; + + if (!r) return -ENOMEM; + resp = (rndis_query_cmplt_type *)r->buf; + + if (!resp) return -ENOMEM; + + if (buf_len && rndis_debug > 1) { + pr_debug("query OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + pr_debug("%03d: %08x %08x %08x %08x\n", i, + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); + } + } + + /* response goes here, right after the header */ + outbuf = (__le32 *)&resp[1]; + resp->InformationBufferOffset = cpu_to_le32(16); + + net = rndis_per_dev_params[configNr].dev; + stats = dev_get_stats(net, &temp); + + switch (OID) { + + /* general oids (table 4-1) */ + + /* mandatory */ + case RNDIS_OID_GEN_SUPPORTED_LIST: + pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__); + length = sizeof(oid_supported_list); + count = length / sizeof(u32); + for (i = 0; i < count; i++) + outbuf[i] = cpu_to_le32(oid_supported_list[i]); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_HARDWARE_STATUS: + pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__); + /* Bogus question! + * Hardware must be ready to receive high level protocols. + * BTW: + * reddite ergo quae sunt Caesaris Caesari + * et quae sunt Dei Deo! + */ + *outbuf = cpu_to_le32(0); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_MEDIA_SUPPORTED: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__); + *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_MEDIA_IN_USE: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__); + /* one medium, one transport... (maybe you do it better) */ + *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); + if (rndis_per_dev_params[configNr].dev) { + *outbuf = cpu_to_le32( + rndis_per_dev_params[configNr].dev->mtu); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_LINK_SPEED: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__); + if (rndis_per_dev_params[configNr].media_state + == RNDIS_MEDIA_STATE_DISCONNECTED) + *outbuf = cpu_to_le32(0); + else + *outbuf = cpu_to_le32( + rndis_per_dev_params[configNr].speed); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); + if (rndis_per_dev_params[configNr].dev) { + *outbuf = cpu_to_le32( + rndis_per_dev_params[configNr].dev->mtu); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); + if (rndis_per_dev_params[configNr].dev) { + *outbuf = cpu_to_le32( + rndis_per_dev_params[configNr].dev->mtu); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_VENDOR_ID: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__); + *outbuf = cpu_to_le32( + rndis_per_dev_params[configNr].vendorID); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_VENDOR_DESCRIPTION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__); + if (rndis_per_dev_params[configNr].vendorDescr) { + length = strlen(rndis_per_dev_params[configNr]. + vendorDescr); + memcpy(outbuf, + rndis_per_dev_params[configNr].vendorDescr, + length); + } else { + outbuf[0] = 0; + } + retval = 0; + break; + + case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); + /* Created as LE */ + *outbuf = rndis_driver_version; + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__); + *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); + *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); + *outbuf = cpu_to_le32(rndis_per_dev_params[configNr] + .media_state); + retval = 0; + break; + + case RNDIS_OID_GEN_PHYSICAL_MEDIUM: + pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__); + *outbuf = cpu_to_le32(0); + retval = 0; + break; + + /* The RNDIS specification is incomplete/wrong. Some versions + * of MS-Windows expect OIDs that aren't specified there. Other + * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! + */ + case RNDIS_OID_GEN_MAC_OPTIONS: /* from WinME */ + pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__); + *outbuf = cpu_to_le32( + RNDIS_MAC_OPTION_RECEIVE_SERIALIZED + | RNDIS_MAC_OPTION_FULL_DUPLEX); + retval = 0; + break; + + /* statistics OIDs (table 4-2) */ + + /* mandatory */ + case RNDIS_OID_GEN_XMIT_OK: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->tx_packets + - stats->tx_errors - stats->tx_dropped); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_RCV_OK: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->rx_packets + - stats->rx_errors - stats->rx_dropped); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_XMIT_ERROR: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->tx_errors); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_RCV_ERROR: + if (rndis_debug > 1) + pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->rx_errors); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_GEN_RCV_NO_BUFFER: + pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->rx_dropped); + retval = 0; + } + break; + + /* ieee802.3 OIDs (table 4-3) */ + + /* mandatory */ + case RNDIS_OID_802_3_PERMANENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__); + if (rndis_per_dev_params[configNr].dev) { + length = ETH_ALEN; + memcpy(outbuf, + rndis_per_dev_params[configNr].host_mac, + length); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_802_3_CURRENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__); + if (rndis_per_dev_params[configNr].dev) { + length = ETH_ALEN; + memcpy(outbuf, + rndis_per_dev_params [configNr].host_mac, + length); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_802_3_MULTICAST_LIST: + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); + /* Multicast base address only */ + *outbuf = cpu_to_le32(0xE0000000); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE: + pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); + /* Multicast base address only */ + *outbuf = cpu_to_le32(1); + retval = 0; + break; + + case RNDIS_OID_802_3_MAC_OPTIONS: + pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__); + *outbuf = cpu_to_le32(0); + retval = 0; + break; + + /* ieee802.3 statistics OIDs (table 4-4) */ + + /* mandatory */ + case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT: + pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); + if (stats) { + *outbuf = cpu_to_le32(stats->rx_frame_errors); + retval = 0; + } + break; + + /* mandatory */ + case RNDIS_OID_802_3_XMIT_ONE_COLLISION: + pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__); + *outbuf = cpu_to_le32(0); + retval = 0; + break; + + /* mandatory */ + case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS: + pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); + *outbuf = cpu_to_le32(0); + retval = 0; + break; + + default: + pr_warning("%s: query unknown OID 0x%08X\n", + __func__, OID); + } + if (retval < 0) + length = 0; + + resp->InformationBufferLength = cpu_to_le32(length); + r->length = length + sizeof(*resp); + resp->MessageLength = cpu_to_le32(r->length); + return retval; +} + +static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, + rndis_resp_t *r) +{ + rndis_set_cmplt_type *resp; + int i, retval = -ENOTSUPP; + struct rndis_params *params; + + if (!r) + return -ENOMEM; + resp = (rndis_set_cmplt_type *)r->buf; + if (!resp) + return -ENOMEM; + + if (buf_len && rndis_debug > 1) { + pr_debug("set OID %08x value, len %d:\n", OID, buf_len); + for (i = 0; i < buf_len; i += 16) { + pr_debug("%03d: %08x %08x %08x %08x\n", i, + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); + } + } + + params = &rndis_per_dev_params[configNr]; + switch (OID) { + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: + + /* these NDIS_PACKET_TYPE_* bitflags are shared with + * cdc_filter; it's not RNDIS-specific + * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: + * PROMISCUOUS, DIRECTED, + * MULTICAST, ALL_MULTICAST, BROADCAST + */ + *params->filter = (u16)get_unaligned_le32(buf); + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n", + __func__, *params->filter); + + /* this call has a significant side effect: it's + * what makes the packet flow start and stop, like + * activating the CDC Ethernet altsetting. + */ + retval = 0; + if (*params->filter) { + params->state = RNDIS_DATA_INITIALIZED; + netif_carrier_on(params->dev); + if (netif_running(params->dev)) + netif_wake_queue(params->dev); + } else { + params->state = RNDIS_INITIALIZED; + netif_carrier_off(params->dev); + netif_stop_queue(params->dev); + } + break; + + case RNDIS_OID_802_3_MULTICAST_LIST: + /* I think we can ignore this */ + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); + retval = 0; + break; + + default: + pr_warning("%s: set unknown OID 0x%08X, size %d\n", + __func__, OID, buf_len); + } + + return retval; +} + +/* + * Response Functions + */ + +static int rndis_init_response(int configNr, rndis_init_msg_type *buf) +{ + rndis_init_cmplt_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + if (!params->dev) + return -ENOTSUPP; + + r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_init_cmplt_type *)r->buf; + + resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C); + resp->MessageLength = cpu_to_le32(52); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION); + resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); + resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); + resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); + resp->MaxPacketsPerTransfer = cpu_to_le32(1); + resp->MaxTransferSize = cpu_to_le32( + params->dev->mtu + + sizeof(struct ethhdr) + + sizeof(struct rndis_packet_msg_type) + + 22); + resp->PacketAlignmentFactor = cpu_to_le32(0); + resp->AFListOffset = cpu_to_le32(0); + resp->AFListSize = cpu_to_le32(0); + + params->resp_avail(params->v); + return 0; +} + +static int rndis_query_response(int configNr, rndis_query_msg_type *buf) +{ + rndis_query_cmplt_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */ + if (!params->dev) + return -ENOTSUPP; + + /* + * we need more memory: + * gen_ndis_query_resp expects enough space for + * rndis_query_cmplt_type followed by data. + * oid_supported_list is the largest data reply + */ + r = rndis_add_response(configNr, + sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_query_cmplt_type *)r->buf; + + resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + + if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID), + le32_to_cpu(buf->InformationBufferOffset) + + 8 + (u8 *)buf, + le32_to_cpu(buf->InformationBufferLength), + r)) { + /* OID not supported */ + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); + resp->MessageLength = cpu_to_le32(sizeof *resp); + resp->InformationBufferLength = cpu_to_le32(0); + resp->InformationBufferOffset = cpu_to_le32(0); + } else + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + + params->resp_avail(params->v); + return 0; +} + +static int rndis_set_response(int configNr, rndis_set_msg_type *buf) +{ + u32 BufLength, BufOffset; + rndis_set_cmplt_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_set_cmplt_type *)r->buf; + + BufLength = le32_to_cpu(buf->InformationBufferLength); + BufOffset = le32_to_cpu(buf->InformationBufferOffset); + +#ifdef VERBOSE_DEBUG + pr_debug("%s: Length: %d\n", __func__, BufLength); + pr_debug("%s: Offset: %d\n", __func__, BufOffset); + pr_debug("%s: InfoBuffer: ", __func__); + + for (i = 0; i < BufLength; i++) { + pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); + } + + pr_debug("\n"); +#endif + + resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C); + resp->MessageLength = cpu_to_le32(16); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID), + ((u8 *)buf) + 8 + BufOffset, BufLength, r)) + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); + else + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + + params->resp_avail(params->v); + return 0; +} + +static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) +{ + rndis_reset_cmplt_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_reset_cmplt_type *)r->buf; + + resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C); + resp->MessageLength = cpu_to_le32(16); + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + /* resent information */ + resp->AddressingReset = cpu_to_le32(1); + + params->resp_avail(params->v); + return 0; +} + +static int rndis_keepalive_response(int configNr, + rndis_keepalive_msg_type *buf) +{ + rndis_keepalive_cmplt_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + /* host "should" check only in RNDIS_DATA_INITIALIZED state */ + + r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_keepalive_cmplt_type *)r->buf; + + resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); + resp->MessageLength = cpu_to_le32(16); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ + resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); + + params->resp_avail(params->v); + return 0; +} + + +/* + * Device to Host Comunication + */ +static int rndis_indicate_status_msg(int configNr, u32 status) +{ + rndis_indicate_status_msg_type *resp; + rndis_resp_t *r; + struct rndis_params *params = rndis_per_dev_params + configNr; + + if (params->state == RNDIS_UNINITIALIZED) + return -ENOTSUPP; + + r = rndis_add_response(configNr, + sizeof(rndis_indicate_status_msg_type)); + if (!r) + return -ENOMEM; + resp = (rndis_indicate_status_msg_type *)r->buf; + + resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE); + resp->MessageLength = cpu_to_le32(20); + resp->Status = cpu_to_le32(status); + resp->StatusBufferLength = cpu_to_le32(0); + resp->StatusBufferOffset = cpu_to_le32(0); + + params->resp_avail(params->v); + return 0; +} + +int rndis_signal_connect(int configNr) +{ + rndis_per_dev_params[configNr].media_state + = RNDIS_MEDIA_STATE_CONNECTED; + return rndis_indicate_status_msg(configNr, + RNDIS_STATUS_MEDIA_CONNECT); +} + +int rndis_signal_disconnect(int configNr) +{ + rndis_per_dev_params[configNr].media_state + = RNDIS_MEDIA_STATE_DISCONNECTED; + return rndis_indicate_status_msg(configNr, + RNDIS_STATUS_MEDIA_DISCONNECT); +} + +void rndis_uninit(int configNr) +{ + u8 *buf; + u32 length; + + if (configNr >= RNDIS_MAX_CONFIGS) + return; + rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED; + + /* drain the response queue */ + while ((buf = rndis_get_next_response(configNr, &length))) + rndis_free_response(configNr, buf); +} + +void rndis_set_host_mac(int configNr, const u8 *addr) +{ + rndis_per_dev_params[configNr].host_mac = addr; +} + +/* + * Message Parser + */ +int rndis_msg_parser(u8 configNr, u8 *buf) +{ + u32 MsgType, MsgLength; + __le32 *tmp; + struct rndis_params *params; + + if (!buf) + return -ENOMEM; + + tmp = (__le32 *)buf; + MsgType = get_unaligned_le32(tmp++); + MsgLength = get_unaligned_le32(tmp++); + + if (configNr >= RNDIS_MAX_CONFIGS) + return -ENOTSUPP; + params = &rndis_per_dev_params[configNr]; + + /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for + * rx/tx statistics and link status, in addition to KEEPALIVE traffic + * and normal HC level polling to see if there's any IN traffic. + */ + + /* For USB: responses may take up to 10 seconds */ + switch (MsgType) { + case RNDIS_MSG_INIT: + pr_debug("%s: RNDIS_MSG_INIT\n", + __func__); + params->state = RNDIS_INITIALIZED; + return rndis_init_response(configNr, + (rndis_init_msg_type *)buf); + + case RNDIS_MSG_HALT: + pr_debug("%s: RNDIS_MSG_HALT\n", + __func__); + params->state = RNDIS_UNINITIALIZED; + if (params->dev) { + netif_carrier_off(params->dev); + netif_stop_queue(params->dev); + } + return 0; + + case RNDIS_MSG_QUERY: + return rndis_query_response(configNr, + (rndis_query_msg_type *)buf); + + case RNDIS_MSG_SET: + return rndis_set_response(configNr, + (rndis_set_msg_type *)buf); + + case RNDIS_MSG_RESET: + pr_debug("%s: RNDIS_MSG_RESET\n", + __func__); + return rndis_reset_response(configNr, + (rndis_reset_msg_type *)buf); + + case RNDIS_MSG_KEEPALIVE: + /* For USB: host does this every 5 seconds */ + if (rndis_debug > 1) + pr_debug("%s: RNDIS_MSG_KEEPALIVE\n", + __func__); + return rndis_keepalive_response(configNr, + (rndis_keepalive_msg_type *) + buf); + + default: + /* At least Windows XP emits some undefined RNDIS messages. + * In one case those messages seemed to relate to the host + * suspending itself. + */ + pr_warning("%s: unknown RNDIS message 0x%08X len %d\n", + __func__, MsgType, MsgLength); + print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET, + buf, MsgLength); + break; + } + + return -ENOTSUPP; +} + +int rndis_register(void (*resp_avail)(void *v), void *v) +{ + u8 i; + + if (!resp_avail) + return -EINVAL; + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { + if (!rndis_per_dev_params[i].used) { + rndis_per_dev_params[i].used = 1; + rndis_per_dev_params[i].resp_avail = resp_avail; + rndis_per_dev_params[i].v = v; + pr_debug("%s: configNr = %d\n", __func__, i); + return i; + } + } + pr_debug("failed\n"); + + return -ENODEV; +} + +void rndis_deregister(int configNr) +{ + pr_debug("%s:\n", __func__); + + if (configNr >= RNDIS_MAX_CONFIGS) return; + rndis_per_dev_params[configNr].used = 0; +} + +int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) +{ + pr_debug("%s:\n", __func__); + if (!dev) + return -EINVAL; + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params[configNr].dev = dev; + rndis_per_dev_params[configNr].filter = cdc_filter; + + return 0; +} + +int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) +{ + pr_debug("%s:\n", __func__); + if (!vendorDescr) return -1; + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params[configNr].vendorID = vendorID; + rndis_per_dev_params[configNr].vendorDescr = vendorDescr; + + return 0; +} + +int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) +{ + pr_debug("%s: %u %u\n", __func__, medium, speed); + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params[configNr].medium = medium; + rndis_per_dev_params[configNr].speed = speed; + + return 0; +} + +void rndis_add_hdr(struct sk_buff *skb) +{ + struct rndis_packet_msg_type *header; + + if (!skb) + return; + header = (void *)skb_push(skb, sizeof(*header)); + memset(header, 0, sizeof *header); + header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET); + header->MessageLength = cpu_to_le32(skb->len); + header->DataOffset = cpu_to_le32(36); + header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); +} + +void rndis_free_response(int configNr, u8 *buf) +{ + rndis_resp_t *r; + struct list_head *act, *tmp; + + list_for_each_safe(act, tmp, + &(rndis_per_dev_params[configNr].resp_queue)) + { + r = list_entry(act, rndis_resp_t, list); + if (r && r->buf == buf) { + list_del(&r->list); + kfree(r); + } + } +} + +u8 *rndis_get_next_response(int configNr, u32 *length) +{ + rndis_resp_t *r; + struct list_head *act, *tmp; + + if (!length) return NULL; + + list_for_each_safe(act, tmp, + &(rndis_per_dev_params[configNr].resp_queue)) + { + r = list_entry(act, rndis_resp_t, list); + if (!r->send) { + r->send = 1; + *length = r->length; + return r->buf; + } + } + + return NULL; +} + +static rndis_resp_t *rndis_add_response(int configNr, u32 length) +{ + rndis_resp_t *r; + + /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ + r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC); + if (!r) return NULL; + + r->buf = (u8 *)(r + 1); + r->length = length; + r->send = 0; + + list_add_tail(&r->list, + &(rndis_per_dev_params[configNr].resp_queue)); + return r; +} + +int rndis_rm_hdr(struct gether *port, + struct sk_buff *skb, + struct sk_buff_head *list) +{ + /* tmp points to a struct rndis_packet_msg_type */ + __le32 *tmp = (void *)skb->data; + + /* MessageType, MessageLength */ + if (cpu_to_le32(RNDIS_MSG_PACKET) + != get_unaligned(tmp++)) { + dev_kfree_skb_any(skb); + return -EINVAL; + } + tmp++; + + /* DataOffset, DataLength */ + if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) { + dev_kfree_skb_any(skb); + return -EOVERFLOW; + } + skb_trim(skb, get_unaligned_le32(tmp++)); + + skb_queue_tail(list, skb); + return 0; +} + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static int rndis_proc_show(struct seq_file *m, void *v) +{ + rndis_params *param = m->private; + + seq_printf(m, + "Config Nr. %d\n" + "used : %s\n" + "state : %s\n" + "medium : 0x%08X\n" + "speed : %d\n" + "cable : %s\n" + "vendor ID : 0x%08X\n" + "vendor : %s\n", + param->confignr, (param->used) ? "y" : "n", + ({ char *s = "?"; + switch (param->state) { + case RNDIS_UNINITIALIZED: + s = "RNDIS_UNINITIALIZED"; break; + case RNDIS_INITIALIZED: + s = "RNDIS_INITIALIZED"; break; + case RNDIS_DATA_INITIALIZED: + s = "RNDIS_DATA_INITIALIZED"; break; + }; s; }), + param->medium, + (param->media_state) ? 0 : param->speed*100, + (param->media_state) ? "disconnected" : "connected", + param->vendorID, param->vendorDescr); + return 0; +} + +static ssize_t rndis_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + rndis_params *p = PDE(file->f_path.dentry->d_inode)->data; + u32 speed = 0; + int i, fl_speed = 0; + + for (i = 0; i < count; i++) { + char c; + if (get_user(c, buffer)) + return -EFAULT; + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fl_speed = 1; + speed = speed * 10 + c - '0'; + break; + case 'C': + case 'c': + rndis_signal_connect(p->confignr); + break; + case 'D': + case 'd': + rndis_signal_disconnect(p->confignr); + break; + default: + if (fl_speed) p->speed = speed; + else pr_debug("%c is not valid\n", c); + break; + } + + buffer++; + } + + return count; +} + +static int rndis_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rndis_proc_show, PDE(inode)->data); +} + +static const struct file_operations rndis_proc_fops = { + .owner = THIS_MODULE, + .open = rndis_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = rndis_proc_write, +}; + +#define NAME_TEMPLATE "driver/rndis-%03d" + +static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + + +int rndis_init(void) +{ + u8 i; + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + char name [20]; + + sprintf(name, NAME_TEMPLATE, i); + rndis_connect_state[i] = proc_create_data(name, 0660, NULL, + &rndis_proc_fops, + (void *)(rndis_per_dev_params + i)); + if (!rndis_connect_state[i]) { + pr_debug("%s: remove entries", __func__); + while (i) { + sprintf(name, NAME_TEMPLATE, --i); + remove_proc_entry(name, NULL); + } + pr_debug("\n"); + return -EIO; + } +#endif + rndis_per_dev_params[i].confignr = i; + rndis_per_dev_params[i].used = 0; + rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED; + rndis_per_dev_params[i].media_state + = RNDIS_MEDIA_STATE_DISCONNECTED; + INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); + } + + return 0; +} + +void rndis_exit(void) +{ +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + u8 i; + char name[20]; + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { + sprintf(name, NAME_TEMPLATE, i); + remove_proc_entry(name, NULL); + } +#endif +} diff --git a/drivers/staging/ccg/rndis.h b/drivers/staging/ccg/rndis.h new file mode 100644 index 0000000..0647f2f --- /dev/null +++ b/drivers/staging/ccg/rndis.h @@ -0,0 +1,222 @@ +/* + * RNDIS Definitions for Remote NDIS + * + * Authors: Benedikt Spranger, Pengutronix + * Robert Schwebel, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This software was originally developed in conformance with + * Microsoft's Remote NDIS Specification License Agreement. + */ + +#ifndef _LINUX_RNDIS_H +#define _LINUX_RNDIS_H + +#include <linux/rndis.h> +#include "ndis.h" + +#define RNDIS_MAXIMUM_FRAME_SIZE 1518 +#define RNDIS_MAX_TOTAL_SIZE 1558 + +typedef struct rndis_init_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 MajorVersion; + __le32 MinorVersion; + __le32 MaxTransferSize; +} rndis_init_msg_type; + +typedef struct rndis_init_cmplt_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 Status; + __le32 MajorVersion; + __le32 MinorVersion; + __le32 DeviceFlags; + __le32 Medium; + __le32 MaxPacketsPerTransfer; + __le32 MaxTransferSize; + __le32 PacketAlignmentFactor; + __le32 AFListOffset; + __le32 AFListSize; +} rndis_init_cmplt_type; + +typedef struct rndis_halt_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; +} rndis_halt_msg_type; + +typedef struct rndis_query_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 OID; + __le32 InformationBufferLength; + __le32 InformationBufferOffset; + __le32 DeviceVcHandle; +} rndis_query_msg_type; + +typedef struct rndis_query_cmplt_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 Status; + __le32 InformationBufferLength; + __le32 InformationBufferOffset; +} rndis_query_cmplt_type; + +typedef struct rndis_set_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 OID; + __le32 InformationBufferLength; + __le32 InformationBufferOffset; + __le32 DeviceVcHandle; +} rndis_set_msg_type; + +typedef struct rndis_set_cmplt_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 Status; +} rndis_set_cmplt_type; + +typedef struct rndis_reset_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 Reserved; +} rndis_reset_msg_type; + +typedef struct rndis_reset_cmplt_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 Status; + __le32 AddressingReset; +} rndis_reset_cmplt_type; + +typedef struct rndis_indicate_status_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 Status; + __le32 StatusBufferLength; + __le32 StatusBufferOffset; +} rndis_indicate_status_msg_type; + +typedef struct rndis_keepalive_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; +} rndis_keepalive_msg_type; + +typedef struct rndis_keepalive_cmplt_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 RequestID; + __le32 Status; +} rndis_keepalive_cmplt_type; + +struct rndis_packet_msg_type +{ + __le32 MessageType; + __le32 MessageLength; + __le32 DataOffset; + __le32 DataLength; + __le32 OOBDataOffset; + __le32 OOBDataLength; + __le32 NumOOBDataElements; + __le32 PerPacketInfoOffset; + __le32 PerPacketInfoLength; + __le32 VcHandle; + __le32 Reserved; +} __attribute__ ((packed)); + +struct rndis_config_parameter +{ + __le32 ParameterNameOffset; + __le32 ParameterNameLength; + __le32 ParameterType; + __le32 ParameterValueOffset; + __le32 ParameterValueLength; +}; + +/* implementation specific */ +enum rndis_state +{ + RNDIS_UNINITIALIZED, + RNDIS_INITIALIZED, + RNDIS_DATA_INITIALIZED, +}; + +typedef struct rndis_resp_t +{ + struct list_head list; + u8 *buf; + u32 length; + int send; +} rndis_resp_t; + +typedef struct rndis_params +{ + u8 confignr; + u8 used; + u16 saved_filter; + enum rndis_state state; + u32 medium; + u32 speed; + u32 media_state; + + const u8 *host_mac; + u16 *filter; + struct net_device *dev; + + u32 vendorID; + const char *vendorDescr; + void (*resp_avail)(void *v); + void *v; + struct list_head resp_queue; +} rndis_params; + +/* RNDIS Message parser and other useless functions */ +int rndis_msg_parser (u8 configNr, u8 *buf); +int rndis_register(void (*resp_avail)(void *v), void *v); +void rndis_deregister (int configNr); +int rndis_set_param_dev (u8 configNr, struct net_device *dev, + u16 *cdc_filter); +int rndis_set_param_vendor (u8 configNr, u32 vendorID, + const char *vendorDescr); +int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); +void rndis_add_hdr (struct sk_buff *skb); +int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, + struct sk_buff_head *list); +u8 *rndis_get_next_response (int configNr, u32 *length); +void rndis_free_response (int configNr, u8 *buf); + +void rndis_uninit (int configNr); +int rndis_signal_connect (int configNr); +int rndis_signal_disconnect (int configNr); +int rndis_state (int configNr); +extern void rndis_set_host_mac (int configNr, const u8 *addr); + +int rndis_init(void); +void rndis_exit (void); + +#endif /* _LINUX_RNDIS_H */ diff --git a/drivers/staging/ccg/storage_common.c b/drivers/staging/ccg/storage_common.c new file mode 100644 index 0000000..8d9bcd8 --- /dev/null +++ b/drivers/staging/ccg/storage_common.c @@ -0,0 +1,893 @@ +/* + * storage_common.c -- Common definitions for mass storage functionality + * + * Copyright (C) 2003-2008 Alan Stern + * Copyeight (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz (mina86@mina86.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +/* + * This file requires the following identifiers used in USB strings to + * be defined (each of type pointer to char): + * - fsg_string_manufacturer -- name of the manufacturer + * - fsg_string_product -- name of the product + * - fsg_string_config -- name of the configuration + * - fsg_string_interface -- name of the interface + * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS + * macro is defined prior to including this file. + */ + +/* + * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and + * fsg_hs_intr_in_desc objects as well as + * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES + * macros are not defined. + * + * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, + * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not + * defined (as well as corresponding entries in string tables are + * missing) and FSG_STRING_INTERFACE has value of zero. + * + * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. + */ + +/* + * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers + * sets the number of pipeline buffers (length of the fsg_buffhd array). + * The valid range of num_buffers is: num >= 2 && num <= 4. + */ + + +#include <linux/usb/storage.h> +#include <scsi/scsi.h> +#include <asm/unaligned.h> + + +/* + * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define FSG_VENDOR_ID 0x0525 /* NetChip */ +#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + + +/*-------------------------------------------------------------------------*/ + + +#ifndef DEBUG +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* !DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VLDBG LDBG +#else +#define VLDBG(lun, fmt, args...) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args) +#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) +#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) +#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) + +/* + * Keep those macros in sync with those in + * include/linux/usb/composite.h or else GCC will complain. If they + * are identical (the same names of arguments, white spaces in the + * same places) GCC will allow redefinition otherwise (even if some + * white space is removed or added) warning will be issued. + * + * Those macros are needed here because File Storage Gadget does not + * include the composite.h header. For composite gadgets those macros + * are redundant since composite.h is included any way. + * + * One could check whether those macros are already defined (which + * would indicate composite.h had been included) or not (which would + * indicate we were in FSG) but this is not done because a warning is + * desired if definitions here differ from the ones in composite.h. + * + * We want the definitions to match and be the same in File Storage + * Gadget as well as Mass Storage Function (and so composite gadgets + * using MSF). If someone changes them in composite.h it will produce + * a warning in this file when building MSF. + */ +#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args) + + + +#ifdef DUMP_MSGS + +# define dump_msg(fsg, /* const char * */ label, \ + /* const u8 * */ buf, /* unsigned */ length) do { \ + if (length < 512) { \ + DBG(fsg, "%s, length %u:\n", label, length); \ + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ + 16, 1, buf, length, 0); \ + } \ +} while (0) + +# define dump_cdb(fsg) do { } while (0) + +#else + +# define dump_msg(fsg, /* const char * */ label, \ + /* const u8 * */ buf, /* unsigned */ length) do { } while (0) + +# ifdef VERBOSE_DEBUG + +# define dump_cdb(fsg) \ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ + 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ + +# else + +# define dump_cdb(fsg) do { } while (0) + +# endif /* VERBOSE_DEBUG */ + +#endif /* DUMP_MSGS */ + +/*-------------------------------------------------------------------------*/ + +/* CBI Interrupt data structure */ +struct interrupt_data { + u8 bType; + u8 bValue; +}; + +#define CBI_INTERRUPT_DATA_LEN 2 + +/* CBI Accept Device-Specific Command request */ +#define USB_CBI_ADSC_REQUEST 0x00 + + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE 16 + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + + +/*-------------------------------------------------------------------------*/ + + +struct fsg_lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; + + unsigned int initially_ro:1; + unsigned int ro:1; + unsigned int removable:1; + unsigned int cdrom:1; + unsigned int prevent_medium_removal:1; + unsigned int registered:1; + unsigned int info_valid:1; + unsigned int nofua:1; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; + + unsigned int blkbits; /* Bits of logical block size of bound block device */ + unsigned int blksize; /* logical block size of bound block device */ + struct device dev; +}; + +#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) + +static struct fsg_lun *fsg_lun_from_dev(struct device *dev) +{ + return container_of(dev, struct fsg_lun, dev); +} + + +/* Big enough to hold our biggest descriptor */ +#define EP0_BUFSIZE 256 +#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; +module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); +MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(void) +{ + if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) + return 0; + pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", + fsg_num_buffers, 2 ,4); + return -EINVAL; +} + +/* Default size of buffer length. */ +#define FSG_BUFLEN ((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS 8 + +enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +struct fsg_buffhd { + void *buf; + enum fsg_buffer_state state; + struct fsg_buffhd *next; + + /* + * The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. + * So we will record the intended request length here. + */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; + int inreq_busy; + struct usb_request *outreq; + int outreq_busy; +}; + +enum fsg_state { + /* This one isn't used anywhere */ + FSG_STATE_COMMAND_PHASE = -10, + FSG_STATE_DATA_PHASE, + FSG_STATE_STATUS_PHASE, + + FSG_STATE_IDLE = 0, + FSG_STATE_ABORT_BULK_OUT, + FSG_STATE_RESET, + FSG_STATE_INTERFACE_CHANGE, + FSG_STATE_CONFIG_CHANGE, + FSG_STATE_DISCONNECT, + FSG_STATE_EXIT, + FSG_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + + +/*-------------------------------------------------------------------------*/ + + +static inline u32 get_unaligned_be24(u8 *buf) +{ + return 0xffffff & (u32) get_unaligned_be32(buf - 1); +} + + +/*-------------------------------------------------------------------------*/ + + +enum { +#ifndef FSG_NO_DEVICE_STRINGS + FSG_STRING_MANUFACTURER = 1, + FSG_STRING_PRODUCT, + FSG_STRING_SERIAL, + FSG_STRING_CONFIG, +#endif + FSG_STRING_INTERFACE +}; + + +#ifndef FSG_NO_OTG +static struct usb_otg_descriptor +fsg_otg_desc = { + .bLength = sizeof fsg_otg_desc, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; +#endif + +/* There is only one interface. */ + +static struct usb_interface_descriptor +fsg_intf_desc = { + .bLength = sizeof fsg_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ + .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ + .iInterface = FSG_STRING_INTERFACE, +}; + +/* + * Three full-speed endpoint descriptors: bulk-in, bulk-out, and + * interrupt-in. + */ + +static struct usb_endpoint_descriptor +fsg_fs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* wMaxPacketSize set by autoconfiguration */ +}; + +static struct usb_endpoint_descriptor +fsg_fs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* wMaxPacketSize set by autoconfiguration */ +}; + +#ifndef FSG_NO_INTR_EP + +static struct usb_endpoint_descriptor +fsg_fs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(2), + .bInterval = 32, /* frames -> 32 ms */ +}; + +#ifndef FSG_NO_OTG +# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 +#else +# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 +#endif + +#endif + +static struct usb_descriptor_header *fsg_fs_function[] = { +#ifndef FSG_NO_OTG + (struct usb_descriptor_header *) &fsg_otg_desc, +#endif + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, +#ifndef FSG_NO_INTR_EP + (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, +#endif + NULL, +}; + + +/* + * USB 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + * + * That means alternate endpoint descriptors (bigger packets) + * and a "device qualifier" ... plus more construction options + * for the configuration descriptor. + */ +static struct usb_endpoint_descriptor +fsg_hs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor +fsg_hs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), + .bInterval = 1, /* NAK every 1 uframe */ +}; + +#ifndef FSG_NO_INTR_EP + +static struct usb_endpoint_descriptor +fsg_hs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(2), + .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ +}; + +#ifndef FSG_NO_OTG +# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 +#else +# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 +#endif + +#endif + +static struct usb_descriptor_header *fsg_hs_function[] = { +#ifndef FSG_NO_OTG + (struct usb_descriptor_header *) &fsg_otg_desc, +#endif + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, +#ifndef FSG_NO_INTR_EP + (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, +#endif + NULL, +}; + +static struct usb_endpoint_descriptor +fsg_ss_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +static struct usb_endpoint_descriptor +fsg_ss_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +#ifndef FSG_NO_INTR_EP + +static struct usb_endpoint_descriptor +fsg_ss_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(2), + .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ +}; + +static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + .wBytesPerInterval = cpu_to_le16(2), +}; + +#ifndef FSG_NO_OTG +# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2 +#else +# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1 +#endif + +#endif + +static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = { + .bLength = USB_DT_USB_EXT_CAP_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_CAP_TYPE_EXT, + + .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT), +}; + +static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = { + .bLength = USB_DT_USB_SS_CAP_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_SS_CAP_TYPE, + + /* .bmAttributes = LTM is not supported yet */ + + .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION + | USB_FULL_SPEED_OPERATION + | USB_HIGH_SPEED_OPERATION + | USB_5GBPS_OPERATION), + .bFunctionalitySupport = USB_LOW_SPEED_OPERATION, + .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT, + .bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT), +}; + +static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + + .wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE + + USB_DT_USB_EXT_CAP_SIZE + + USB_DT_USB_SS_CAP_SIZE), + + .bNumDeviceCaps = 2, +}; + +static struct usb_descriptor_header *fsg_ss_function[] = { +#ifndef FSG_NO_OTG + (struct usb_descriptor_header *) &fsg_otg_desc, +#endif + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, +#ifndef FSG_NO_INTR_EP + (struct usb_descriptor_header *) &fsg_ss_intr_in_desc, + (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc, +#endif + NULL, +}; + +/* Maxpacket and other transfer characteristics vary by speed. */ +static __maybe_unused struct usb_endpoint_descriptor * +fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *ss) +{ + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return ss; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + + +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +static struct usb_string fsg_strings[] = { +#ifndef FSG_NO_DEVICE_STRINGS + {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, + {FSG_STRING_PRODUCT, fsg_string_product}, + {FSG_STRING_SERIAL, ""}, + {FSG_STRING_CONFIG, fsg_string_config}, +#endif + {FSG_STRING_INTERFACE, fsg_string_interface}, + {} +}; + +static struct usb_gadget_strings fsg_stringtab = { + .language = 0x0409, /* en-us */ + .strings = fsg_strings, +}; + + + /*-------------------------------------------------------------------------*/ + +/* + * If the next two routines are called while the gadget is registered, + * the caller must own fsg->filesem for writing. + */ + +static void fsg_lun_close(struct fsg_lun *curlun) +{ + if (curlun->filp) { + LDBG(curlun, "close backing file\n"); + fput(curlun->filp); + curlun->filp = NULL; + } +} + + +static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) +{ + int ro; + struct file *filp = NULL; + int rc = -EINVAL; + struct inode *inode = NULL; + loff_t size; + loff_t num_sectors; + loff_t min_sectors; + unsigned int blkbits; + unsigned int blksize; + + /* R/W if we can, R/O if we must */ + ro = curlun->initially_ro; + if (!ro) { + filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); + if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES) + ro = 1; + } + if (ro) + filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + LINFO(curlun, "unable to open backing file: %s\n", filename); + return PTR_ERR(filp); + } + + if (!(filp->f_mode & FMODE_WRITE)) + ro = 1; + + inode = filp->f_path.dentry->d_inode; + if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { + LINFO(curlun, "invalid file type: %s\n", filename); + goto out; + } + + /* + * If we can't read the file, it's no good. + * If we can't write the file, use it read-only. + */ + if (!(filp->f_op->read || filp->f_op->aio_read)) { + LINFO(curlun, "file not readable: %s\n", filename); + goto out; + } + if (!(filp->f_op->write || filp->f_op->aio_write)) + ro = 1; + + size = i_size_read(inode->i_mapping->host); + if (size < 0) { + LINFO(curlun, "unable to find file size: %s\n", filename); + rc = (int) size; + goto out; + } + + if (curlun->cdrom) { + blksize = 2048; + blkbits = 11; + } else if (inode->i_bdev) { + blksize = bdev_logical_block_size(inode->i_bdev); + blkbits = blksize_bits(blksize); + } else { + blksize = 512; + blkbits = 9; + } + + num_sectors = size >> blkbits; /* File size in logic-block-size blocks */ + min_sectors = 1; + if (curlun->cdrom) { + min_sectors = 300; /* Smallest track is 300 frames */ + if (num_sectors >= 256*60*75) { + num_sectors = 256*60*75 - 1; + LINFO(curlun, "file too big: %s\n", filename); + LINFO(curlun, "using only first %d blocks\n", + (int) num_sectors); + } + } + if (num_sectors < min_sectors) { + LINFO(curlun, "file too small: %s\n", filename); + rc = -ETOOSMALL; + goto out; + } + + if (fsg_lun_is_open(curlun)) + fsg_lun_close(curlun); + + curlun->blksize = blksize; + curlun->blkbits = blkbits; + curlun->ro = ro; + curlun->filp = filp; + curlun->file_length = size; + curlun->num_sectors = num_sectors; + LDBG(curlun, "open backing file: %s\n", filename); + return 0; + +out: + fput(filp); + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +/* + * Sync the file data, don't bother with the metadata. + * This code was copied from fs/buffer.c:sys_fdatasync(). + */ +static int fsg_lun_fsync_sub(struct fsg_lun *curlun) +{ + struct file *filp = curlun->filp; + + if (curlun->ro || !filp) + return 0; + return vfs_fsync(filp, 1); +} + +static void store_cdrom_address(u8 *dest, int msf, u32 addr) +{ + if (msf) { + /* Convert to Minutes-Seconds-Frames */ + addr >>= 2; /* Convert to 2048-byte frames */ + addr += 2*75; /* Lead-in occupies 2 seconds */ + dest[3] = addr % 75; /* Frames */ + addr /= 75; + dest[2] = addr % 60; /* Seconds */ + addr /= 60; + dest[1] = addr; /* Minutes */ + dest[0] = 0; /* Reserved */ + } else { + /* Absolute sector */ + put_unaligned_be32(addr, dest); + } +} + + +/*-------------------------------------------------------------------------*/ + + +static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) + ? curlun->ro + : curlun->initially_ro); +} + +static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%u\n", curlun->nofua); +} + +static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + char *p; + ssize_t rc; + + down_read(filesem); + if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + if (IS_ERR(p)) + rc = PTR_ERR(p); + else { + rc = strlen(p); + memmove(buf, p, rc); + buf[rc] = '\n'; /* Add a newline */ + buf[++rc] = 0; + } + } else { /* No file, return 0 bytes */ + *buf = 0; + rc = 0; + } + up_read(filesem); + return rc; +} + + +static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t rc; + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + unsigned ro; + + rc = kstrtouint(buf, 2, &ro); + if (rc) + return rc; + + /* + * Allow the write-enable status to change only while the + * backing file is closed. + */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { + curlun->ro = ro; + curlun->initially_ro = ro; + LDBG(curlun, "read-only status set to %d\n", curlun->ro); + rc = count; + } + up_read(filesem); + return rc; +} + +static ssize_t fsg_store_nofua(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + unsigned nofua; + int ret; + + ret = kstrtouint(buf, 2, &nofua); + if (ret) + return ret; + + /* Sync data when switching from async mode to sync */ + if (!nofua && curlun->nofua) + fsg_lun_fsync_sub(curlun); + + curlun->nofua = nofua; + + return count; +} + +static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + int rc = 0; + + if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; /* "Door is locked" */ + } + + /* Remove a trailing newline */ + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; /* Ugh! */ + + /* Load new medium */ + down_write(filesem); + if (count > 0 && buf[0]) { + /* fsg_lun_open() will close existing file if any. */ + rc = fsg_lun_open(curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; + } else if (fsg_lun_is_open(curlun)) { + fsg_lun_close(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + up_write(filesem); + return (rc < 0 ? rc : count); +} diff --git a/drivers/staging/ccg/u_ether.c b/drivers/staging/ccg/u_ether.c new file mode 100644 index 0000000..1154a99 --- /dev/null +++ b/drivers/staging/ccg/u_ether.c @@ -0,0 +1,986 @@ +/* + * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack + * + * Copyright (C) 2003-2005,2008 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* #define VERBOSE_DEBUG */ + +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/device.h> +#include <linux/ctype.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> + +#include "u_ether.h" + + +/* + * This component encapsulates the Ethernet link glue needed to provide + * one (!) network link through the USB gadget stack, normally "usb0". + * + * The control and data models are handled by the function driver which + * connects to this code; such as CDC Ethernet (ECM or EEM), + * "CDC Subset", or RNDIS. That includes all descriptor and endpoint + * management. + * + * Link level addressing is handled by this component using module + * parameters; if no such parameters are provided, random link level + * addresses are used. Each end of the link uses one address. The + * host end address is exported in various ways, and is often recorded + * in configuration databases. + * + * The driver which assembles each configuration using such a link is + * responsible for ensuring that each configuration includes at most one + * instance of is network link. (The network layer provides ways for + * this single "physical" link to be used by multiple virtual links.) + */ + +#define UETH__VERSION "29-May-2008" + +struct eth_dev { + /* lock is held while accessing port_usb + * or updating its backlink port_usb->ioport + */ + spinlock_t lock; + struct gether *port_usb; + + struct net_device *net; + struct usb_gadget *gadget; + + spinlock_t req_lock; /* guard {rx,tx}_reqs */ + struct list_head tx_reqs, rx_reqs; + atomic_t tx_qlen; + + struct sk_buff_head rx_frames; + + unsigned header_len; + struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb); + int (*unwrap)(struct gether *, + struct sk_buff *skb, + struct sk_buff_head *list); + + struct work_struct work; + + unsigned long todo; +#define WORK_RX_MEMORY 0 + + bool zlp; + u8 host_mac[ETH_ALEN]; +}; + +/*-------------------------------------------------------------------------*/ + +#define RX_EXTRA 20 /* bytes guarding against rx overflows */ + +#define DEFAULT_QLEN 2 /* double buffering by default */ + +static unsigned qmult = 5; +module_param(qmult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed"); + +/* for dual-speed hardware, use deeper queues at high/super speed */ +static inline int qlen(struct usb_gadget *gadget) +{ + if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH || + gadget->speed == USB_SPEED_SUPER)) + return qmult * DEFAULT_QLEN; + else + return DEFAULT_QLEN; +} + +/*-------------------------------------------------------------------------*/ + +/* REVISIT there must be a better way than having two sets + * of debug calls ... + */ + +#undef DBG +#undef VDBG +#undef ERROR +#undef INFO + +#define xprintk(d, level, fmt, args...) \ + printk(level "%s: " fmt , (d)->net->name , ## args) + +#ifdef DEBUG +#undef DEBUG +#define DBG(dev, fmt, args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DBG(dev, fmt, args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VDBG DBG +#else +#define VDBG(dev, fmt, args...) \ + do { } while (0) +#endif /* DEBUG */ + +#define ERROR(dev, fmt, args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define INFO(dev, fmt, args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +/* NETWORK DRIVER HOOKUP (to the layer above this driver) */ + +static int ueth_change_mtu(struct net_device *net, int new_mtu) +{ + struct eth_dev *dev = netdev_priv(net); + unsigned long flags; + int status = 0; + + /* don't change MTU on "live" link (peer won't know) */ + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) + status = -EBUSY; + else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN) + status = -ERANGE; + else + net->mtu = new_mtu; + spin_unlock_irqrestore(&dev->lock, flags); + + return status; +} + +static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) +{ + struct eth_dev *dev = netdev_priv(net); + + strlcpy(p->driver, "g_ether", sizeof p->driver); + strlcpy(p->version, UETH__VERSION, sizeof p->version); + strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version); + strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info); +} + +/* REVISIT can also support: + * - WOL (by tracking suspends and issuing remote wakeup) + * - msglevel (implies updated messaging) + * - ... probably more ethtool ops + */ + +static const struct ethtool_ops ops = { + .get_drvinfo = eth_get_drvinfo, + .get_link = ethtool_op_get_link, +}; + +static void defer_kevent(struct eth_dev *dev, int flag) +{ + if (test_and_set_bit(flag, &dev->todo)) + return; + if (!schedule_work(&dev->work)) + ERROR(dev, "kevent %d may have been dropped\n", flag); + else + DBG(dev, "kevent %d scheduled\n", flag); +} + +static void rx_complete(struct usb_ep *ep, struct usb_request *req); + +static int +rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) +{ + struct sk_buff *skb; + int retval = -ENOMEM; + size_t size = 0; + struct usb_ep *out; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) + out = dev->port_usb->out_ep; + else + out = NULL; + spin_unlock_irqrestore(&dev->lock, flags); + + if (!out) + return -ENOTCONN; + + + /* Padding up to RX_EXTRA handles minor disagreements with host. + * Normally we use the USB "terminate on short read" convention; + * so allow up to (N*maxpacket), since that memory is normally + * already allocated. Some hardware doesn't deal well with short + * reads (e.g. DMA must be N*maxpacket), so for now don't trim a + * byte off the end (to force hardware errors on overflow). + * + * RNDIS uses internal framing, and explicitly allows senders to + * pad to end-of-packet. That's potentially nice for speed, but + * means receivers can't recover lost synch on their own (because + * new packets don't only start after a short RX). + */ + size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA; + size += dev->port_usb->header_len; + size += out->maxpacket - 1; + size -= size % out->maxpacket; + + if (dev->port_usb->is_fixed) + size = max_t(size_t, size, dev->port_usb->fixed_out_len); + + skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); + if (skb == NULL) { + DBG(dev, "no rx skb\n"); + goto enomem; + } + + /* Some platforms perform better when IP packets are aligned, + * but on at least one, checksumming fails otherwise. Note: + * RNDIS headers involve variable numbers of LE32 values. + */ + skb_reserve(skb, NET_IP_ALIGN); + + req->buf = skb->data; + req->length = size; + req->complete = rx_complete; + req->context = skb; + + retval = usb_ep_queue(out, req, gfp_flags); + if (retval == -ENOMEM) +enomem: + defer_kevent(dev, WORK_RX_MEMORY); + if (retval) { + DBG(dev, "rx submit --> %d\n", retval); + if (skb) + dev_kfree_skb_any(skb); + spin_lock_irqsave(&dev->req_lock, flags); + list_add(&req->list, &dev->rx_reqs); + spin_unlock_irqrestore(&dev->req_lock, flags); + } + return retval; +} + +static void rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct sk_buff *skb = req->context, *skb2; + struct eth_dev *dev = ep->driver_data; + int status = req->status; + + switch (status) { + + /* normal completion */ + case 0: + skb_put(skb, req->actual); + + if (dev->unwrap) { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) { + status = dev->unwrap(dev->port_usb, + skb, + &dev->rx_frames); + } else { + dev_kfree_skb_any(skb); + status = -ENOTCONN; + } + spin_unlock_irqrestore(&dev->lock, flags); + } else { + skb_queue_tail(&dev->rx_frames, skb); + } + skb = NULL; + + skb2 = skb_dequeue(&dev->rx_frames); + while (skb2) { + if (status < 0 + || ETH_HLEN > skb2->len + || skb2->len > ETH_FRAME_LEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + DBG(dev, "rx length %d\n", skb2->len); + dev_kfree_skb_any(skb2); + goto next_frame; + } + skb2->protocol = eth_type_trans(skb2, dev->net); + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += skb2->len; + + /* no buffer copies needed, unless hardware can't + * use skb buffers. + */ + status = netif_rx(skb2); +next_frame: + skb2 = skb_dequeue(&dev->rx_frames); + } + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + VDBG(dev, "rx shutdown, code %d\n", status); + goto quiesce; + + /* for hardware automagic (such as pxa) */ + case -ECONNABORTED: /* endpoint reset */ + DBG(dev, "rx %s reset\n", ep->name); + defer_kevent(dev, WORK_RX_MEMORY); +quiesce: + dev_kfree_skb_any(skb); + goto clean; + + /* data overrun */ + case -EOVERFLOW: + dev->net->stats.rx_over_errors++; + /* FALLTHROUGH */ + + default: + dev->net->stats.rx_errors++; + DBG(dev, "rx status %d\n", status); + break; + } + + if (skb) + dev_kfree_skb_any(skb); + if (!netif_running(dev->net)) { +clean: + spin_lock(&dev->req_lock); + list_add(&req->list, &dev->rx_reqs); + spin_unlock(&dev->req_lock); + req = NULL; + } + if (req) + rx_submit(dev, req, GFP_ATOMIC); +} + +static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) +{ + unsigned i; + struct usb_request *req; + + if (!n) + return -ENOMEM; + + /* queue/recycle up to N requests */ + i = n; + list_for_each_entry(req, list, list) { + if (i-- == 0) + goto extra; + } + while (i--) { + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (!req) + return list_empty(list) ? -ENOMEM : 0; + list_add(&req->list, list); + } + return 0; + +extra: + /* free extras */ + for (;;) { + struct list_head *next; + + next = req->list.next; + list_del(&req->list); + usb_ep_free_request(ep, req); + + if (next == list) + break; + + req = container_of(next, struct usb_request, list); + } + return 0; +} + +static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n) +{ + int status; + + spin_lock(&dev->req_lock); + status = prealloc(&dev->tx_reqs, link->in_ep, n); + if (status < 0) + goto fail; + status = prealloc(&dev->rx_reqs, link->out_ep, n); + if (status < 0) + goto fail; + goto done; +fail: + DBG(dev, "can't alloc requests\n"); +done: + spin_unlock(&dev->req_lock); + return status; +} + +static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) +{ + struct usb_request *req; + unsigned long flags; + + /* fill unused rxq slots with some skb */ + spin_lock_irqsave(&dev->req_lock, flags); + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del_init(&req->list); + spin_unlock_irqrestore(&dev->req_lock, flags); + + if (rx_submit(dev, req, gfp_flags) < 0) { + defer_kevent(dev, WORK_RX_MEMORY); + return; + } + + spin_lock_irqsave(&dev->req_lock, flags); + } + spin_unlock_irqrestore(&dev->req_lock, flags); +} + +static void eth_work(struct work_struct *work) +{ + struct eth_dev *dev = container_of(work, struct eth_dev, work); + + if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) { + if (netif_running(dev->net)) + rx_fill(dev, GFP_KERNEL); + } + + if (dev->todo) + DBG(dev, "work done, flags = 0x%lx\n", dev->todo); +} + +static void tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct sk_buff *skb = req->context; + struct eth_dev *dev = ep->driver_data; + + switch (req->status) { + default: + dev->net->stats.tx_errors++; + VDBG(dev, "tx err %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNRESET: /* unlink */ + case -ESHUTDOWN: /* disconnect etc */ + break; + case 0: + dev->net->stats.tx_bytes += skb->len; + } + dev->net->stats.tx_packets++; + + spin_lock(&dev->req_lock); + list_add(&req->list, &dev->tx_reqs); + spin_unlock(&dev->req_lock); + dev_kfree_skb_any(skb); + + atomic_dec(&dev->tx_qlen); + if (netif_carrier_ok(dev->net)) + netif_wake_queue(dev->net); +} + +static inline int is_promisc(u16 cdc_filter) +{ + return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; +} + +static netdev_tx_t eth_start_xmit(struct sk_buff *skb, + struct net_device *net) +{ + struct eth_dev *dev = netdev_priv(net); + int length = skb->len; + int retval; + struct usb_request *req = NULL; + unsigned long flags; + struct usb_ep *in; + u16 cdc_filter; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) { + in = dev->port_usb->in_ep; + cdc_filter = dev->port_usb->cdc_filter; + } else { + in = NULL; + cdc_filter = 0; + } + spin_unlock_irqrestore(&dev->lock, flags); + + if (!in) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* apply outgoing CDC or RNDIS filters */ + if (!is_promisc(cdc_filter)) { + u8 *dest = skb->data; + + if (is_multicast_ether_addr(dest)) { + u16 type; + + /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host + * SET_ETHERNET_MULTICAST_FILTERS requests + */ + if (is_broadcast_ether_addr(dest)) + type = USB_CDC_PACKET_TYPE_BROADCAST; + else + type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; + if (!(cdc_filter & type)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ + } + + spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return NETDEV_TX_BUSY; + } + + req = container_of(dev->tx_reqs.next, struct usb_request, list); + list_del(&req->list); + + /* temporarily stop TX queue when the freelist empties */ + if (list_empty(&dev->tx_reqs)) + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->req_lock, flags); + + /* no buffer copies needed, unless the network stack did it + * or the hardware can't use skb buffers. + * or there's not enough space for extra headers we need + */ + if (dev->wrap) { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) + skb = dev->wrap(dev->port_usb, skb); + spin_unlock_irqrestore(&dev->lock, flags); + if (!skb) + goto drop; + + length = skb->len; + } + req->buf = skb->data; + req->context = skb; + req->complete = tx_complete; + + /* NCM requires no zlp if transfer is dwNtbInMaxSize */ + if (dev->port_usb->is_fixed && + length == dev->port_usb->fixed_in_len && + (length % in->maxpacket) == 0) + req->zero = 0; + else + req->zero = 1; + + /* use zlp framing on tx for strict CDC-Ether conformance, + * though any robust network rx path ignores extra padding. + * and some hardware doesn't like to write zlps. + */ + if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) + length++; + + req->length = length; + + /* throttle high/super speed IRQ rate back slightly */ + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || + dev->gadget->speed == USB_SPEED_SUPER) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; + + retval = usb_ep_queue(in, req, GFP_ATOMIC); + switch (retval) { + default: + DBG(dev, "tx queue err %d\n", retval); + break; + case 0: + net->trans_start = jiffies; + atomic_inc(&dev->tx_qlen); + } + + if (retval) { + dev_kfree_skb_any(skb); +drop: + dev->net->stats.tx_dropped++; + spin_lock_irqsave(&dev->req_lock, flags); + if (list_empty(&dev->tx_reqs)) + netif_start_queue(net); + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->req_lock, flags); + } + return NETDEV_TX_OK; +} + +/*-------------------------------------------------------------------------*/ + +static void eth_start(struct eth_dev *dev, gfp_t gfp_flags) +{ + DBG(dev, "%s\n", __func__); + + /* fill the rx queue */ + rx_fill(dev, gfp_flags); + + /* and open the tx floodgates */ + atomic_set(&dev->tx_qlen, 0); + netif_wake_queue(dev->net); +} + +static int eth_open(struct net_device *net) +{ + struct eth_dev *dev = netdev_priv(net); + struct gether *link; + + DBG(dev, "%s\n", __func__); + if (netif_carrier_ok(dev->net)) + eth_start(dev, GFP_KERNEL); + + spin_lock_irq(&dev->lock); + link = dev->port_usb; + if (link && link->open) + link->open(link); + spin_unlock_irq(&dev->lock); + + return 0; +} + +static int eth_stop(struct net_device *net) +{ + struct eth_dev *dev = netdev_priv(net); + unsigned long flags; + + VDBG(dev, "%s\n", __func__); + netif_stop_queue(net); + + DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", + dev->net->stats.rx_packets, dev->net->stats.tx_packets, + dev->net->stats.rx_errors, dev->net->stats.tx_errors + ); + + /* ensure there are no more active requests */ + spin_lock_irqsave(&dev->lock, flags); + if (dev->port_usb) { + struct gether *link = dev->port_usb; + + if (link->close) + link->close(link); + + /* NOTE: we have no abort-queue primitive we could use + * to cancel all pending I/O. Instead, we disable then + * reenable the endpoints ... this idiom may leave toggle + * wrong, but that's a self-correcting error. + * + * REVISIT: we *COULD* just let the transfers complete at + * their own pace; the network stack can handle old packets. + * For the moment we leave this here, since it works. + */ + usb_ep_disable(link->in_ep); + usb_ep_disable(link->out_ep); + if (netif_carrier_ok(net)) { + DBG(dev, "host still using in/out endpoints\n"); + usb_ep_enable(link->in_ep); + usb_ep_enable(link->out_ep); + } + } + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */ +static char *dev_addr; +module_param(dev_addr, charp, S_IRUGO); +MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); + +/* this address is invisible to ifconfig */ +static char *host_addr; +module_param(host_addr, charp, S_IRUGO); +MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); + +static int get_ether_addr(const char *str, u8 *dev_addr) +{ + if (str) { + unsigned i; + + for (i = 0; i < 6; i++) { + unsigned char num; + + if ((*str == '.') || (*str == ':')) + str++; + num = hex_to_bin(*str++) << 4; + num |= hex_to_bin(*str++); + dev_addr [i] = num; + } + if (is_valid_ether_addr(dev_addr)) + return 0; + } + eth_random_addr(dev_addr); + return 1; +} + +static struct eth_dev *the_dev; + +static const struct net_device_ops eth_netdev_ops = { + .ndo_open = eth_open, + .ndo_stop = eth_stop, + .ndo_start_xmit = eth_start_xmit, + .ndo_change_mtu = ueth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +static struct device_type gadget_type = { + .name = "gadget", +}; + +/** + * gether_setup_name - initialize one ethernet-over-usb link + * @g: gadget to associated with these links + * @ethaddr: NULL, or a buffer in which the ethernet address of the + * host side of the link is recorded + * @netname: name for network device (for example, "usb") + * Context: may sleep + * + * This sets up the single network link that may be exported by a + * gadget driver using this framework. The link layer addresses are + * set up using module parameters. + * + * Returns negative errno, or zero on success + */ +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname) +{ + struct eth_dev *dev; + struct net_device *net; + int status; + + if (the_dev) + return -EBUSY; + + net = alloc_etherdev(sizeof *dev); + if (!net) + return -ENOMEM; + + dev = netdev_priv(net); + spin_lock_init(&dev->lock); + spin_lock_init(&dev->req_lock); + INIT_WORK(&dev->work, eth_work); + INIT_LIST_HEAD(&dev->tx_reqs); + INIT_LIST_HEAD(&dev->rx_reqs); + + skb_queue_head_init(&dev->rx_frames); + + /* network device setup */ + dev->net = net; + snprintf(net->name, sizeof(net->name), "%s%%d", netname); + + if (get_ether_addr(dev_addr, net->dev_addr)) + dev_warn(&g->dev, + "using random %s ethernet address\n", "self"); + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&g->dev, + "using random %s ethernet address\n", "host"); + + if (ethaddr) + memcpy(ethaddr, dev->host_mac, ETH_ALEN); + + net->netdev_ops = ð_netdev_ops; + + SET_ETHTOOL_OPS(net, &ops); + + dev->gadget = g; + SET_NETDEV_DEV(net, &g->dev); + SET_NETDEV_DEVTYPE(net, &gadget_type); + + status = register_netdev(net); + if (status < 0) { + dev_dbg(&g->dev, "register_netdev failed, %d\n", status); + free_netdev(net); + } else { + INFO(dev, "MAC %pM\n", net->dev_addr); + INFO(dev, "HOST MAC %pM\n", dev->host_mac); + + the_dev = dev; + + /* two kinds of host-initiated state changes: + * - iff DATA transfer is active, carrier is "on" + * - tx queueing enabled if open *and* carrier is "on" + */ + netif_carrier_off(net); + } + + return status; +} + +/** + * gether_cleanup - remove Ethernet-over-USB device + * Context: may sleep + * + * This is called to free all resources allocated by @gether_setup(). + */ +void gether_cleanup(void) +{ + if (!the_dev) + return; + + unregister_netdev(the_dev->net); + flush_work_sync(&the_dev->work); + free_netdev(the_dev->net); + + the_dev = NULL; +} + + +/** + * gether_connect - notify network layer that USB link is active + * @link: the USB link, set up with endpoints, descriptors matching + * current device speed, and any framing wrapper(s) set up. + * Context: irqs blocked + * + * This is called to activate endpoints and let the network layer know + * the connection is active ("carrier detect"). It may cause the I/O + * queues to open and start letting network packets flow, but will in + * any case activate the endpoints so that they respond properly to the + * USB host. + * + * Verify net_device pointer returned using IS_ERR(). If it doesn't + * indicate some error code (negative errno), ep->driver_data values + * have been overwritten. + */ +struct net_device *gether_connect(struct gether *link) +{ + struct eth_dev *dev = the_dev; + int result = 0; + + if (!dev) + return ERR_PTR(-EINVAL); + + link->in_ep->driver_data = dev; + result = usb_ep_enable(link->in_ep); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", + link->in_ep->name, result); + goto fail0; + } + + link->out_ep->driver_data = dev; + result = usb_ep_enable(link->out_ep); + if (result != 0) { + DBG(dev, "enable %s --> %d\n", + link->out_ep->name, result); + goto fail1; + } + + if (result == 0) + result = alloc_requests(dev, link, qlen(dev->gadget)); + + if (result == 0) { + dev->zlp = link->is_zlp_ok; + DBG(dev, "qlen %d\n", qlen(dev->gadget)); + + dev->header_len = link->header_len; + dev->unwrap = link->unwrap; + dev->wrap = link->wrap; + + spin_lock(&dev->lock); + dev->port_usb = link; + link->ioport = dev; + if (netif_running(dev->net)) { + if (link->open) + link->open(link); + } else { + if (link->close) + link->close(link); + } + spin_unlock(&dev->lock); + + netif_carrier_on(dev->net); + if (netif_running(dev->net)) + eth_start(dev, GFP_ATOMIC); + + /* on error, disable any endpoints */ + } else { + (void) usb_ep_disable(link->out_ep); +fail1: + (void) usb_ep_disable(link->in_ep); + } +fail0: + /* caller is responsible for cleanup on error */ + if (result < 0) + return ERR_PTR(result); + return dev->net; +} + +/** + * gether_disconnect - notify network layer that USB link is inactive + * @link: the USB link, on which gether_connect() was called + * Context: irqs blocked + * + * This is called to deactivate endpoints and let the network layer know + * the connection went inactive ("no carrier"). + * + * On return, the state is as if gether_connect() had never been called. + * The endpoints are inactive, and accordingly without active USB I/O. + * Pointers to endpoint descriptors and endpoint private data are nulled. + */ +void gether_disconnect(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + struct usb_request *req; + + WARN_ON(!dev); + if (!dev) + return; + + DBG(dev, "%s\n", __func__); + + netif_stop_queue(dev->net); + netif_carrier_off(dev->net); + + /* disable endpoints, forcing (synchronous) completion + * of all pending i/o. then free the request objects + * and forget about the endpoints. + */ + usb_ep_disable(link->in_ep); + spin_lock(&dev->req_lock); + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, + struct usb_request, list); + list_del(&req->list); + + spin_unlock(&dev->req_lock); + usb_ep_free_request(link->in_ep, req); + spin_lock(&dev->req_lock); + } + spin_unlock(&dev->req_lock); + link->in_ep->driver_data = NULL; + link->in_ep->desc = NULL; + + usb_ep_disable(link->out_ep); + spin_lock(&dev->req_lock); + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + + spin_unlock(&dev->req_lock); + usb_ep_free_request(link->out_ep, req); + spin_lock(&dev->req_lock); + } + spin_unlock(&dev->req_lock); + link->out_ep->driver_data = NULL; + link->out_ep->desc = NULL; + + /* finish forgetting about this USB link episode */ + dev->header_len = 0; + dev->unwrap = NULL; + dev->wrap = NULL; + + spin_lock(&dev->lock); + dev->port_usb = NULL; + link->ioport = NULL; + spin_unlock(&dev->lock); +} diff --git a/drivers/staging/ccg/u_ether.h b/drivers/staging/ccg/u_ether.h new file mode 100644 index 0000000..6f4a1623 --- /dev/null +++ b/drivers/staging/ccg/u_ether.h @@ -0,0 +1,154 @@ +/* + * u_ether.h -- interface to USB gadget "ethernet link" utilities + * + * Copyright (C) 2003-2005,2008 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __U_ETHER_H +#define __U_ETHER_H + +#include <linux/err.h> +#include <linux/if_ether.h> +#include <linux/usb/composite.h> +#include <linux/usb/cdc.h> + +#include "gadget_chips.h" + + +/* + * This represents the USB side of an "ethernet" link, managed by a USB + * function which provides control and (maybe) framing. Two functions + * in different configurations could share the same ethernet link/netdev, + * using different host interaction models. + * + * There is a current limitation that only one instance of this link may + * be present in any given configuration. When that's a problem, network + * layer facilities can be used to package multiple logical links on this + * single "physical" one. + */ +struct gether { + struct usb_function func; + + /* updated by gether_{connect,disconnect} */ + struct eth_dev *ioport; + + /* endpoints handle full and/or high speeds */ + struct usb_ep *in_ep; + struct usb_ep *out_ep; + + bool is_zlp_ok; + + u16 cdc_filter; + + /* hooks for added framing, as needed for RNDIS and EEM. */ + u32 header_len; + /* NCM requires fixed size bundles */ + bool is_fixed; + u32 fixed_out_len; + u32 fixed_in_len; + struct sk_buff *(*wrap)(struct gether *port, + struct sk_buff *skb); + int (*unwrap)(struct gether *port, + struct sk_buff *skb, + struct sk_buff_head *list); + + /* called on network open/close */ + void (*open)(struct gether *); + void (*close)(struct gether *); +}; + +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ + |USB_CDC_PACKET_TYPE_DIRECTED) + +/* variant of gether_setup that allows customizing network device name */ +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname); + +/* netdev setup/teardown as directed by the gadget driver */ +/* gether_setup - initialize one ethernet-over-usb link + * @g: gadget to associated with these links + * @ethaddr: NULL, or a buffer in which the ethernet address of the + * host side of the link is recorded + * Context: may sleep + * + * This sets up the single network link that may be exported by a + * gadget driver using this framework. The link layer addresses are + * set up using module parameters. + * + * Returns negative errno, or zero on success + */ +static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +{ + return gether_setup_name(g, ethaddr, "usb"); +} + +void gether_cleanup(void); + +/* connect/disconnect is handled by individual functions */ +struct net_device *gether_connect(struct gether *); +void gether_disconnect(struct gether *); + +/* Some controllers can't support CDC Ethernet (ECM) ... */ +static inline bool can_support_ecm(struct usb_gadget *gadget) +{ + if (!gadget_supports_altsettings(gadget)) + return false; + + /* Everything else is *presumably* fine ... but this is a bit + * chancy, so be **CERTAIN** there are no hardware issues with + * your controller. Add it above if it can't handle CDC. + */ + return true; +} + +/* each configuration may bind one instance of an ethernet link */ +int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int eem_bind_config(struct usb_configuration *c); + +#ifdef USB_ETH_RNDIS + +int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer); + +#else + +static inline int +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) +{ + return 0; +} + +#endif + +/** + * rndis_bind_config - add RNDIS network link to a configuration + * @c: the configuration to support the network link + * @ethaddr: a buffer in which the ethernet address of the host side + * side of the link was recorded + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + * + * Caller must have called @gether_setup(). Caller is also responsible + * for calling @gether_cleanup() before module unload. + */ +static inline int rndis_bind_config(struct usb_configuration *c, + u8 ethaddr[ETH_ALEN]) +{ + return rndis_bind_config_vendor(c, ethaddr, 0, NULL); +} + + +#endif /* __U_ETHER_H */ diff --git a/drivers/staging/ccg/u_serial.c b/drivers/staging/ccg/u_serial.c new file mode 100644 index 0000000..5b3f5ff --- /dev/null +++ b/drivers/staging/ccg/u_serial.c @@ -0,0 +1,1341 @@ +/* + * u_serial.c - utilities for USB gadget "serial port"/TTY support + * + * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) + * Copyright (C) 2008 David Brownell + * Copyright (C) 2008 by Nokia Corporation + * + * This code also borrows from usbserial.c, which is + * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2000 Peter Berger (pberger@brimson.com) + * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com) + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of that License or (at your option) any later version. + */ + +/* #define VERBOSE_DEBUG */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/slab.h> +#include <linux/export.h> + +#include "u_serial.h" + + +/* + * This component encapsulates the TTY layer glue needed to provide basic + * "serial port" functionality through the USB gadget stack. Each such + * port is exposed through a /dev/ttyGS* node. + * + * After initialization (gserial_setup), these TTY port devices stay + * available until they are removed (gserial_cleanup). Each one may be + * connected to a USB function (gserial_connect), or disconnected (with + * gserial_disconnect) when the USB host issues a config change event. + * Data can only flow when the port is connected to the host. + * + * A given TTY port can be made available in multiple configurations. + * For example, each one might expose a ttyGS0 node which provides a + * login application. In one case that might use CDC ACM interface 0, + * while another configuration might use interface 3 for that. The + * work to handle that (including descriptor management) is not part + * of this component. + * + * Configurations may expose more than one TTY port. For example, if + * ttyGS0 provides login service, then ttyGS1 might provide dialer access + * for a telephone or fax link. And ttyGS2 might be something that just + * needs a simple byte stream interface for some messaging protocol that + * is managed in userspace ... OBEX, PTP, and MTP have been mentioned. + */ + +#define PREFIX "ttyGS" + +/* + * gserial is the lifecycle interface, used by USB functions + * gs_port is the I/O nexus, used by the tty driver + * tty_struct links to the tty/filesystem framework + * + * gserial <---> gs_port ... links will be null when the USB link is + * inactive; managed by gserial_{connect,disconnect}(). each gserial + * instance can wrap its own USB control protocol. + * gserial->ioport == usb_ep->driver_data ... gs_port + * gs_port->port_usb ... gserial + * + * gs_port <---> tty_struct ... links will be null when the TTY file + * isn't opened; managed by gs_open()/gs_close() + * gserial->port_tty ... tty_struct + * tty_struct->driver_data ... gserial + */ + +/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the + * next layer of buffering. For TX that's a circular buffer; for RX + * consider it a NOP. A third layer is provided by the TTY code. + */ +#define QUEUE_SIZE 16 +#define WRITE_BUF_SIZE 8192 /* TX only */ + +/* circular buffer */ +struct gs_buf { + unsigned buf_size; + char *buf_buf; + char *buf_get; + char *buf_put; +}; + +/* + * The port structure holds info for each port, one for each minor number + * (and thus for each /dev/ node). + */ +struct gs_port { + struct tty_port port; + spinlock_t port_lock; /* guard port_* access */ + + struct gserial *port_usb; + + bool openclose; /* open/close in progress */ + u8 port_num; + + struct list_head read_pool; + int read_started; + int read_allocated; + struct list_head read_queue; + unsigned n_read; + struct tasklet_struct push; + + struct list_head write_pool; + int write_started; + int write_allocated; + struct gs_buf port_write_buf; + wait_queue_head_t drain_wait; /* wait while writes drain */ + + /* REVISIT this state ... */ + struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ +}; + +/* increase N_PORTS if you need more */ +#define N_PORTS 4 +static struct portmaster { + struct mutex lock; /* protect open/close */ + struct gs_port *port; +} ports[N_PORTS]; +static unsigned n_ports; + +#define GS_CLOSE_TIMEOUT 15 /* seconds */ + + + +#ifdef VERBOSE_DEBUG +#define pr_vdebug(fmt, arg...) \ + pr_debug(fmt, ##arg) +#else +#define pr_vdebug(fmt, arg...) \ + ({ if (0) pr_debug(fmt, ##arg); }) +#endif + +/*-------------------------------------------------------------------------*/ + +/* Circular Buffer */ + +/* + * gs_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ +static int gs_buf_alloc(struct gs_buf *gb, unsigned size) +{ + gb->buf_buf = kmalloc(size, GFP_KERNEL); + if (gb->buf_buf == NULL) + return -ENOMEM; + + gb->buf_size = size; + gb->buf_put = gb->buf_buf; + gb->buf_get = gb->buf_buf; + + return 0; +} + +/* + * gs_buf_free + * + * Free the buffer and all associated memory. + */ +static void gs_buf_free(struct gs_buf *gb) +{ + kfree(gb->buf_buf); + gb->buf_buf = NULL; +} + +/* + * gs_buf_clear + * + * Clear out all data in the circular buffer. + */ +static void gs_buf_clear(struct gs_buf *gb) +{ + gb->buf_get = gb->buf_put; + /* equivalent to a get of all data available */ +} + +/* + * gs_buf_data_avail + * + * Return the number of bytes of data written into the circular + * buffer. + */ +static unsigned gs_buf_data_avail(struct gs_buf *gb) +{ + return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size; +} + +/* + * gs_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ +static unsigned gs_buf_space_avail(struct gs_buf *gb) +{ + return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size; +} + +/* + * gs_buf_put + * + * Copy data data from a user buffer and put it into the circular buffer. + * Restrict to the amount of space available. + * + * Return the number of bytes copied. + */ +static unsigned +gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count) +{ + unsigned len; + + len = gs_buf_space_avail(gb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = gb->buf_buf + gb->buf_size - gb->buf_put; + if (count > len) { + memcpy(gb->buf_put, buf, len); + memcpy(gb->buf_buf, buf+len, count - len); + gb->buf_put = gb->buf_buf + count - len; + } else { + memcpy(gb->buf_put, buf, count); + if (count < len) + gb->buf_put += count; + else /* count == len */ + gb->buf_put = gb->buf_buf; + } + + return count; +} + +/* + * gs_buf_get + * + * Get data from the circular buffer and copy to the given buffer. + * Restrict to the amount of data available. + * + * Return the number of bytes copied. + */ +static unsigned +gs_buf_get(struct gs_buf *gb, char *buf, unsigned count) +{ + unsigned len; + + len = gs_buf_data_avail(gb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = gb->buf_buf + gb->buf_size - gb->buf_get; + if (count > len) { + memcpy(buf, gb->buf_get, len); + memcpy(buf+len, gb->buf_buf, count - len); + gb->buf_get = gb->buf_buf + count - len; + } else { + memcpy(buf, gb->buf_get, count); + if (count < len) + gb->buf_get += count; + else /* count == len */ + gb->buf_get = gb->buf_buf; + } + + return count; +} + +/*-------------------------------------------------------------------------*/ + +/* I/O glue between TTY (upper) and USB function (lower) driver layers */ + +/* + * gs_alloc_req + * + * Allocate a usb_request and its buffer. Returns a pointer to the + * usb_request or NULL if there is an error. + */ +struct usb_request * +gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, kmalloc_flags); + + if (req != NULL) { + req->length = len; + req->buf = kmalloc(len, kmalloc_flags); + if (req->buf == NULL) { + usb_ep_free_request(ep, req); + return NULL; + } + } + + return req; +} + +/* + * gs_free_req + * + * Free a usb_request and its buffer. + */ +void gs_free_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +/* + * gs_send_packet + * + * If there is data to send, a packet is built in the given + * buffer and the size is returned. If there is no data to + * send, 0 is returned. + * + * Called with port_lock held. + */ +static unsigned +gs_send_packet(struct gs_port *port, char *packet, unsigned size) +{ + unsigned len; + + len = gs_buf_data_avail(&port->port_write_buf); + if (len < size) + size = len; + if (size != 0) + size = gs_buf_get(&port->port_write_buf, packet, size); + return size; +} + +/* + * gs_start_tx + * + * This function finds available write requests, calls + * gs_send_packet to fill these packets with data, and + * continues until either there are no more write requests + * available or no more data to send. This function is + * run whenever data arrives or write requests are available. + * + * Context: caller owns port_lock; port_usb is non-null. + */ +static int gs_start_tx(struct gs_port *port) +/* +__releases(&port->port_lock) +__acquires(&port->port_lock) +*/ +{ + struct list_head *pool = &port->write_pool; + struct usb_ep *in = port->port_usb->in; + int status = 0; + bool do_tty_wake = false; + + while (!list_empty(pool)) { + struct usb_request *req; + int len; + + if (port->write_started >= QUEUE_SIZE) + break; + + req = list_entry(pool->next, struct usb_request, list); + len = gs_send_packet(port, req->buf, in->maxpacket); + if (len == 0) { + wake_up_interruptible(&port->drain_wait); + break; + } + do_tty_wake = true; + + req->length = len; + list_del(&req->list); + req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); + + pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", + port->port_num, len, *((u8 *)req->buf), + *((u8 *)req->buf+1), *((u8 *)req->buf+2)); + + /* Drop lock while we call out of driver; completions + * could be issued while we do so. Disconnection may + * happen too; maybe immediately before we queue this! + * + * NOTE that we may keep sending data for a while after + * the TTY closed (dev->ioport->port_tty is NULL). + */ + spin_unlock(&port->port_lock); + status = usb_ep_queue(in, req, GFP_ATOMIC); + spin_lock(&port->port_lock); + + if (status) { + pr_debug("%s: %s %s err %d\n", + __func__, "queue", in->name, status); + list_add(&req->list, pool); + break; + } + + port->write_started++; + + /* abort immediately after disconnect */ + if (!port->port_usb) + break; + } + + if (do_tty_wake && port->port.tty) + tty_wakeup(port->port.tty); + return status; +} + +/* + * Context: caller owns port_lock, and port_usb is set + */ +static unsigned gs_start_rx(struct gs_port *port) +/* +__releases(&port->port_lock) +__acquires(&port->port_lock) +*/ +{ + struct list_head *pool = &port->read_pool; + struct usb_ep *out = port->port_usb->out; + + while (!list_empty(pool)) { + struct usb_request *req; + int status; + struct tty_struct *tty; + + /* no more rx if closed */ + tty = port->port.tty; + if (!tty) + break; + + if (port->read_started >= QUEUE_SIZE) + break; + + req = list_entry(pool->next, struct usb_request, list); + list_del(&req->list); + req->length = out->maxpacket; + + /* drop lock while we call out; the controller driver + * may need to call us back (e.g. for disconnect) + */ + spin_unlock(&port->port_lock); + status = usb_ep_queue(out, req, GFP_ATOMIC); + spin_lock(&port->port_lock); + + if (status) { + pr_debug("%s: %s %s err %d\n", + __func__, "queue", out->name, status); + list_add(&req->list, pool); + break; + } + port->read_started++; + + /* abort immediately after disconnect */ + if (!port->port_usb) + break; + } + return port->read_started; +} + +/* + * RX tasklet takes data out of the RX queue and hands it up to the TTY + * layer until it refuses to take any more data (or is throttled back). + * Then it issues reads for any further data. + * + * If the RX queue becomes full enough that no usb_request is queued, + * the OUT endpoint may begin NAKing as soon as its FIFO fills up. + * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) + * can be buffered before the TTY layer's buffers (currently 64 KB). + */ +static void gs_rx_push(unsigned long _port) +{ + struct gs_port *port = (void *)_port; + struct tty_struct *tty; + struct list_head *queue = &port->read_queue; + bool disconnect = false; + bool do_push = false; + + /* hand any queued data to the tty */ + spin_lock_irq(&port->port_lock); + tty = port->port.tty; + while (!list_empty(queue)) { + struct usb_request *req; + + req = list_first_entry(queue, struct usb_request, list); + + /* discard data if tty was closed */ + if (!tty) + goto recycle; + + /* leave data queued if tty was rx throttled */ + if (test_bit(TTY_THROTTLED, &tty->flags)) + break; + + switch (req->status) { + case -ESHUTDOWN: + disconnect = true; + pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); + break; + + default: + /* presumably a transient fault */ + pr_warning(PREFIX "%d: unexpected RX status %d\n", + port->port_num, req->status); + /* FALLTHROUGH */ + case 0: + /* normal completion */ + break; + } + + /* push data to (open) tty */ + if (req->actual) { + char *packet = req->buf; + unsigned size = req->actual; + unsigned n; + int count; + + /* we may have pushed part of this packet already... */ + n = port->n_read; + if (n) { + packet += n; + size -= n; + } + + count = tty_insert_flip_string(tty, packet, size); + if (count) + do_push = true; + if (count != size) { + /* stop pushing; TTY layer can't handle more */ + port->n_read += count; + pr_vdebug(PREFIX "%d: rx block %d/%d\n", + port->port_num, + count, req->actual); + break; + } + port->n_read = 0; + } +recycle: + list_move(&req->list, &port->read_pool); + port->read_started--; + } + + /* Push from tty to ldisc; without low_latency set this is handled by + * a workqueue, so we won't get callbacks and can hold port_lock + */ + if (tty && do_push) + tty_flip_buffer_push(tty); + + + /* We want our data queue to become empty ASAP, keeping data + * in the tty and ldisc (not here). If we couldn't push any + * this time around, there may be trouble unless there's an + * implicit tty_unthrottle() call on its way... + * + * REVISIT we should probably add a timer to keep the tasklet + * from starving ... but it's not clear that case ever happens. + */ + if (!list_empty(queue) && tty) { + if (!test_bit(TTY_THROTTLED, &tty->flags)) { + if (do_push) + tasklet_schedule(&port->push); + else + pr_warning(PREFIX "%d: RX not scheduled?\n", + port->port_num); + } + } + + /* If we're still connected, refill the USB RX queue. */ + if (!disconnect && port->port_usb) + gs_start_rx(port); + + spin_unlock_irq(&port->port_lock); +} + +static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct gs_port *port = ep->driver_data; + + /* Queue all received data until the tty layer is ready for it. */ + spin_lock(&port->port_lock); + list_add_tail(&req->list, &port->read_queue); + tasklet_schedule(&port->push); + spin_unlock(&port->port_lock); +} + +static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct gs_port *port = ep->driver_data; + + spin_lock(&port->port_lock); + list_add(&req->list, &port->write_pool); + port->write_started--; + + switch (req->status) { + default: + /* presumably a transient fault */ + pr_warning("%s: unexpected %s status %d\n", + __func__, ep->name, req->status); + /* FALL THROUGH */ + case 0: + /* normal completion */ + gs_start_tx(port); + break; + + case -ESHUTDOWN: + /* disconnect */ + pr_vdebug("%s: %s shutdown\n", __func__, ep->name); + break; + } + + spin_unlock(&port->port_lock); +} + +static void gs_free_requests(struct usb_ep *ep, struct list_head *head, + int *allocated) +{ + struct usb_request *req; + + while (!list_empty(head)) { + req = list_entry(head->next, struct usb_request, list); + list_del(&req->list); + gs_free_req(ep, req); + if (allocated) + (*allocated)--; + } +} + +static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, + void (*fn)(struct usb_ep *, struct usb_request *), + int *allocated) +{ + int i; + struct usb_request *req; + int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE; + + /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't + * do quite that many this time, don't fail ... we just won't + * be as speedy as we might otherwise be. + */ + for (i = 0; i < n; i++) { + req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC); + if (!req) + return list_empty(head) ? -ENOMEM : 0; + req->complete = fn; + list_add_tail(&req->list, head); + if (allocated) + (*allocated)++; + } + return 0; +} + +/** + * gs_start_io - start USB I/O streams + * @dev: encapsulates endpoints to use + * Context: holding port_lock; port_tty and port_usb are non-null + * + * We only start I/O when something is connected to both sides of + * this port. If nothing is listening on the host side, we may + * be pointlessly filling up our TX buffers and FIFO. + */ +static int gs_start_io(struct gs_port *port) +{ + struct list_head *head = &port->read_pool; + struct usb_ep *ep = port->port_usb->out; + int status; + unsigned started; + + /* Allocate RX and TX I/O buffers. We can't easily do this much + * earlier (with GFP_KERNEL) because the requests are coupled to + * endpoints, as are the packet sizes we'll be using. Different + * configurations may use different endpoints with a given port; + * and high speed vs full speed changes packet sizes too. + */ + status = gs_alloc_requests(ep, head, gs_read_complete, + &port->read_allocated); + if (status) + return status; + + status = gs_alloc_requests(port->port_usb->in, &port->write_pool, + gs_write_complete, &port->write_allocated); + if (status) { + gs_free_requests(ep, head, &port->read_allocated); + return status; + } + + /* queue read requests */ + port->n_read = 0; + started = gs_start_rx(port); + + /* unblock any pending writes into our circular buffer */ + if (started) { + tty_wakeup(port->port.tty); + } else { + gs_free_requests(ep, head, &port->read_allocated); + gs_free_requests(port->port_usb->in, &port->write_pool, + &port->write_allocated); + status = -EIO; + } + + return status; +} + +/*-------------------------------------------------------------------------*/ + +/* TTY Driver */ + +/* + * gs_open sets up the link between a gs_port and its associated TTY. + * That link is broken *only* by TTY close(), and all driver methods + * know that. + */ +static int gs_open(struct tty_struct *tty, struct file *file) +{ + int port_num = tty->index; + struct gs_port *port; + int status; + + do { + mutex_lock(&ports[port_num].lock); + port = ports[port_num].port; + if (!port) + status = -ENODEV; + else { + spin_lock_irq(&port->port_lock); + + /* already open? Great. */ + if (port->port.count) { + status = 0; + port->port.count++; + + /* currently opening/closing? wait ... */ + } else if (port->openclose) { + status = -EBUSY; + + /* ... else we do the work */ + } else { + status = -EAGAIN; + port->openclose = true; + } + spin_unlock_irq(&port->port_lock); + } + mutex_unlock(&ports[port_num].lock); + + switch (status) { + default: + /* fully handled */ + return status; + case -EAGAIN: + /* must do the work */ + break; + case -EBUSY: + /* wait for EAGAIN task to finish */ + msleep(1); + /* REVISIT could have a waitchannel here, if + * concurrent open performance is important + */ + break; + } + } while (status != -EAGAIN); + + /* Do the "real open" */ + spin_lock_irq(&port->port_lock); + + /* allocate circular buffer on first open */ + if (port->port_write_buf.buf_buf == NULL) { + + spin_unlock_irq(&port->port_lock); + status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); + spin_lock_irq(&port->port_lock); + + if (status) { + pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", + port->port_num, tty, file); + port->openclose = false; + goto exit_unlock_port; + } + } + + /* REVISIT if REMOVED (ports[].port NULL), abort the open + * to let rmmod work faster (but this way isn't wrong). + */ + + /* REVISIT maybe wait for "carrier detect" */ + + tty->driver_data = port; + port->port.tty = tty; + + port->port.count = 1; + port->openclose = false; + + /* if connected, start the I/O stream */ + if (port->port_usb) { + struct gserial *gser = port->port_usb; + + pr_debug("gs_open: start ttyGS%d\n", port->port_num); + gs_start_io(port); + + if (gser->connect) + gser->connect(gser); + } + + pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); + + status = 0; + +exit_unlock_port: + spin_unlock_irq(&port->port_lock); + return status; +} + +static int gs_writes_finished(struct gs_port *p) +{ + int cond; + + /* return true on disconnect or empty buffer */ + spin_lock_irq(&p->port_lock); + cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf); + spin_unlock_irq(&p->port_lock); + + return cond; +} + +static void gs_close(struct tty_struct *tty, struct file *file) +{ + struct gs_port *port = tty->driver_data; + struct gserial *gser; + + spin_lock_irq(&port->port_lock); + + if (port->port.count != 1) { + if (port->port.count == 0) + WARN_ON(1); + else + --port->port.count; + goto exit; + } + + pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file); + + /* mark port as closing but in use; we can drop port lock + * and sleep if necessary + */ + port->openclose = true; + port->port.count = 0; + + gser = port->port_usb; + if (gser && gser->disconnect) + gser->disconnect(gser); + + /* wait for circular write buffer to drain, disconnect, or at + * most GS_CLOSE_TIMEOUT seconds; then discard the rest + */ + if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { + spin_unlock_irq(&port->port_lock); + wait_event_interruptible_timeout(port->drain_wait, + gs_writes_finished(port), + GS_CLOSE_TIMEOUT * HZ); + spin_lock_irq(&port->port_lock); + gser = port->port_usb; + } + + /* Iff we're disconnected, there can be no I/O in flight so it's + * ok to free the circular buffer; else just scrub it. And don't + * let the push tasklet fire again until we're re-opened. + */ + if (gser == NULL) + gs_buf_free(&port->port_write_buf); + else + gs_buf_clear(&port->port_write_buf); + + tty->driver_data = NULL; + port->port.tty = NULL; + + port->openclose = false; + + pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", + port->port_num, tty, file); + + wake_up_interruptible(&port->port.close_wait); +exit: + spin_unlock_irq(&port->port_lock); +} + +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + int status; + + pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", + port->port_num, tty, count); + + spin_lock_irqsave(&port->port_lock, flags); + if (count) + count = gs_buf_put(&port->port_write_buf, buf, count); + /* treat count == 0 as flush_chars() */ + if (port->port_usb) + status = gs_start_tx(port); + spin_unlock_irqrestore(&port->port_lock, flags); + + return count; +} + +static int gs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + int status; + + pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n", + port->port_num, tty, ch, __builtin_return_address(0)); + + spin_lock_irqsave(&port->port_lock, flags); + status = gs_buf_put(&port->port_write_buf, &ch, 1); + spin_unlock_irqrestore(&port->port_lock, flags); + + return status; +} + +static void gs_flush_chars(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + + pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); + + spin_lock_irqsave(&port->port_lock, flags); + if (port->port_usb) + gs_start_tx(port); + spin_unlock_irqrestore(&port->port_lock, flags); +} + +static int gs_write_room(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + int room = 0; + + spin_lock_irqsave(&port->port_lock, flags); + if (port->port_usb) + room = gs_buf_space_avail(&port->port_write_buf); + spin_unlock_irqrestore(&port->port_lock, flags); + + pr_vdebug("gs_write_room: (%d,%p) room=%d\n", + port->port_num, tty, room); + + return room; +} + +static int gs_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + int chars = 0; + + spin_lock_irqsave(&port->port_lock, flags); + chars = gs_buf_data_avail(&port->port_write_buf); + spin_unlock_irqrestore(&port->port_lock, flags); + + pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n", + port->port_num, tty, chars); + + return chars; +} + +/* undo side effects of setting TTY_THROTTLED */ +static void gs_unthrottle(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + + spin_lock_irqsave(&port->port_lock, flags); + if (port->port_usb) { + /* Kickstart read queue processing. We don't do xon/xoff, + * rts/cts, or other handshaking with the host, but if the + * read queue backs up enough we'll be NAKing OUT packets. + */ + tasklet_schedule(&port->push); + pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); + } + spin_unlock_irqrestore(&port->port_lock, flags); +} + +static int gs_break_ctl(struct tty_struct *tty, int duration) +{ + struct gs_port *port = tty->driver_data; + int status = 0; + struct gserial *gser; + + pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n", + port->port_num, duration); + + spin_lock_irq(&port->port_lock); + gser = port->port_usb; + if (gser && gser->send_break) + status = gser->send_break(gser, duration); + spin_unlock_irq(&port->port_lock); + + return status; +} + +static const struct tty_operations gs_tty_ops = { + .open = gs_open, + .close = gs_close, + .write = gs_write, + .put_char = gs_put_char, + .flush_chars = gs_flush_chars, + .write_room = gs_write_room, + .chars_in_buffer = gs_chars_in_buffer, + .unthrottle = gs_unthrottle, + .break_ctl = gs_break_ctl, +}; + +/*-------------------------------------------------------------------------*/ + +static struct tty_driver *gs_tty_driver; + +static int +gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) +{ + struct gs_port *port; + + port = kzalloc(sizeof(struct gs_port), GFP_KERNEL); + if (port == NULL) + return -ENOMEM; + + tty_port_init(&port->port); + spin_lock_init(&port->port_lock); + init_waitqueue_head(&port->drain_wait); + + tasklet_init(&port->push, gs_rx_push, (unsigned long) port); + + INIT_LIST_HEAD(&port->read_pool); + INIT_LIST_HEAD(&port->read_queue); + INIT_LIST_HEAD(&port->write_pool); + + port->port_num = port_num; + port->port_line_coding = *coding; + + ports[port_num].port = port; + + return 0; +} + +/** + * gserial_setup - initialize TTY driver for one or more ports + * @g: gadget to associate with these ports + * @count: how many ports to support + * Context: may sleep + * + * The TTY stack needs to know in advance how many devices it should + * plan to manage. Use this call to set up the ports you will be + * exporting through USB. Later, connect them to functions based + * on what configuration is activated by the USB host; and disconnect + * them as appropriate. + * + * An example would be a two-configuration device in which both + * configurations expose port 0, but through different functions. + * One configuration could even expose port 1 while the other + * one doesn't. + * + * Returns negative errno or zero. + */ +int gserial_setup(struct usb_gadget *g, unsigned count) +{ + unsigned i; + struct usb_cdc_line_coding coding; + int status; + + if (count == 0 || count > N_PORTS) + return -EINVAL; + + gs_tty_driver = alloc_tty_driver(count); + if (!gs_tty_driver) + return -ENOMEM; + + gs_tty_driver->driver_name = "g_serial"; + gs_tty_driver->name = PREFIX; + /* uses dynamically assigned dev_t values */ + + gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; + gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + gs_tty_driver->init_termios = tty_std_termios; + + /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on + * MS-Windows. Otherwise, most of these flags shouldn't affect + * anything unless we were to actually hook up to a serial line. + */ + gs_tty_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + gs_tty_driver->init_termios.c_ispeed = 9600; + gs_tty_driver->init_termios.c_ospeed = 9600; + + coding.dwDTERate = cpu_to_le32(9600); + coding.bCharFormat = 8; + coding.bParityType = USB_CDC_NO_PARITY; + coding.bDataBits = USB_CDC_1_STOP_BITS; + + tty_set_operations(gs_tty_driver, &gs_tty_ops); + + /* make devices be openable */ + for (i = 0; i < count; i++) { + mutex_init(&ports[i].lock); + status = gs_port_alloc(i, &coding); + if (status) { + count = i; + goto fail; + } + } + n_ports = count; + + /* export the driver ... */ + status = tty_register_driver(gs_tty_driver); + if (status) { + pr_err("%s: cannot register, err %d\n", + __func__, status); + goto fail; + } + + /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ + for (i = 0; i < count; i++) { + struct device *tty_dev; + + tty_dev = tty_register_device(gs_tty_driver, i, &g->dev); + if (IS_ERR(tty_dev)) + pr_warning("%s: no classdev for port %d, err %ld\n", + __func__, i, PTR_ERR(tty_dev)); + } + + pr_debug("%s: registered %d ttyGS* device%s\n", __func__, + count, (count == 1) ? "" : "s"); + + return status; +fail: + while (count--) + kfree(ports[count].port); + put_tty_driver(gs_tty_driver); + gs_tty_driver = NULL; + return status; +} + +static int gs_closed(struct gs_port *port) +{ + int cond; + + spin_lock_irq(&port->port_lock); + cond = (port->port.count == 0) && !port->openclose; + spin_unlock_irq(&port->port_lock); + return cond; +} + +/** + * gserial_cleanup - remove TTY-over-USB driver and devices + * Context: may sleep + * + * This is called to free all resources allocated by @gserial_setup(). + * Accordingly, it may need to wait until some open /dev/ files have + * closed. + * + * The caller must have issued @gserial_disconnect() for any ports + * that had previously been connected, so that there is never any + * I/O pending when it's called. + */ +void gserial_cleanup(void) +{ + unsigned i; + struct gs_port *port; + + if (!gs_tty_driver) + return; + + /* start sysfs and /dev/ttyGS* node removal */ + for (i = 0; i < n_ports; i++) + tty_unregister_device(gs_tty_driver, i); + + for (i = 0; i < n_ports; i++) { + /* prevent new opens */ + mutex_lock(&ports[i].lock); + port = ports[i].port; + ports[i].port = NULL; + mutex_unlock(&ports[i].lock); + + tasklet_kill(&port->push); + + /* wait for old opens to finish */ + wait_event(port->port.close_wait, gs_closed(port)); + + WARN_ON(port->port_usb != NULL); + + kfree(port); + } + n_ports = 0; + + tty_unregister_driver(gs_tty_driver); + put_tty_driver(gs_tty_driver); + gs_tty_driver = NULL; + + pr_debug("%s: cleaned up ttyGS* support\n", __func__); +} + +/** + * gserial_connect - notify TTY I/O glue that USB link is active + * @gser: the function, set up with endpoints and descriptors + * @port_num: which port is active + * Context: any (usually from irq) + * + * This is called activate endpoints and let the TTY layer know that + * the connection is active ... not unlike "carrier detect". It won't + * necessarily start I/O queues; unless the TTY is held open by any + * task, there would be no point. However, the endpoints will be + * activated so the USB host can perform I/O, subject to basic USB + * hardware flow control. + * + * Caller needs to have set up the endpoints and USB function in @dev + * before calling this, as well as the appropriate (speed-specific) + * endpoint descriptors, and also have set up the TTY driver by calling + * @gserial_setup(). + * + * Returns negative errno or zero. + * On success, ep->driver_data will be overwritten. + */ +int gserial_connect(struct gserial *gser, u8 port_num) +{ + struct gs_port *port; + unsigned long flags; + int status; + + if (!gs_tty_driver || port_num >= n_ports) + return -ENXIO; + + /* we "know" gserial_cleanup() hasn't been called */ + port = ports[port_num].port; + + /* activate the endpoints */ + status = usb_ep_enable(gser->in); + if (status < 0) + return status; + gser->in->driver_data = port; + + status = usb_ep_enable(gser->out); + if (status < 0) + goto fail_out; + gser->out->driver_data = port; + + /* then tell the tty glue that I/O can work */ + spin_lock_irqsave(&port->port_lock, flags); + gser->ioport = port; + port->port_usb = gser; + + /* REVISIT unclear how best to handle this state... + * we don't really couple it with the Linux TTY. + */ + gser->port_line_coding = port->port_line_coding; + + /* REVISIT if waiting on "carrier detect", signal. */ + + /* if it's already open, start I/O ... and notify the serial + * protocol about open/close status (connect/disconnect). + */ + if (port->port.count) { + pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); + gs_start_io(port); + if (gser->connect) + gser->connect(gser); + } else { + if (gser->disconnect) + gser->disconnect(gser); + } + + spin_unlock_irqrestore(&port->port_lock, flags); + + return status; + +fail_out: + usb_ep_disable(gser->in); + gser->in->driver_data = NULL; + return status; +} + +/** + * gserial_disconnect - notify TTY I/O glue that USB link is inactive + * @gser: the function, on which gserial_connect() was called + * Context: any (usually from irq) + * + * This is called to deactivate endpoints and let the TTY layer know + * that the connection went inactive ... not unlike "hangup". + * + * On return, the state is as if gserial_connect() had never been called; + * there is no active USB I/O on these endpoints. + */ +void gserial_disconnect(struct gserial *gser) +{ + struct gs_port *port = gser->ioport; + unsigned long flags; + + if (!port) + return; + + /* tell the TTY glue not to do I/O here any more */ + spin_lock_irqsave(&port->port_lock, flags); + + /* REVISIT as above: how best to track this? */ + port->port_line_coding = gser->port_line_coding; + + port->port_usb = NULL; + gser->ioport = NULL; + if (port->port.count > 0 || port->openclose) { + wake_up_interruptible(&port->drain_wait); + if (port->port.tty) + tty_hangup(port->port.tty); + } + spin_unlock_irqrestore(&port->port_lock, flags); + + /* disable endpoints, aborting down any active I/O */ + usb_ep_disable(gser->out); + gser->out->driver_data = NULL; + + usb_ep_disable(gser->in); + gser->in->driver_data = NULL; + + /* finally, free any unused/unusable I/O buffers */ + spin_lock_irqsave(&port->port_lock, flags); + if (port->port.count == 0 && !port->openclose) + gs_buf_free(&port->port_write_buf); + gs_free_requests(gser->out, &port->read_pool, NULL); + gs_free_requests(gser->out, &port->read_queue, NULL); + gs_free_requests(gser->in, &port->write_pool, NULL); + + port->read_allocated = port->read_started = + port->write_allocated = port->write_started = 0; + + spin_unlock_irqrestore(&port->port_lock, flags); +} diff --git a/drivers/staging/ccg/u_serial.h b/drivers/staging/ccg/u_serial.h new file mode 100644 index 0000000..9b0fe64 --- /dev/null +++ b/drivers/staging/ccg/u_serial.h @@ -0,0 +1,65 @@ +/* + * u_serial.h - interface to USB gadget "serial port"/TTY utilities + * + * Copyright (C) 2008 David Brownell + * Copyright (C) 2008 by Nokia Corporation + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of that License or (at your option) any later version. + */ + +#ifndef __U_SERIAL_H +#define __U_SERIAL_H + +#include <linux/usb/composite.h> +#include <linux/usb/cdc.h> + +/* + * One non-multiplexed "serial" I/O port ... there can be several of these + * on any given USB peripheral device, if it provides enough endpoints. + * + * The "u_serial" utility component exists to do one thing: manage TTY + * style I/O using the USB peripheral endpoints listed here, including + * hookups to sysfs and /dev for each logical "tty" device. + * + * REVISIT at least ACM could support tiocmget() if needed. + * + * REVISIT someday, allow multiplexing several TTYs over these endpoints. + */ +struct gserial { + struct usb_function func; + + /* port is managed by gserial_{connect,disconnect} */ + struct gs_port *ioport; + + struct usb_ep *in; + struct usb_ep *out; + + /* REVISIT avoid this CDC-ACM support harder ... */ + struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ + + /* notification callbacks */ + void (*connect)(struct gserial *p); + void (*disconnect)(struct gserial *p); + int (*send_break)(struct gserial *p, int duration); +}; + +/* utilities to allocate/free request and buffer */ +struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags); +void gs_free_req(struct usb_ep *, struct usb_request *req); + +/* port setup/teardown is handled by gadget driver */ +int gserial_setup(struct usb_gadget *g, unsigned n_ports); +void gserial_cleanup(void); + +/* connect/disconnect is handled by individual functions */ +int gserial_connect(struct gserial *, u8 port_num); +void gserial_disconnect(struct gserial *); + +/* functions are bound to configurations by a config or gadget driver */ +int acm_bind_config(struct usb_configuration *c, u8 port_num); +int gser_bind_config(struct usb_configuration *c, u8 port_num); +int obex_bind_config(struct usb_configuration *c, u8 port_num); + +#endif /* __U_SERIAL_H */ diff --git a/drivers/staging/ccg/usbstring.c b/drivers/staging/ccg/usbstring.c new file mode 100644 index 0000000..4d25b90 --- /dev/null +++ b/drivers/staging/ccg/usbstring.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/string.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/nls.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + + +/** + * usb_gadget_get_string - fill out a string descriptor + * @table: of c strings encoded using UTF-8 + * @id: string id, from low byte of wValue in get string descriptor + * @buf: at least 256 bytes, must be 16-bit aligned + * + * Finds the UTF-8 string matching the ID, and converts it into a + * string descriptor in utf16-le. + * Returns length of descriptor (always even) or negative errno + * + * If your driver needs stings in multiple languages, you'll probably + * "switch (wIndex) { ... }" in your ep0 string descriptor logic, + * using this routine after choosing which set of UTF-8 strings to use. + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 + * characters (which are also widely used in C strings). + */ +int +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) +{ + struct usb_string *s; + int len; + + /* descriptor 0 has the language id */ + if (id == 0) { + buf [0] = 4; + buf [1] = USB_DT_STRING; + buf [2] = (u8) table->language; + buf [3] = (u8) (table->language >> 8); + return 4; + } + for (s = table->strings; s && s->s; s++) + if (s->id == id) + break; + + /* unrecognized: stall. */ + if (!s || !s->s) + return -EINVAL; + + /* string descriptors have length, tag, then UTF16-LE text */ + len = min ((size_t) 126, strlen (s->s)); + len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[2], 126); + if (len < 0) + return -EINVAL; + buf [0] = (len + 1) * 2; + buf [1] = USB_DT_STRING; + return buf [0]; +} + diff --git a/drivers/staging/keucr/usb.c b/drivers/staging/keucr/usb.c index 4833034..55a0b82 100644 --- a/drivers/staging/keucr/usb.c +++ b/drivers/staging/keucr/usb.c @@ -320,7 +320,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id) us->subclass = idesc->bInterfaceSubClass; us->protocol = idesc->bInterfaceProtocol; - us->fflags = USB_US_ORIG_FLAGS(id->driver_info); + us->fflags = id->driver_info; us->Power_IsResum = false; if (us->fflags & US_FL_IGNORE_DEVICE) diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 5c969ad..099bc69 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -16,8 +16,6 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static bool debug; - /* Version Information */ #define DRIVER_VERSION "v2.14" #define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc" @@ -184,11 +182,11 @@ static int port_paranoia_check(struct usb_serial_port *port, const char *function) { if (!port) { - dbg("%s - port == NULL", function); + pr_debug("%s - port == NULL", function); return -1; } if (!port->serial) { - dbg("%s - port->serial == NULL\n", function); + pr_debug("%s - port->serial == NULL\n", function); return -1; } @@ -199,12 +197,12 @@ static int serial_paranoia_check(struct usb_serial *serial, const char *function) { if (!serial) { - dbg("%s - serial == NULL\n", function); + pr_debug("%s - serial == NULL\n", function); return -1; } if (!serial->type) { - dbg("%s - serial->type == NULL!", function); + pr_debug("%s - serial->type == NULL!", function); return -1; } @@ -274,7 +272,7 @@ static void qt_write_bulk_callback(struct urb *urb) status = urb->status; if (status) { - dbg("nonzero write bulk status received:%d\n", status); + dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status); return; } @@ -307,8 +305,8 @@ static void qt_read_bulk_callback(struct urb *urb) if (urb->status) { qt_port->ReadBulkStopped = 1; - dbg("%s - nonzero write bulk status received: %d\n", - __func__, urb->status); + dev_dbg(&urb->dev->dev, "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); return; } @@ -323,21 +321,19 @@ static void qt_read_bulk_callback(struct urb *urb) /* index = MINOR(port->tty->device) - serial->minor; */ index = tty->index - serial->minor; - dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); + dev_dbg(&port->dev, "%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); if (port_paranoia_check(port, __func__) != 0) { - dbg("%s - port_paranoia_check, exiting\n", __func__); qt_port->ReadBulkStopped = 1; goto exit; } - if (!serial) { - dbg("%s - bad serial pointer, exiting\n", __func__); + if (!serial) goto exit; - } + if (qt_port->closePending == 1) { /* Were closing , stop reading */ - dbg("%s - (qt_port->closepending == 1\n", __func__); + dev_dbg(&port->dev, "%s - (qt_port->closepending == 1\n", __func__); qt_port->ReadBulkStopped = 1; goto exit; } @@ -355,8 +351,8 @@ static void qt_read_bulk_callback(struct urb *urb) if (urb->status) { qt_port->ReadBulkStopped = 1; - dbg("%s - nonzero read bulk status received: %d\n", - __func__, urb->status); + dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n", + __func__, urb->status); goto exit; } @@ -371,7 +367,7 @@ static void qt_read_bulk_callback(struct urb *urb) case 0x00: /* line status change 4th byte must follow */ if (i > (RxCount - 4)) { - dbg("Illegal escape seuences in received data\n"); + dev_dbg(&port->dev, "Illegal escape seuences in received data\n"); break; } ProcessLineStatus(qt_port, data[i + 3]); @@ -381,9 +377,9 @@ static void qt_read_bulk_callback(struct urb *urb) case 0x01: /* Modem status status change 4th byte must follow */ - dbg("Modem status status.\n"); + dev_dbg(&port->dev, "Modem status status.\n"); if (i > (RxCount - 4)) { - dbg("Illegal escape sequences in received data\n"); + dev_dbg(&port->dev, "Illegal escape sequences in received data\n"); break; } ProcessModemStatus(qt_port, @@ -392,7 +388,7 @@ static void qt_read_bulk_callback(struct urb *urb) flag = 1; break; case 0xff: - dbg("No status sequence.\n"); + dev_dbg(&port->dev, "No status sequence.\n"); if (tty) { ProcessRxChar(tty, port, data[i]); @@ -421,8 +417,8 @@ static void qt_read_bulk_callback(struct urb *urb) qt_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dbg("%s - failed resubmitting read urb, error %d", - __func__, result); + dev_dbg(&port->dev, "%s - failed resubmitting read urb, error %d", + __func__, result); else { if (RxCount) { tty_flip_buffer_push(tty); @@ -517,7 +513,6 @@ static int qt_set_device(struct usb_serial *serial, PortSettings += ((__u16) (device_data->porta)); length = sizeof(struct qt_get_device_data); - dbg("%s - PortSettings = 0x%x\n", __func__, PortSettings); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_SET_GET_DEVICE, 0x40, PortSettings, @@ -691,6 +686,7 @@ static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 index) static int qt_startup(struct usb_serial *serial) { + struct device *dev = &serial->dev->dev; struct usb_serial_port *port; struct quatech_port *qt_port; struct qt_get_device_data DeviceData; @@ -702,8 +698,6 @@ static int qt_startup(struct usb_serial *serial) port = serial->port[i]; qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL); if (!qt_port) { - dbg("%s: kzalloc for quatech_port (%d) failed!.", - __func__, i); for (--i; i >= 0; i--) { port = serial->port[i]; kfree(usb_get_serial_port_data(port)); @@ -718,25 +712,23 @@ static int qt_startup(struct usb_serial *serial) } status = qt_get_device(serial, &DeviceData); - if (status < 0) { - dbg(__FILE__ "box_get_device failed"); + if (status < 0) goto startup_error; - } - dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); + dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb); DeviceData.portb &= ~FULLPWRBIT; - dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); + dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb); status = qt_set_device(serial, &DeviceData); if (status < 0) { - dbg(__FILE__ "qt_set_device failed\n"); + dev_dbg(dev, "qt_set_device failed\n"); goto startup_error; } status = qt_get_device(serial, &DeviceData); if (status < 0) { - dbg(__FILE__ "qt_get_device failed"); + dev_dbg(dev, "qt_get_device failed\n"); goto startup_error; } @@ -780,29 +772,27 @@ static int qt_startup(struct usb_serial *serial) status = BoxSetPrebufferLevel(serial); /* sets to default value */ if (status < 0) { - dbg(__FILE__ "BoxSetPrebufferLevel failed\n"); + dev_dbg(dev, "BoxSetPrebufferLevel failed\n"); goto startup_error; } status = BoxSetATC(serial, ATC_DISABLED); if (status < 0) { - dbg(__FILE__ "BoxSetATC failed\n"); + dev_dbg(dev, "BoxSetATC failed\n"); goto startup_error; } - dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); + dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb); DeviceData.portb |= NEXT_BOARD_POWER_BIT; - dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); + dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb); status = qt_set_device(serial, &DeviceData); if (status < 0) { - dbg(__FILE__ "qt_set_device failed\n"); + dev_dbg(dev, "qt_set_device failed\n"); goto startup_error; } - dbg("Exit Success %s\n", __func__); - return 0; startup_error: @@ -813,8 +803,6 @@ startup_error: usb_set_serial_port_data(port, NULL); } - dbg("Exit fail %s\n", __func__); - return -EIO; } @@ -869,10 +857,10 @@ static int qt_open(struct tty_struct *tty, /* Port specific setups */ result = qt_open_channel(serial, port->number, &ChannelData); if (result < 0) { - dbg(__FILE__ "qt_open_channel failed\n"); + dev_dbg(&port->dev, "qt_open_channel failed\n"); return result; } - dbg(__FILE__ "qt_open_channel completed.\n"); + dev_dbg(&port->dev, "qt_open_channel completed.\n"); /* FIXME: are these needed? Does it even do anything useful? */ quatech_port->shadowLSR = ChannelData.line_status & @@ -884,10 +872,10 @@ static int qt_open(struct tty_struct *tty, /* Set Baud rate to default and turn off (default)flow control here */ result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR); if (result < 0) { - dbg(__FILE__ "qt_setuart failed\n"); + dev_dbg(&port->dev, "qt_setuart failed\n"); return result; } - dbg(__FILE__ "qt_setuart completed.\n"); + dev_dbg(&port->dev, "qt_setuart completed.\n"); /* * Put this here to make it responsive to stty and defaults set by @@ -922,12 +910,12 @@ static int qt_open(struct tty_struct *tty, } - dbg("port number is %d\n", port->number); - dbg("serial number is %d\n", port->serial->minor); - dbg("Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); - dbg("BulkOut endpoint is %d\n", port->bulk_out_endpointAddress); - dbg("Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress); - dbg("port's number in the device is %d\n", quatech_port->port_num); + dev_dbg(&port->dev, "port number is %d\n", port->number); + dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor); + dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress); + dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress); + dev_dbg(&port->dev, "port's number in the device is %d\n", quatech_port->port_num); quatech_port->read_urb = port->read_urb; /* set up our bulk in urb */ @@ -940,7 +928,7 @@ static int qt_open(struct tty_struct *tty, quatech_port->read_urb->transfer_buffer_length, qt_read_bulk_callback, quatech_port); - dbg("qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress); quatech_port->read_urb_busy = true; result = usb_submit_urb(quatech_port->read_urb, GFP_KERNEL); if (result) { @@ -974,8 +962,6 @@ static int qt_chars_in_buffer(struct tty_struct *tty) chars = port->write_urb->transfer_buffer_length; } - dbg("%s - returns %d\n", __func__, chars); - return chars; } @@ -997,7 +983,7 @@ static void qt_block_until_empty(struct tty_struct *tty, wait--; if (wait == 0) { - dbg("%s - TIMEOUT", __func__); + dev_dbg(&qt_port->port->dev, "%s - TIMEOUT", __func__); return; } else { wait = 30; @@ -1035,17 +1021,15 @@ static void qt_close(struct usb_serial_port *port) /* Close uart channel */ status = qt_close_channel(serial, index); if (status < 0) - dbg("%s - port %d qt_close_channel failed.\n", - __func__, port->number); + dev_dbg(&port->dev, "%s - port %d qt_close_channel failed.\n", __func__, port->number); port0->open_ports--; - dbg("qt_num_open_ports in close%d:in port%d\n", - port0->open_ports, port->number); + dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n", port0->open_ports, port->number); if (port0->open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { - dbg("%s", "Shutdown interrupt_in_urb\n"); + dev_dbg(&port->dev, "%s", "Shutdown interrupt_in_urb\n"); usb_kill_urb(serial->port[0]->interrupt_in_urb); } @@ -1069,14 +1053,14 @@ static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, return -ENODEV; if (count == 0) { - dbg("%s - write request of 0 bytes\n", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) { - dbg("%s - already writing\n", __func__); + dev_dbg(&port->dev, "%s - already writing\n", __func__); return 0; } @@ -1096,8 +1080,8 @@ static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) - dbg("%s - failed submitting write urb, error %d\n", - __func__, result); + dev_dbg(&port->dev, "%s - failed submitting write urb, error %d\n", + __func__, result); else result = count; @@ -1116,10 +1100,8 @@ static int qt_write_room(struct tty_struct *tty) int retval = -EINVAL; - if (port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port\n"); + if (port_paranoia_check(port, __func__)) return -1; - } serial = get_usb_serial(port, __func__); @@ -1148,7 +1130,7 @@ static int qt_ioctl(struct tty_struct *tty, struct usb_serial *serial = get_usb_serial(port, __func__); unsigned int index; - dbg("%s cmd 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); index = tty->index - serial->minor; @@ -1181,7 +1163,7 @@ static int qt_ioctl(struct tty_struct *tty, return 0; } - dbg("%s -No ioctl for that one. port = %d\n", __func__, port->number); + dev_dbg(&port->dev, "%s -No ioctl for that one. port = %d\n", __func__, port->number); return -ENOIOCTLCMD; } @@ -1228,7 +1210,7 @@ static void qt_set_termios(struct tty_struct *tty, else new_LCR |= SERIAL_ONE_STOPB; - dbg("%s - 4\n", __func__); + dev_dbg(&port->dev, "%s - 4\n", __func__); /* Thats the LCR stuff, go ahead and set it */ baud = tty_get_baud_rate(tty); @@ -1236,7 +1218,7 @@ static void qt_set_termios(struct tty_struct *tty, /* pick a default, any default... */ baud = 9600; - dbg("%s - got baud = %d\n", __func__, baud); + dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud); divisor = MAX_BAUD_RATE / baud; remainder = MAX_BAUD_RATE % baud; @@ -1250,30 +1232,28 @@ static void qt_set_termios(struct tty_struct *tty, status = qt_setuart(port->serial, index, (unsigned short)divisor, new_LCR); if (status < 0) { - dbg(__FILE__ "qt_setuart failed\n"); + dev_dbg(&port->dev, "qt_setuart failed\n"); return; } /* Now determine flow control */ if (cflag & CRTSCTS) { - dbg("%s - Enabling HW flow control port %d\n", __func__, - port->number); + dev_dbg(&port->dev, "%s - Enabling HW flow control port %d\n", __func__, port->number); /* Enable RTS/CTS flow control */ status = BoxSetHW_FlowCtrl(port->serial, index, 1); if (status < 0) { - dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); + dev_dbg(&port->dev, "BoxSetHW_FlowCtrl failed\n"); return; } } else { /* Disable RTS/CTS flow control */ - dbg("%s - disabling HW flow control port %d\n", __func__, - port->number); + dev_dbg(&port->dev, "%s - disabling HW flow control port %d\n", __func__, port->number); status = BoxSetHW_FlowCtrl(port->serial, index, 0); if (status < 0) { - dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); + dev_dbg(&port->dev, "BoxSetHW_FlowCtrl failed\n"); return; } @@ -1288,13 +1268,13 @@ static void qt_set_termios(struct tty_struct *tty, BoxSetSW_FlowCtrl(port->serial, index, stop_char, start_char); if (status < 0) - dbg(__FILE__ "BoxSetSW_FlowCtrl (enabled) failed\n"); + dev_dbg(&port->dev, "BoxSetSW_FlowCtrl (enabled) failed\n"); } else { /* disable SW flow control */ status = BoxDisable_SW_FlowCtrl(port->serial, index); if (status < 0) - dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); + dev_dbg(&port->dev, "BoxSetSW_FlowCtrl (diabling) failed\n"); } termios->c_cflag &= ~CMSPAR; @@ -1471,10 +1451,10 @@ static void qt_unthrottle(struct tty_struct *tty) mutex_lock(&qt_port->lock); if (qt_port->RxHolding == 1) { - dbg("%s -qt_port->RxHolding == 1\n", __func__); + dev_dbg(&port->dev, "%s -qt_port->RxHolding == 1\n", __func__); qt_port->RxHolding = 0; - dbg("%s - qt_port->RxHolding = 0\n", __func__); + dev_dbg(&port->dev, "%s - qt_port->RxHolding = 0\n", __func__); /* if we have a bulk endpoint, start it up */ if ((serial->num_bulk_in) && (qt_port->ReadBulkStopped == 1)) { @@ -1500,11 +1480,6 @@ static int qt_calc_num_ports(struct usb_serial *serial) { int num_ports; - dbg("numberofendpoints: %d\n", - (int)serial->interface->cur_altsetting->desc.bNumEndpoints); - dbg("numberofendpoints: %d\n", - (int)serial->interface->altsetting->desc.bNumEndpoints); - num_ports = (serial->interface->cur_altsetting->desc.bNumEndpoints - 1) / 2; @@ -1545,6 +1520,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 8919842..57f11f9 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -161,8 +161,7 @@ static void usbip_dump_usb_device(struct usb_device *udev) dev_dbg(dev, "have_langid %d, string_langid %d\n", udev->have_langid, udev->string_langid); - dev_dbg(dev, "maxchild %d, children %p\n", - udev->maxchild, udev->children); + dev_dbg(dev, "maxchild %d\n", udev->maxchild); } static void usbip_dump_request_type(__u8 rt) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7065df6..2564b54 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -48,6 +48,7 @@ config USB_ARCH_HAS_EHCI default y if SPARC_LEON default y if ARCH_MMP default y if MACH_LOONGSON1 + default y if PLAT_ORION default PCI # some non-PCI HCDs implement xHCI diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index d7e422d..e1f8b2c 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -307,6 +307,34 @@ enum { #define FW_GET_BYTE(p) (*((__u8 *) (p))) #define FW_DIR "ueagle-atm/" +#define EAGLE_FIRMWARE FW_DIR "eagle.fw" +#define ADI930_FIRMWARE FW_DIR "adi930.fw" +#define EAGLE_I_FIRMWARE FW_DIR "eagleI.fw" +#define EAGLE_II_FIRMWARE FW_DIR "eagleII.fw" +#define EAGLE_III_FIRMWARE FW_DIR "eagleIII.fw" +#define EAGLE_IV_FIRMWARE FW_DIR "eagleIV.fw" + +#define DSP4I_FIRMWARE FW_DIR "DSP4i.bin" +#define DSP4P_FIRMWARE FW_DIR "DSP4p.bin" +#define DSP9I_FIRMWARE FW_DIR "DSP9i.bin" +#define DSP9P_FIRMWARE FW_DIR "DSP9p.bin" +#define DSPEI_FIRMWARE FW_DIR "DSPei.bin" +#define DSPEP_FIRMWARE FW_DIR "DSPep.bin" +#define FPGA930_FIRMWARE FW_DIR "930-fpga.bin" + +#define CMV4P_FIRMWARE FW_DIR "CMV4p.bin" +#define CMV4PV2_FIRMWARE FW_DIR "CMV4p.bin.v2" +#define CMV4I_FIRMWARE FW_DIR "CMV4i.bin" +#define CMV4IV2_FIRMWARE FW_DIR "CMV4i.bin.v2" +#define CMV9P_FIRMWARE FW_DIR "CMV9p.bin" +#define CMV9PV2_FIRMWARE FW_DIR "CMV9p.bin.v2" +#define CMV9I_FIRMWARE FW_DIR "CMV9i.bin" +#define CMV9IV2_FIRMWARE FW_DIR "CMV9i.bin.v2" +#define CMVEP_FIRMWARE FW_DIR "CMVep.bin" +#define CMVEPV2_FIRMWARE FW_DIR "CMVep.bin.v2" +#define CMVEI_FIRMWARE FW_DIR "CMVei.bin" +#define CMVEIV2_FIRMWARE FW_DIR "CMVei.bin.v2" + #define UEA_FW_NAME_MAX 30 #define NB_MODEM 4 @@ -694,26 +722,26 @@ err: static int uea_load_firmware(struct usb_device *usb, unsigned int ver) { int ret; - char *fw_name = FW_DIR "eagle.fw"; + char *fw_name = EAGLE_FIRMWARE; uea_enters(usb); uea_info(usb, "pre-firmware device, uploading firmware\n"); switch (ver) { case ADI930: - fw_name = FW_DIR "adi930.fw"; + fw_name = ADI930_FIRMWARE; break; case EAGLE_I: - fw_name = FW_DIR "eagleI.fw"; + fw_name = EAGLE_I_FIRMWARE; break; case EAGLE_II: - fw_name = FW_DIR "eagleII.fw"; + fw_name = EAGLE_II_FIRMWARE; break; case EAGLE_III: - fw_name = FW_DIR "eagleIII.fw"; + fw_name = EAGLE_III_FIRMWARE; break; case EAGLE_IV: - fw_name = FW_DIR "eagleIV.fw"; + fw_name = EAGLE_IV_FIRMWARE; break; } @@ -869,19 +897,19 @@ static int request_dsp(struct uea_softc *sc) if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSP4i.bin"; + dsp_name = DSP4I_FIRMWARE; else - dsp_name = FW_DIR "DSP4p.bin"; + dsp_name = DSP4P_FIRMWARE; } else if (UEA_CHIP_VERSION(sc) == ADI930) { if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSP9i.bin"; + dsp_name = DSP9I_FIRMWARE; else - dsp_name = FW_DIR "DSP9p.bin"; + dsp_name = DSP9P_FIRMWARE; } else { if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSPei.bin"; + dsp_name = DSPEI_FIRMWARE; else - dsp_name = FW_DIR "DSPep.bin"; + dsp_name = DSPEP_FIRMWARE; } ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev); @@ -1925,7 +1953,7 @@ static int load_XILINX_firmware(struct uea_softc *sc) int ret, size, u, ln; const u8 *pfw; u8 value; - char *fw_name = FW_DIR "930-fpga.bin"; + char *fw_name = FPGA930_FIRMWARE; uea_enters(INS_TO_USBDEV(sc)); @@ -2753,3 +2781,28 @@ module_usb_driver(uea_driver); MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka"); MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver"); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_FIRMWARE(EAGLE_FIRMWARE); +MODULE_FIRMWARE(ADI930_FIRMWARE); +MODULE_FIRMWARE(EAGLE_I_FIRMWARE); +MODULE_FIRMWARE(EAGLE_II_FIRMWARE); +MODULE_FIRMWARE(EAGLE_III_FIRMWARE); +MODULE_FIRMWARE(EAGLE_IV_FIRMWARE); +MODULE_FIRMWARE(DSP4I_FIRMWARE); +MODULE_FIRMWARE(DSP4P_FIRMWARE); +MODULE_FIRMWARE(DSP9I_FIRMWARE); +MODULE_FIRMWARE(DSP9P_FIRMWARE); +MODULE_FIRMWARE(DSPEI_FIRMWARE); +MODULE_FIRMWARE(DSPEP_FIRMWARE); +MODULE_FIRMWARE(FPGA930_FIRMWARE); +MODULE_FIRMWARE(CMV4P_FIRMWARE); +MODULE_FIRMWARE(CMV4PV2_FIRMWARE); +MODULE_FIRMWARE(CMV4I_FIRMWARE); +MODULE_FIRMWARE(CMV4IV2_FIRMWARE); +MODULE_FIRMWARE(CMV9P_FIRMWARE); +MODULE_FIRMWARE(CMV9PV2_FIRMWARE); +MODULE_FIRMWARE(CMV9I_FIRMWARE); +MODULE_FIRMWARE(CMV9IV2_FIRMWARE); +MODULE_FIRMWARE(CMVEP_FIRMWARE); +MODULE_FIRMWARE(CMVEPV2_FIRMWARE); +MODULE_FIRMWARE(CMVEI_FIRMWARE); +MODULE_FIRMWARE(CMVEIV2_FIRMWARE); diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index ee62b35..35f10bf 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -84,7 +84,7 @@ #include <linux/ratelimit.h> #ifdef VERBOSE_DEBUG -static int usbatm_print_packet(const unsigned char *data, int len); +static int usbatm_print_packet(struct usbatm_data *instance, const unsigned char *data, int len); #define PACKETDEBUG(arg...) usbatm_print_packet(arg) #define vdbg(arg...) dev_dbg(arg) #else @@ -230,8 +230,8 @@ static int usbatm_submit_urb(struct urb *urb) struct usbatm_channel *channel = urb->context; int ret; - vdbg("%s: submitting urb 0x%p, size %u", - __func__, urb, urb->transfer_buffer_length); + /* vdbg("%s: submitting urb 0x%p, size %u", + __func__, urb, urb->transfer_buffer_length); */ ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { @@ -261,8 +261,8 @@ static void usbatm_complete(struct urb *urb) unsigned long flags; int status = urb->status; - vdbg("%s: urb 0x%p, status %d, actual_length %d", - __func__, urb, status, urb->actual_length); + /* vdbg("%s: urb 0x%p, status %d, actual_length %d", + __func__, urb, status, urb->actual_length); */ /* usually in_interrupt(), but not always */ spin_lock_irqsave(&channel->lock, flags); @@ -311,7 +311,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4); u8 pti = ((source[3] & 0xe) >> 1); - vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); + vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) { instance->cached_vpi = vpi; @@ -381,7 +381,9 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char goto out; } - vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc); + vdbg(&instance->usb_intf->dev, + "%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", + __func__, length, pdu_length, vcc); if (!(skb = dev_alloc_skb(length))) { if (printk_ratelimit()) @@ -391,7 +393,9 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char goto out; } - vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize); + vdbg(&instance->usb_intf->dev, + "%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", + __func__, skb, skb->truesize); if (!atm_charge(vcc, skb->truesize)) { atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", @@ -405,10 +409,11 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char length); __skb_put(skb, length); - vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u", + vdbg(&instance->usb_intf->dev, + "%s: sending skb 0x%p, skb->len %u, skb->truesize %u", __func__, skb, skb->len, skb->truesize); - PACKETDEBUG(skb->data, skb->len); + PACKETDEBUG(instance, skb->data, skb->len); vcc->push(vcc, skb); @@ -474,7 +479,8 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance, unsigned int bytes_written; unsigned int stride = instance->tx_channel.stride; - vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space); + vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u", + __func__, skb->len, avail_space); UDSL_ASSERT(instance, !(avail_space % stride)); for (bytes_written = 0; bytes_written < avail_space && ctrl->len; @@ -534,7 +540,8 @@ static void usbatm_rx_process(unsigned long data) struct urb *urb; while ((urb = usbatm_pop_urb(&instance->rx_channel))) { - vdbg("%s: processing urb 0x%p", __func__, urb); + vdbg(&instance->usb_intf->dev, + "%s: processing urb 0x%p", __func__, urb); if (usb_pipeisoc(urb->pipe)) { unsigned char *merge_start = NULL; @@ -608,7 +615,8 @@ static void usbatm_tx_process(unsigned long data) buffer + bytes_written, buf_size - bytes_written); - vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p", + vdbg(&instance->usb_intf->dev, + "%s: wrote %u bytes from skb 0x%p to urb 0x%p", __func__, bytes_written, skb, urb); if (!UDSL_SKB(skb)->len) { @@ -664,7 +672,8 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct usbatm_control *ctrl = UDSL_SKB(skb); int err; - vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); + vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__, + skb, skb->len); /* racy disconnection check - fine */ if (!instance || instance->disconnected) { @@ -688,7 +697,7 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) goto fail; } - PACKETDEBUG(skb->data, skb->len); + PACKETDEBUG(instance, skb->data, skb->len); /* initialize the control block */ ctrl->atm.vcc = vcc; @@ -1202,7 +1211,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, if (i >= num_rcv_urbs) list_add_tail(&urb->urb_list, &channel->list); - vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p", + vdbg(&intf->dev, "%s: alloced buffer 0x%p buf size %u urb 0x%p", __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); } @@ -1359,7 +1368,8 @@ MODULE_VERSION(DRIVER_VERSION); ************/ #ifdef VERBOSE_DEBUG -static int usbatm_print_packet(const unsigned char *data, int len) +static int usbatm_print_packet(struct usbatm_data *instance, + const unsigned char *data, int len) { unsigned char buffer[256]; int i = 0, j = 0; @@ -1369,7 +1379,7 @@ static int usbatm_print_packet(const unsigned char *data, int len) sprintf(buffer, "%.3d :", i); for (j = 0; (j < 16) && (i < len); j++, i++) sprintf(buffer, "%s %2.2x", buffer, data[i]); - dbg("%s", buffer); + dev_dbg(&instance->usb_intf->dev, "%s", buffer); } return i; } diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 47e499c..1ea932a 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -13,7 +13,6 @@ if USB_CHIPIDEA config USB_CHIPIDEA_UDC bool "ChipIdea device controller" depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA - select USB_GADGET_DUALSPEED help Say Y here to enable device controller functionality of the ChipIdea driver. diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 5c66d9c..d92ca32 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -1,3 +1,5 @@ +ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG + obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o ci_hdrc-y := core.o @@ -15,5 +17,5 @@ ifneq ($(CONFIG_PCI),) endif ifneq ($(CONFIG_OF_DEVICE),) - obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o endif diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index d738603..e25d126 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -139,6 +139,7 @@ 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; diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c index ef60d06..0f5ca4b 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.c +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -20,8 +20,10 @@ #include <linux/usb/chipidea.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h> #include "ci.h" +#include "ci13xxx_imx.h" #define pdev_to_phy(pdev) \ ((struct usb_phy *)platform_get_drvdata(pdev)) @@ -34,6 +36,55 @@ struct ci13xxx_imx_data { struct regulator *reg_vbus; }; +static const struct usbmisc_ops *usbmisc_ops; + +/* Common functions shared by usbmisc drivers */ + +int usbmisc_set_ops(const struct usbmisc_ops *ops) +{ + if (usbmisc_ops) + return -EBUSY; + + usbmisc_ops = ops; + + return 0; +} +EXPORT_SYMBOL_GPL(usbmisc_set_ops); + +void usbmisc_unset_ops(const struct usbmisc_ops *ops) +{ + usbmisc_ops = NULL; +} +EXPORT_SYMBOL_GPL(usbmisc_unset_ops); + +int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) +{ + struct device_node *np = dev->of_node; + struct of_phandle_args args; + int ret; + + usbdev->dev = dev; + + ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", + 0, &args); + if (ret) { + dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", + ret); + memset(usbdev, 0, sizeof(*usbdev)); + return ret; + } + usbdev->index = args.args[0]; + of_node_put(args.np); + + if (of_find_property(np, "disable-over-current", NULL)) + usbdev->disable_oc = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(usbmisc_get_init_data); + +/* End of common functions shared by usbmisc drivers*/ + static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = { .name = "ci13xxx_imx", .flags = CI13XXX_REQUIRE_TRANSCEIVER | @@ -49,8 +100,13 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) struct device_node *phy_np; struct resource *res; struct regulator *reg_vbus; + struct pinctrl *pinctrl; int ret; + if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL) + && !usbmisc_ops) + return -EPROBE_DEFER; + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n"); @@ -63,6 +119,11 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) return -ENOENT; } + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "pinctrl get/select failed, err=%ld\n", + PTR_ERR(pinctrl)); + data->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(data->clk)) { dev_err(&pdev->dev, @@ -120,6 +181,16 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) *pdev->dev.dma_mask = DMA_BIT_MASK(32); dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask); } + + if (usbmisc_ops && usbmisc_ops->init) { + ret = usbmisc_ops->init(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "usbmisc init failed, ret=%d\n", ret); + goto err; + } + } + plat_ci = ci13xxx_add_device(&pdev->dev, pdev->resource, pdev->num_resources, &ci13xxx_imx_platdata); diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h new file mode 100644 index 0000000..2e88acc --- /dev/null +++ b/drivers/usb/chipidea/ci13xxx_imx.h @@ -0,0 +1,28 @@ +/* + * 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 + */ + +/* Used to set SoC specific callbacks */ +struct usbmisc_ops { + /* It's called once when probe a usb device */ + int (*init)(struct device *dev); +}; + +struct usbmisc_usb_device { + struct device *dev; /* usb controller device */ + int index; + + int disable_oc:1; /* over current detect disabled */ +}; + +int usbmisc_set_ops(const struct usbmisc_ops *ops); +void usbmisc_unset_ops(const struct usbmisc_ops *ops); +int +usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 1083585..f69d029 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -273,14 +273,13 @@ static void ci_role_work(struct work_struct *work) struct ci13xxx *ci = container_of(work, struct ci13xxx, work); enum ci_role role = ci_otg_role(ci); - hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); - if (role != ci->role) { dev_dbg(ci->dev, "switching from %s to %s\n", ci_role(ci)->name, ci->roles[role]->name); ci_role_stop(ci); ci_role_start(ci, role); + enable_irq(ci->irq); } } @@ -320,17 +319,22 @@ static irqreturn_t ci_irq(int irq, void *data) { struct ci13xxx *ci = data; irqreturn_t ret = IRQ_NONE; + u32 otgsc = 0; + + if (ci->is_otg) + otgsc = hw_read(ci, OP_OTGSC, ~0); - if (ci->is_otg) { - u32 sts = hw_read(ci, OP_OTGSC, ~0); + if (ci->role != CI_ROLE_END) + ret = ci_role(ci)->irq(ci); - if (sts & OTGSC_IDIS) { - queue_work(ci->wq, &ci->work); - ret = IRQ_HANDLED; - } + if (ci->is_otg && (otgsc & OTGSC_IDIS)) { + hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + disable_irq_nosync(ci->irq); + queue_work(ci->wq, &ci->work); + ret = IRQ_HANDLED; } - return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci); + return ret; } static DEFINE_IDA(ci_ida); @@ -462,6 +466,8 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev) if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { ci->is_otg = true; + /* ID pin needs 1ms debouce time, we delay 2ms for safe */ + mdelay(2); ci->role = ci_otg_role(ci); } else { ci->role = ci->roles[CI_ROLE_HOST] diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d214448..2f45bba 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -305,6 +305,18 @@ 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) @@ -371,6 +383,16 @@ 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 *****************************************************************************/ @@ -1370,6 +1392,7 @@ 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); @@ -1544,8 +1567,10 @@ 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; @@ -1651,6 +1676,13 @@ 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; @@ -1726,6 +1758,7 @@ 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); @@ -1788,6 +1821,9 @@ 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); @@ -1828,6 +1864,7 @@ 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; } diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c new file mode 100644 index 0000000..416e3fc --- /dev/null +++ b/drivers/usb/chipidea/usbmisc_imx6q.c @@ -0,0 +1,162 @@ +/* + * 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 __devinit 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_request_and_ioremap(&pdev->dev, res); + if (!data->base) + return -EADDRNOTAVAIL; + + 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 __devexit 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 = __devexit_p(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>"); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ff7b5a8..36f2be4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -39,7 +39,6 @@ #include <linux/serial.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> -#include <linux/serial.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/uaccess.h> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 9981984..f70c1a1 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -56,7 +56,7 @@ config USB_SUSPEND config USB_OTG bool "OTG support" - depends on USB && EXPERIMENTAL + depends on USB depends on USB_SUSPEND default n help diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index f4bdd0c..7199adc 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -702,6 +702,8 @@ int usb_get_configuration(struct usb_device *dev) if (result < 0) { dev_err(ddev, "unable to read config index %d " "descriptor/%s: %d\n", cfgno, "start", result); + if (result != -EPIPE) + goto err; dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 3440812..f460de3 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -496,6 +496,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, char *pages_start, *data_end, *speed; unsigned int length; ssize_t total_written = 0; + struct usb_device *childdev = NULL; /* don't bother with anything else if we're not writing any data */ if (*nbytes <= 0) @@ -589,14 +590,12 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, free_pages((unsigned long)pages_start, 1); /* Now look at all of this device's children. */ - for (chix = 0; chix < usbdev->maxchild; chix++) { - struct usb_device *childdev = usbdev->children[chix]; - + usb_hub_for_each_child(usbdev, chix, childdev) { if (childdev) { usb_lock_device(childdev); ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev, bus, - level + 1, chix, ++cnt); + level + 1, chix - 1, ++cnt); usb_unlock_device(childdev); if (ret == -EFAULT) return total_written; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ebb8a9d..e0356cb 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1928,6 +1928,38 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg) return 0; } +static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_disconnect_claim dc; + struct usb_interface *intf; + + if (copy_from_user(&dc, arg, sizeof(dc))) + return -EFAULT; + + intf = usb_ifnum_to_if(ps->dev, dc.interface); + if (!intf) + return -EINVAL; + + if (intf->dev.driver) { + struct usb_driver *driver = to_usb_driver(intf->dev.driver); + + if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) && + strncmp(dc.driver, intf->dev.driver->name, + sizeof(dc.driver)) != 0) + return -EBUSY; + + if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) && + strncmp(dc.driver, intf->dev.driver->name, + sizeof(dc.driver)) == 0) + return -EBUSY; + + dev_dbg(&intf->dev, "disconnect by usbfs\n"); + usb_driver_release_interface(driver, intf); + } + + return claimintf(ps, dc.interface); +} + /* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from @@ -2101,6 +2133,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, case USBDEVFS_GET_CAPABILITIES: ret = proc_get_capabilities(ps, p); break; + case USBDEVFS_DISCONNECT_CLAIM: + ret = proc_disconnect_claim(ps, p); + break; } usb_unlock_device(dev); if (ret >= 0) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 445455a..ddd820d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -125,10 +125,9 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) { struct usb_dynid *dynid, *n; struct usb_driver *usb_driver = to_usb_driver(driver); - u32 idVendor = 0; - u32 idProduct = 0; - int fields = 0; - int retval = 0; + u32 idVendor; + u32 idProduct; + int fields; fields = sscanf(buf, "%x %x", &idVendor, &idProduct); if (fields < 2) @@ -141,14 +140,10 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) (id->idProduct == idProduct)) { list_del(&dynid->node); kfree(dynid); - retval = 0; break; } } spin_unlock(&usb_driver->dynids.lock); - - if (retval) - return retval; return count; } static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id); diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index db7fe50..68cc653 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -24,10 +24,6 @@ struct ep_device { #define to_ep_device(_dev) \ container_of(_dev, struct ep_device, dev) -struct device_type usb_ep_device_type = { - .name = "usb_endpoint", -}; - struct ep_attribute { struct attribute attr; ssize_t (*show)(struct usb_device *, @@ -172,6 +168,11 @@ static void ep_device_release(struct device *dev) kfree(ep_dev); } +struct device_type usb_ep_device_type = { + .name = "usb_endpoint", + .release = ep_device_release, +}; + int usb_create_ep_devs(struct device *parent, struct usb_host_endpoint *endpoint, struct usb_device *udev) @@ -190,7 +191,6 @@ int usb_create_ep_devs(struct device *parent, ep_dev->dev.groups = ep_dev_groups; ep_dev->dev.type = &usb_ep_device_type; ep_dev->dev.parent = parent; - ep_dev->dev.release = ep_device_release; dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); retval = device_register(&ep_dev->dev); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 75ba209..1e741bc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -22,6 +22,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/bcd.h> #include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> @@ -123,9 +124,8 @@ static inline int is_root_hub(struct usb_device *udev) */ /*-------------------------------------------------------------------------*/ - -#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) -#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) +#define KERNEL_REL bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff)) +#define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff)) /* usb 3.0 root hub device descriptor */ static const u8 usb3_rh_dev_descriptor[18] = { @@ -2151,15 +2151,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; - unsigned long flags; irqreturn_t rc; - /* IRQF_DISABLED doesn't work correctly with shared IRQs - * when the first handler doesn't use it. So let's just - * assume it's never used. - */ - local_irq_save(flags); - if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2167,7 +2160,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) else rc = IRQ_HANDLED; - local_irq_restore(flags); return rc; } EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2355,14 +2347,6 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, int retval; if (hcd->driver->irq) { - - /* IRQF_DISABLED doesn't work as advertised when used together - * with IRQF_SHARED. As usb_hcd_irq() will always disable - * interrupts we can remove it here. - */ - if (irqflags & IRQF_SHARED) - irqflags &= ~IRQF_DISABLED; - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); retval = request_irq(irqnum, &usb_hcd_irq, irqflags, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 128a804..673ee46 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -39,6 +39,13 @@ #endif #endif +struct usb_port { + struct usb_device *child; + struct device dev; + struct dev_state *port_owner; + enum usb_port_connect_type connect_type; +}; + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -83,7 +90,7 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; - struct dev_state **port_owners; + struct usb_port **ports; }; static inline int hub_is_superspeed(struct usb_device *hdev) @@ -156,6 +163,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 +#define to_usb_port(_dev) \ + container_of(_dev, struct usb_port, dev) static int usb_reset_and_verify_device(struct usb_device *udev); @@ -174,7 +183,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus) /* Note that hdev or one of its children must be locked! */ static struct usb_hub *hdev_to_hub(struct usb_device *hdev) { - if (!hdev || !hdev->actconfig) + if (!hdev || !hdev->actconfig || !hdev->maxchild) return NULL; return usb_get_intfdata(hdev->actconfig->interface[0]); } @@ -869,8 +878,8 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) struct usb_device *hdev = hub->hdev; int ret = 0; - if (hdev->children[port1-1] && set_state) - usb_set_device_state(hdev->children[port1-1], + if (hub->ports[port1 - 1]->child && set_state) + usb_set_device_state(hub->ports[port1 - 1]->child, USB_STATE_NOTATTACHED); if (!hub->error && !hub_is_superspeed(hub->hdev)) ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); @@ -1026,7 +1035,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * which ports need attention. */ for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hdev->children[port1-1]; + struct usb_device *udev = hub->ports[port1 - 1]->child; u16 portstatus, portchange; portstatus = portchange = 0; @@ -1191,8 +1200,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) if (type != HUB_SUSPEND) { /* Disconnect all the children */ for (i = 0; i < hdev->maxchild; ++i) { - if (hdev->children[i]) - usb_disconnect(&hdev->children[i]); + if (hub->ports[i]->child) + usb_disconnect(&hub->ports[i]->child); } } @@ -1222,6 +1231,52 @@ static int hub_post_reset(struct usb_interface *intf) return 0; } +static void usb_port_device_release(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + + kfree(port_dev); +} + +static void usb_hub_remove_port_device(struct usb_hub *hub, + int port1) +{ + device_unregister(&hub->ports[port1 - 1]->dev); +} + +struct device_type usb_port_device_type = { + .name = "usb_port", + .release = usb_port_device_release, +}; + +static int usb_hub_create_port_device(struct usb_hub *hub, + int port1) +{ + struct usb_port *port_dev = NULL; + int retval; + + port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); + if (!port_dev) { + retval = -ENOMEM; + goto exit; + } + + hub->ports[port1 - 1] = port_dev; + port_dev->dev.parent = hub->intfdev; + port_dev->dev.type = &usb_port_device_type; + dev_set_name(&port_dev->dev, "port%d", port1); + + retval = device_register(&port_dev->dev); + if (retval) + goto error_register; + return 0; + +error_register: + put_device(&port_dev->dev); +exit: + return retval; +} + static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { @@ -1231,7 +1286,7 @@ static int hub_configure(struct usb_hub *hub, u16 hubstatus, hubchange; u16 wHubCharacteristics; unsigned int pipe; - int maxp, ret; + int maxp, ret, i; char *message = "out of memory"; hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); @@ -1271,11 +1326,9 @@ static int hub_configure(struct usb_hub *hub, dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, (hdev->maxchild == 1) ? "" : "s"); - hdev->children = kzalloc(hdev->maxchild * - sizeof(struct usb_device *), GFP_KERNEL); - hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *), - GFP_KERNEL); - if (!hdev->children || !hub->port_owners) { + hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), + GFP_KERNEL); + if (!hub->ports) { ret = -ENOMEM; goto fail; } @@ -1484,6 +1537,11 @@ static int hub_configure(struct usb_hub *hub, if (hub->has_indicators && blinkenlights) hub->indicator [0] = INDICATOR_CYCLE; + for (i = 0; i < hdev->maxchild; i++) + if (usb_hub_create_port_device(hub, i + 1) < 0) + dev_err(hub->intfdev, + "couldn't create port%d device.\n", i + 1); + hub_activate(hub, HUB_INIT); return 0; @@ -1508,6 +1566,7 @@ static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = interface_to_usbdev(intf); + int i; /* Take the hub off the event list and don't let it be added again */ spin_lock_irq(&hub_event_lock); @@ -1523,14 +1582,16 @@ static void hub_disconnect(struct usb_interface *intf) hub_quiesce(hub, HUB_DISCONNECT); usb_set_intfdata (intf, NULL); + + for (i = 0; i < hdev->maxchild; i++) + usb_hub_remove_port_device(hub, i + 1); hub->hdev->maxchild = 0; if (hub->hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; usb_free_urb(hub->urb); - kfree(hdev->children); - kfree(hub->port_owners); + kfree(hub->ports); kfree(hub->descriptor); kfree(hub->status); kfree(hub->buffer); @@ -1617,6 +1678,7 @@ static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { struct usb_device *hdev = interface_to_usbdev (intf); + struct usb_hub *hub = hdev_to_hub(hdev); /* assert ifno == 0 (part of hub spec) */ switch (code) { @@ -1630,11 +1692,11 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) else { info->nports = hdev->maxchild; for (i = 0; i < info->nports; i++) { - if (hdev->children[i] == NULL) + if (hub->ports[i]->child == NULL) info->port[i] = 0; else info->port[i] = - hdev->children[i]->devnum; + hub->ports[i]->child->devnum; } } spin_unlock_irq(&device_state_lock); @@ -1662,7 +1724,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1, /* This assumes that devices not managed by the hub driver * will always have maxchild equal to 0. */ - *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); + *ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner); return 0; } @@ -1699,16 +1761,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) { + struct usb_hub *hub = hdev_to_hub(hdev); int n; - struct dev_state **powner; - n = find_port_owner(hdev, 1, &powner); - if (n == 0) { - for (; n < hdev->maxchild; (++n, ++powner)) { - if (*powner == owner) - *powner = NULL; - } + for (n = 0; n < hdev->maxchild; n++) { + if (hub->ports[n]->port_owner == owner) + hub->ports[n]->port_owner = NULL; } + } /* The caller must hold udev's lock */ @@ -1719,17 +1779,17 @@ bool usb_device_is_owned(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) return false; hub = hdev_to_hub(udev->parent); - return !!hub->port_owners[udev->portnum - 1]; + return !!hub->ports[udev->portnum - 1]->port_owner; } - static void recursively_mark_NOTATTACHED(struct usb_device *udev) { + struct usb_hub *hub = hdev_to_hub(udev); int i; for (i = 0; i < udev->maxchild; ++i) { - if (udev->children[i]) - recursively_mark_NOTATTACHED(udev->children[i]); + if (hub->ports[i]->child) + recursively_mark_NOTATTACHED(hub->ports[i]->child); } if (udev->state == USB_STATE_SUSPENDED) udev->active_duration -= jiffies; @@ -1893,6 +1953,7 @@ static void hub_free_dev(struct usb_device *udev) void usb_disconnect(struct usb_device **pdev) { struct usb_device *udev = *pdev; + struct usb_hub *hub = hdev_to_hub(udev); int i; /* mark the device as inactive, so any further urb submissions for @@ -1907,8 +1968,8 @@ void usb_disconnect(struct usb_device **pdev) /* Free up all the children before we remove this device */ for (i = 0; i < udev->maxchild; i++) { - if (udev->children[i]) - usb_disconnect(&udev->children[i]); + if (hub->ports[i]->child) + usb_disconnect(&hub->ports[i]->child); } /* deallocate hcd/hardware state ... nuking all pending urbs and @@ -2113,7 +2174,8 @@ static void set_usb_port_removable(struct usb_device *udev) return; if (hub_is_superspeed(hdev)) { - if (hub->descriptor->u.ss.DeviceRemovable & (1 << port)) + if (le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable) + & (1 << port)) removable = false; } else { if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8))) @@ -3072,7 +3134,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; - udev = hdev->children [port1-1]; + udev = hub->ports[port1 - 1]->child; if (udev && udev->can_submit) { dev_warn(&intf->dev, "port %d nyet suspended\n", port1); if (PMSG_IS_AUTO(msg)) @@ -3999,7 +4061,7 @@ hub_power_remaining (struct usb_hub *hub) remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent; for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hdev->children[port1 - 1]; + struct usb_device *udev = hub->ports[port1 - 1]->child; int delta; if (!udev) @@ -4063,7 +4125,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, #endif /* Try to resuscitate an existing device */ - udev = hdev->children[port1-1]; + udev = hub->ports[port1 - 1]->child; if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && udev->state != USB_STATE_NOTATTACHED) { usb_lock_device(udev); @@ -4092,7 +4154,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, /* Disconnect any existing devices under this port */ if (udev) - usb_disconnect(&hdev->children[port1-1]); + usb_disconnect(&hub->ports[port1 - 1]->child); clear_bit(port1, hub->change_bits); /* We can forget about a "removed" device when there's a physical @@ -4228,7 +4290,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hdev->state == USB_STATE_NOTATTACHED) status = -ENOTCONN; else - hdev->children[port1-1] = udev; + hub->ports[port1 - 1]->child = udev; spin_unlock_irq(&device_state_lock); /* Run it through the hoops (find a driver, etc) */ @@ -4236,7 +4298,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = usb_new_device(udev); if (status) { spin_lock_irq(&device_state_lock); - hdev->children[port1-1] = NULL; + hub->ports[port1 - 1]->child = NULL; spin_unlock_irq(&device_state_lock); } } @@ -4282,7 +4344,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, int ret; hdev = hub->hdev; - udev = hdev->children[port-1]; + udev = hub->ports[port - 1]->child; if (!hub_is_superspeed(hdev)) { if (!(portchange & USB_PORT_STAT_C_SUSPEND)) return 0; @@ -4436,7 +4498,7 @@ static void hub_events(void) */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change - && hdev->children[i-1]) { + && hub->ports[i - 1]->child) { dev_err (hub_dev, "port %i " "disabled by hub (EMI?), " @@ -4993,3 +5055,75 @@ void usb_queue_reset_device(struct usb_interface *iface) schedule_work(&iface->reset_ws); } EXPORT_SYMBOL_GPL(usb_queue_reset_device); + +/** + * usb_hub_find_child - Get the pointer of child device + * attached to the port which is specified by @port1. + * @hdev: USB device belonging to the usb hub + * @port1: port num to indicate which port the child device + * is attached to. + * + * USB drivers call this function to get hub's child device + * pointer. + * + * Return NULL if input param is invalid and + * child's usb_device pointer if non-NULL. + */ +struct usb_device *usb_hub_find_child(struct usb_device *hdev, + int port1) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + if (port1 < 1 || port1 > hdev->maxchild) + return NULL; + return hub->ports[port1 - 1]->child; +} +EXPORT_SYMBOL_GPL(usb_hub_find_child); + +/** + * usb_set_hub_port_connect_type - set hub port connect type. + * @hdev: USB device belonging to the usb hub + * @port1: port num of the port + * @type: connect type of the port + */ +void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, + enum usb_port_connect_type type) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + hub->ports[port1 - 1]->connect_type = type; +} + +/** + * usb_get_hub_port_connect_type - Get the port's connect type + * @hdev: USB device belonging to the usb hub + * @port1: port num of the port + * + * Return connect type of the port and if input params are + * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN. + */ +enum usb_port_connect_type +usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + return hub->ports[port1 - 1]->connect_type; +} + +#ifdef CONFIG_ACPI +/** + * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle + * @hdev: USB device belonging to the usb hub + * @port1: port num of the port + * + * Return port's acpi handle if successful, NULL if params are + * invaild. + */ +acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, + int port1) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev); +} +#endif diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0ab7da2..1ed5afd 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -146,8 +146,6 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(size); - /* dbg("usb_control_msg"); */ - ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); kfree(dr); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index e77a8e8..fdefd9c 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -209,7 +209,7 @@ void usb_detect_quirks(struct usb_device *udev) * for all devices. It will affect things like hub resets * and EMF-related port disables. */ - if (!(udev->quirks & USB_QUIRK_RESET_MORPHS)) + if (!(udev->quirks & USB_QUIRK_RESET)) udev->persist_enabled = 1; #endif /* CONFIG_PM */ } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 682e825..818e4a0 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -196,7 +196,7 @@ show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char * struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS)); + return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET)); } static ssize_t @@ -204,15 +204,15 @@ set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int config; + int val; - if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1) + if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1) return -EINVAL; usb_lock_device(udev); - if (config) - udev->quirks |= USB_QUIRK_RESET_MORPHS; + if (val) + udev->quirks |= USB_QUIRK_RESET; else - udev->quirks &= ~USB_QUIRK_RESET_MORPHS; + udev->quirks &= ~USB_QUIRK_RESET; usb_unlock_device(udev); return count; } diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 8947b20..0ef7d42 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -19,20 +19,91 @@ #include "usb.h" -static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle) +/** + * usb_acpi_power_manageable - check whether usb port has + * acpi power resource. + * @hdev: USB device belonging to the usb hub + * @index: port index based zero + * + * Return true if the port has acpi power resource and false if no. + */ +bool usb_acpi_power_manageable(struct usb_device *hdev, int index) +{ + acpi_handle port_handle; + int port1 = index + 1; + + port_handle = usb_get_hub_port_acpi_handle(hdev, + port1); + if (port_handle) + return acpi_bus_power_manageable(port_handle); + else + return false; +} +EXPORT_SYMBOL_GPL(usb_acpi_power_manageable); + +/** + * usb_acpi_set_power_state - control usb port's power via acpi power + * resource + * @hdev: USB device belonging to the usb hub + * @index: port index based zero + * @enable: power state expected to be set + * + * Notice to use usb_acpi_power_manageable() to check whether the usb port + * has acpi power resource before invoking this function. + * + * Returns 0 on success, else negative errno. + */ +int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) +{ + acpi_handle port_handle; + unsigned char state; + int port1 = index + 1; + int error = -EINVAL; + + port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev, + port1); + if (!port_handle) + return error; + + if (enable) + state = ACPI_STATE_D0; + else + state = ACPI_STATE_D3_COLD; + + error = acpi_bus_set_power(port_handle, state); + if (!error) + dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n", + port1, enable); + else + dev_dbg(&hdev->dev, "The power of hub port failed to be set\n"); + + return error; +} +EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); + +static int usb_acpi_check_port_connect_type(struct usb_device *hdev, + acpi_handle handle, int port1) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *upc; + struct acpi_pld pld; int ret = 0; - status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); - + /* + * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is + * user visible and _UPC indicates whether it is connectable. If + * the port was visible and connectable, it could be freely connected + * and disconnected with USB devices. If no visible and connectable, + * a usb device is directly hard-wired to the port. If no visible and + * no connectable, the port would be not used. + */ + status = acpi_get_physical_device_location(handle, &pld); if (ACPI_FAILURE(status)) return -ENODEV; + status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); upc = buffer.pointer; - if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) { ret = -EINVAL; @@ -40,69 +111,107 @@ static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle) } if (upc->package.elements[0].integer.value) - udev->removable = USB_DEVICE_REMOVABLE; - else - udev->removable = USB_DEVICE_FIXED; + if (pld.user_visible) + usb_set_hub_port_connect_type(hdev, port1, + USB_PORT_CONNECT_TYPE_HOT_PLUG); + else + usb_set_hub_port_connect_type(hdev, port1, + USB_PORT_CONNECT_TYPE_HARD_WIRED); + else if (!pld.user_visible) + usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED); out: kfree(upc); return ret; } -static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle) -{ - acpi_status status; - struct acpi_pld pld; - - status = acpi_get_physical_device_location(handle, &pld); - - if (ACPI_FAILURE(status)) - return -ENODEV; - - if (pld.user_visible) - udev->removable = USB_DEVICE_REMOVABLE; - else - udev->removable = USB_DEVICE_FIXED; - - return 0; -} - static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) { struct usb_device *udev; - struct device *parent; acpi_handle *parent_handle; - - if (!is_usb_device(dev)) - return -ENODEV; - - udev = to_usb_device(dev); - parent = dev->parent; - parent_handle = DEVICE_ACPI_HANDLE(parent); - - if (!parent_handle) - return -ENODEV; - - *handle = acpi_get_child(parent_handle, udev->portnum); - - if (!*handle) - return -ENODEV; + int port_num; /* - * PLD will tell us whether a port is removable to the user or - * not. If we don't get an answer from PLD (it's not present - * or it's malformed) then try to infer it from UPC. If a - * device isn't connectable then it's probably not removable. + * In the ACPI DSDT table, only usb root hub and usb ports are + * acpi device nodes. The hierarchy like following. + * Device (EHC1) + * Device (HUBN) + * Device (PR01) + * Device (PR11) + * Device (PR12) + * Device (PR13) + * ... + * So all binding process is divided into two parts. binding + * root hub and usb ports. */ - if (usb_acpi_check_pld(udev, *handle) != 0) - usb_acpi_check_upc(udev, *handle); + if (is_usb_device(dev)) { + udev = to_usb_device(dev); + if (udev->parent) { + enum usb_port_connect_type type; + + /* + * According usb port's connect type to set usb device's + * removability. + */ + type = usb_get_hub_port_connect_type(udev->parent, + udev->portnum); + switch (type) { + case USB_PORT_CONNECT_TYPE_HOT_PLUG: + udev->removable = USB_DEVICE_REMOVABLE; + break; + case USB_PORT_CONNECT_TYPE_HARD_WIRED: + udev->removable = USB_DEVICE_FIXED; + break; + default: + udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN; + break; + } + + return -ENODEV; + } + + /* root hub's parent is the usb hcd. */ + parent_handle = DEVICE_ACPI_HANDLE(dev->parent); + *handle = acpi_get_child(parent_handle, udev->portnum); + if (!*handle) + return -ENODEV; + return 0; + } else if (is_usb_port(dev)) { + sscanf(dev_name(dev), "port%d", &port_num); + /* Get the struct usb_device point of port's hub */ + udev = to_usb_device(dev->parent->parent); + + /* + * The root hub ports' parent is the root hub. The non-root-hub + * ports' parent is the parent hub port which the hub is + * connected to. + */ + if (!udev->parent) { + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), + port_num); + if (!*handle) + return -ENODEV; + } else { + parent_handle = + usb_get_hub_port_acpi_handle(udev->parent, + udev->portnum); + if (!parent_handle) + return -ENODEV; + + *handle = acpi_get_child(parent_handle, port_num); + if (!*handle) + return -ENODEV; + } + usb_acpi_check_port_connect_type(udev, *handle, port_num); + } else + return -ENODEV; return 0; } static struct acpi_bus_type usb_acpi_bus = { .bus = &usb_bus_type, - .find_bridge = NULL, + .find_bridge = usb_acpi_find_device, .find_device = usb_acpi_find_device, }; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index acb103c..1c528c1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,4 +1,5 @@ #include <linux/pm.h> +#include <linux/acpi.h> struct dev_state; @@ -115,6 +116,7 @@ extern struct bus_type usb_bus_type; extern struct device_type usb_device_type; extern struct device_type usb_if_device_type; extern struct device_type usb_ep_device_type; +extern struct device_type usb_port_device_type; extern struct usb_device_driver usb_generic_driver; static inline int is_usb_device(const struct device *dev) @@ -132,6 +134,11 @@ static inline int is_usb_endpoint(const struct device *dev) return dev->type == &usb_ep_device_type; } +static inline int is_usb_port(const struct device *dev) +{ + return dev->type == &usb_port_device_type; +} + /* Do the same for device drivers and interface drivers. */ static inline int is_usb_device_driver(struct device_driver *drv) @@ -162,10 +169,16 @@ extern void usb_notify_add_device(struct usb_device *udev); extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); +extern enum usb_port_connect_type + usb_get_hub_port_connect_type(struct usb_device *hdev, int port1); +extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, + enum usb_port_connect_type type); #ifdef CONFIG_ACPI extern int usb_acpi_register(void); extern void usb_acpi_unregister(void); +extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, + int port1); #else static inline int usb_acpi_register(void) { return 0; }; static inline void usb_acpi_unregister(void) { }; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index d13c60f4..f6a6e07 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -2,8 +2,6 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB && USB_GADGET) select USB_OTG_UTILS - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a68ff53..b415c0c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -50,6 +50,7 @@ #include <linux/dma-mapping.h> #include <linux/of.h> +#include <linux/usb/otg.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -99,6 +100,7 @@ void dwc3_put_device_id(int id) ret = test_bit(id, dwc3_devs); WARN(!ret, "dwc3: ID %d not in use\n", id); + smp_mb__before_clear_bit(); clear_bit(id, dwc3_devs); } EXPORT_SYMBOL_GPL(dwc3_put_device_id); @@ -136,6 +138,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc) reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + usb_phy_init(dwc->usb2_phy); + usb_phy_init(dwc->usb3_phy); mdelay(100); /* Clear USB3 PHY reset */ @@ -464,12 +468,24 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return -ENOMEM; } - regs = devm_ioremap(dev, res->start, resource_size(res)); + regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } + dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR_OR_NULL(dwc->usb2_phy)) { + dev_err(dev, "no usb2 phy configured\n"); + return -EPROBE_DEFER; + } + + dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); + if (IS_ERR_OR_NULL(dwc->usb3_phy)) { + dev_err(dev, "no usb3 phy configured\n"); + return -EPROBE_DEFER; + } + spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 151eca8..243affc 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -457,7 +457,6 @@ enum dwc3_phy { enum dwc3_ep0_next { DWC3_EP0_UNKNOWN = 0, DWC3_EP0_COMPLETE, - DWC3_EP0_NRDY_SETUP, DWC3_EP0_NRDY_DATA, DWC3_EP0_NRDY_STATUS, }; @@ -624,6 +623,8 @@ struct dwc3_scratchpad_array { * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents * @mode: mode of operation + * @usb2_phy: pointer to USB2 PHY + * @usb3_phy: pointer to USB3 PHY * @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 @@ -667,6 +668,9 @@ struct dwc3 { struct usb_gadget gadget; struct usb_gadget_driver *gadget_driver; + struct usb_phy *usb2_phy; + struct usb_phy *usb3_phy; + void __iomem *regs; size_t regs_size; @@ -779,7 +783,6 @@ struct dwc3_event_depevt { #define DEPEVT_STREAMEVT_NOTFOUND 2 /* Control-only Status */ -#define DEPEVT_STATUS_CONTROL_SETUP 0 #define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_STATUS 2 diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index b8f0038..ca65978 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -19,16 +19,74 @@ #include <linux/platform_data/dwc3-exynos.h> #include <linux/dma-mapping.h> #include <linux/clk.h> +#include <linux/usb/otg.h> +#include <linux/usb/nop-usb-xceiv.h> #include "core.h" struct dwc3_exynos { struct platform_device *dwc3; + struct platform_device *usb2_phy; + struct platform_device *usb3_phy; struct device *dev; struct clk *clk; }; +static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos) +{ + 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", 0); + if (!pdev) + return -ENOMEM; + + exynos->usb2_phy = pdev; + pdata.type = USB_PHY_TYPE_USB2; + + ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); + if (ret) + goto err1; + + pdev = platform_device_alloc("nop_usb_xceiv", 1); + if (!pdev) { + ret = -ENOMEM; + goto err1; + } + + exynos->usb3_phy = pdev; + pdata.type = USB_PHY_TYPE_USB3; + + ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata)); + if (ret) + goto err2; + + ret = platform_device_add(exynos->usb2_phy); + if (ret) + goto err2; + + ret = platform_device_add(exynos->usb3_phy); + if (ret) + goto err3; + + return 0; + +err3: + platform_device_del(exynos->usb2_phy); + +err2: + platform_device_put(exynos->usb3_phy); + +err1: + platform_device_put(exynos->usb2_phy); + + return ret; +} + static int __devinit dwc3_exynos_probe(struct platform_device *pdev) { struct dwc3_exynos_data *pdata = pdev->dev.platform_data; @@ -51,6 +109,12 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev) if (devid < 0) goto err1; + ret = dwc3_exynos_register_phys(exynos); + if (ret) { + dev_err(&pdev->dev, "couldn't register PHYs\n"); + goto err1; + } + dwc3 = platform_device_alloc("dwc3", devid); if (!dwc3) { dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); @@ -120,6 +184,8 @@ static int __devexit dwc3_exynos_remove(struct platform_device *pdev) struct dwc3_exynos_data *pdata = pdev->dev.platform_data; platform_device_unregister(exynos->dwc3); + platform_device_unregister(exynos->usb2_phy); + platform_device_unregister(exynos->usb3_phy); dwc3_put_device_id(exynos->dwc3->id); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 479dc04..ee57a10 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -48,6 +48,9 @@ #include <linux/io.h> #include <linux/of.h> +#include <linux/usb/otg.h> +#include <linux/usb/nop-usb-xceiv.h> + #include "core.h" /* @@ -131,6 +134,8 @@ struct dwc3_omap { spinlock_t lock; struct platform_device *dwc3; + struct platform_device *usb2_phy; + struct platform_device *usb3_phy; struct device *dev; int irq; @@ -152,6 +157,59 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value) writel(value, base + offset); } +static int __devinit 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", 0); + 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", 1); + 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) { @@ -251,6 +309,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) return -ENOMEM; } + ret = dwc3_omap_register_phys(omap); + if (ret) { + dev_err(dev, "couldn't register PHYs\n"); + return ret; + } + devid = dwc3_get_device_id(); if (devid < 0) return -ENODEV; @@ -371,6 +435,8 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev) struct dwc3_omap *omap = platform_get_drvdata(pdev); platform_device_unregister(omap->dwc3); + platform_device_unregister(omap->usb2_phy); + platform_device_unregister(omap->usb3_phy); dwc3_put_device_id(omap->dwc3->id); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a9ca9ad..94f550e 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -42,6 +42,9 @@ #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/usb/otg.h> +#include <linux/usb/nop-usb-xceiv.h> + #include "core.h" /* FIXME define these in <linux/pci_ids.h> */ @@ -51,8 +54,64 @@ struct dwc3_pci { struct device *dev; struct platform_device *dwc3; + struct platform_device *usb2_phy; + struct platform_device *usb3_phy; }; +static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue) +{ + 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", 0); + if (!pdev) + return -ENOMEM; + + glue->usb2_phy = pdev; + pdata.type = USB_PHY_TYPE_USB2; + + ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); + if (ret) + goto err1; + + pdev = platform_device_alloc("nop_usb_xceiv", 1); + if (!pdev) { + ret = -ENOMEM; + goto err1; + } + + glue->usb3_phy = pdev; + pdata.type = USB_PHY_TYPE_USB3; + + ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); + if (ret) + goto err2; + + ret = platform_device_add(glue->usb2_phy); + if (ret) + goto err2; + + ret = platform_device_add(glue->usb3_phy); + if (ret) + goto err3; + + return 0; + +err3: + platform_device_del(glue->usb2_phy); + +err2: + platform_device_put(glue->usb3_phy); + +err1: + platform_device_put(glue->usb2_phy); + + return ret; +} + static int __devinit dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) { @@ -80,6 +139,12 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, pci_set_power_state(pci, PCI_D0); pci_set_master(pci); + ret = dwc3_pci_register_phys(glue); + if (ret) { + dev_err(dev, "couldn't register PHYs\n"); + return ret; + } + devid = dwc3_get_device_id(); if (devid < 0) { ret = -ENOMEM; @@ -144,6 +209,8 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci) { struct dwc3_pci *glue = pci_get_drvdata(pci); + platform_device_unregister(glue->usb2_phy); + platform_device_unregister(glue->usb3_phy); dwc3_put_device_id(glue->dwc3->id); platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e4d5ca8..d7da073 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -125,7 +125,6 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, struct dwc3_request *req) { struct dwc3 *dwc = dep->dwc; - int ret = 0; req->request.actual = 0; req->request.status = -EINPROGRESS; @@ -156,16 +155,72 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, dep->flags &= ~(DWC3_EP_PENDING_REQUEST | DWC3_EP0_DIR_IN); - } else if (dwc->delayed_status) { + + return 0; + } + + /* + * In case gadget driver asked us to delay the STATUS phase, + * handle it here. + */ + if (dwc->delayed_status) { + unsigned direction; + + direction = !dwc->ep0_expect_in; dwc->delayed_status = false; if (dwc->ep0state == EP0_STATUS_PHASE) - __dwc3_ep0_do_control_status(dwc, dwc->eps[1]); + __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); else dev_dbg(dwc->dev, "too early for delayed status\n"); + + return 0; } - return ret; + /* + * Unfortunately we have uncovered a limitation wrt the Data Phase. + * + * Section 9.4 says we can wait for the XferNotReady(DATA) event to + * come before issueing Start Transfer command, but if we do, we will + * miss situations where the host starts another SETUP phase instead of + * the DATA phase. Such cases happen at least on TD.7.6 of the Link + * Layer Compliance Suite. + * + * The problem surfaces due to the fact that in case of back-to-back + * SETUP packets there will be no XferNotReady(DATA) generated and we + * will be stuck waiting for XferNotReady(DATA) forever. + * + * By looking at tables 9-13 and 9-14 of the Databook, we can see that + * it tells us to start Data Phase right away. It also mentions that if + * we receive a SETUP phase instead of the DATA phase, core will issue + * XferComplete for the DATA phase, before actually initiating it in + * the wire, with the TRB's status set to "SETUP_PENDING". Such status + * can only be used to print some debugging logs, as the core expects + * us to go through to the STATUS phase and start a CONTROL_STATUS TRB, + * just so it completes right away, without transferring anything and, + * only then, we can go back to the SETUP phase. + * + * Because of this scenario, SNPS decided to change the programming + * model of control transfers and support on-demand transfers only for + * the STATUS phase. To fix the issue we have now, we will always wait + * for gadget driver to queue the DATA phase's struct usb_request, then + * start it right away. + * + * If we're actually in a 2-stage transfer, we will wait for + * XferNotReady(STATUS). + */ + if (dwc->three_stage_setup) { + unsigned direction; + + direction = dwc->ep0_expect_in; + dwc->ep0state = EP0_DATA_PHASE; + + __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); + + dep->flags &= ~DWC3_EP0_DIR_IN; + } + + return 0; } int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, @@ -207,9 +262,14 @@ out: static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { - struct dwc3_ep *dep = dwc->eps[0]; + struct dwc3_ep *dep; + + /* reinitialize physical ep1 */ + dep = dwc->eps[1]; + dep->flags = DWC3_EP_ENABLED; /* stall is always issued on EP0 */ + dep = dwc->eps[0]; __dwc3_gadget_ep_set_halt(dep, 1); dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; @@ -698,6 +758,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct dwc3_trb *trb; struct dwc3_ep *ep0; u32 transferred; + u32 status; u32 length; u8 epnum; @@ -710,6 +771,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ur = &r->request; trb = dwc->ep0_trb; + + status = DWC3_TRB_SIZE_TRBSTS(trb->size); + if (status == DWC3_TRBSTS_SETUP_PENDING) { + dev_dbg(dwc->dev, "Setup Pending received\n"); + + if (r) + dwc3_gadget_giveback(ep0, r, -ECONNRESET); + + return; + } + length = trb->size & DWC3_TRB_SIZE_MASK; if (dwc->ep0_bounced) { @@ -745,8 +817,11 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, { struct dwc3_request *r; struct dwc3_ep *dep; + struct dwc3_trb *trb; + u32 status; dep = dwc->eps[0]; + trb = dwc->ep0_trb; if (!list_empty(&dep->request_list)) { r = next_request(&dep->request_list); @@ -766,6 +841,10 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, } } + status = DWC3_TRB_SIZE_TRBSTS(trb->size); + if (status == DWC3_TRBSTS_SETUP_PENDING) + dev_dbg(dwc->dev, "Setup Pending received\n"); + dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } @@ -799,12 +878,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, } } -static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - dwc3_ep0_out_start(dwc); -} - static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req) { @@ -857,29 +930,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, WARN_ON(ret < 0); } -static void dwc3_ep0_do_control_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_ep *dep; - struct dwc3_request *req; - - dep = dwc->eps[0]; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); - dep->flags |= DWC3_EP_PENDING_REQUEST; - - if (event->endpoint_number) - dep->flags |= DWC3_EP0_DIR_IN; - return; - } - - req = next_request(&dep->request_list); - dep = dwc->eps[event->endpoint_number]; - - __dwc3_ep0_do_control_data(dwc, dep, req); -} - static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -911,100 +961,61 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, __dwc3_ep0_do_control_status(dwc, dep); } -static void dwc3_ep0_xfernotready(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) +static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) { - dwc->setup_packet_pending = true; - - /* - * This part is very tricky: If we have just handled - * XferNotReady(Setup) and we're now expecting a - * XferComplete but, instead, we receive another - * XferNotReady(Setup), we should STALL and restart - * the state machine. - * - * In all other cases, we just continue waiting - * for the XferComplete event. - * - * We are a little bit unsafe here because we're - * not trying to ensure that last event was, indeed, - * XferNotReady(Setup). - * - * Still, we don't expect any condition where that - * should happen and, even if it does, it would be - * another error condition. - */ - if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); - dwc3_ep0_stall_and_restart(dwc); - break; - case DEPEVT_STATUS_CONTROL_DATA: - /* FALLTHROUGH */ - case DEPEVT_STATUS_CONTROL_STATUS: - /* FALLTHROUGH */ - default: - dev_vdbg(dwc->dev, "waiting for XferComplete\n"); - } + struct dwc3_gadget_ep_cmd_params params; + u32 cmd; + int ret; + if (!dep->resource_index) return; - } - - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Control Setup\n"); - dwc->ep0state = EP0_SETUP_PHASE; + cmd = DWC3_DEPCMD_ENDTRANSFER; + cmd |= DWC3_DEPCMD_CMDIOC; + cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); + memset(¶ms, 0, sizeof(params)); + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + WARN_ON_ONCE(ret); + dep->resource_index = 0; +} - dwc3_ep0_do_control_setup(dwc, event); - break; +static void dwc3_ep0_xfernotready(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + dwc->setup_packet_pending = true; + switch (event->status) { case DEPEVT_STATUS_CONTROL_DATA: dev_vdbg(dwc->dev, "Control Data\n"); - dwc->ep0state = EP0_DATA_PHASE; - - if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_DATA); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - /* - * One of the possible error cases is when Host _does_ - * request for Data Phase, but it does so on the wrong - * direction. + * We already have a DATA transfer in the controller's cache, + * if we receive a XferNotReady(DATA) we will ignore it, unless + * it's for the wrong direction. * - * Here, we already know ep0_next_event is DATA (see above), - * so we only need to check for direction. + * In that case, we must issue END_TRANSFER command to the Data + * Phase we already have started and issue SetStall on the + * control endpoint. */ if (dwc->ep0_expect_in != event->endpoint_number) { + struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; + dev_vdbg(dwc->dev, "Wrong direction for Data phase\n"); + dwc3_ep0_end_control_data(dwc, dep); dwc3_ep0_stall_and_restart(dwc); return; } - dwc3_ep0_do_control_data(dwc, event); break; case DEPEVT_STATUS_CONTROL_STATUS: + if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) + return; + dev_vdbg(dwc->dev, "Control Status\n"); dwc->ep0state = EP0_STATUS_PHASE; - if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_STATUS); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - if (dwc->delayed_status) { WARN_ON_ONCE(event->endpoint_number != 1); dev_vdbg(dwc->dev, "Mass Storage delayed status\n"); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c2813c2b..c9e729a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -434,15 +434,25 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3_gadget_ep_cmd_params params; memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) - | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) - | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1); + | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); + + /* Burst size is only needed in SuperSpeed mode */ + if (dwc->gadget.speed == USB_SPEED_SUPER) { + u32 burst = dep->endpoint.maxburst - 1; + + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + } + + if (ignore) + params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN | DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -501,7 +511,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) */ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3 *dwc = dep->dwc; u32 reg; @@ -513,7 +524,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc); + ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore); if (ret) return ret; @@ -561,27 +572,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) if (!list_empty(&dep->req_queued)) { dwc3_stop_active_transfer(dwc, dep->number); - /* - * NOTICE: We are violating what the Databook says about the - * EndTransfer command. Ideally we would _always_ wait for the - * EndTransfer Command Completion IRQ, but that's causing too - * much trouble synchronizing between us and gadget driver. - * - * We have discussed this with the IP Provider and it was - * suggested to giveback all requests here, but give HW some - * extra time to synchronize with the interconnect. We're using - * an arbitraty 100us delay for that. - * - * Note also that a similar handling was tested by Synopsys - * (thanks a lot Paul) and nothing bad has come out of it. - * In short, what we're doing is: - * - * - Issue EndTransfer WITH CMDIOC bit set - * - Wait 100us - * - giveback all requests to gadget driver - */ - udelay(100); - + /* - giveback all requests to gadget driver */ while (!list_empty(&dep->req_queued)) { req = next_request(&dep->req_queued); @@ -660,6 +651,12 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dep = to_dwc3_ep(ep); dwc = dep->dwc; + if (dep->flags & DWC3_EP_ENABLED) { + dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", + dep->name); + return 0; + } + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: strlcat(dep->name, "-control", sizeof(dep->name)); @@ -677,16 +674,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_err(dwc->dev, "invalid endpoint transfer type\n"); } - if (dep->flags & DWC3_EP_ENABLED) { - dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", - dep->name); - return 0; - } - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc); + ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1105,12 +1096,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) } ret = __dwc3_gadget_kick_transfer(dep, 0, true); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1119,16 +1107,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * core may not see the modified TRB(s). */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY)) { + (dep->flags & DWC3_EP_BUSY) && + !(dep->flags & DWC3_EP_MISSED_ISOC)) { WARN_ON_ONCE(!dep->resource_index); ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1533,14 +1519,14 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err0; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err1; @@ -1765,7 +1751,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, int i; for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { - struct dwc3_ep *dep = dwc->eps[i]; + dep = dwc->eps[i]; if (!(dep->flags & DWC3_EP_ENABLED)) continue; @@ -1892,6 +1878,25 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) if (!dep->resource_index) return; + /* + * NOTICE: We are violating what the Databook says about the + * EndTransfer command. Ideally we would _always_ wait for the + * EndTransfer Command Completion IRQ, but that's causing too + * much trouble synchronizing between us and gadget driver. + * + * We have discussed this with the IP Provider and it was + * suggested to giveback all requests here, but give HW some + * extra time to synchronize with the interconnect. We're using + * an arbitraty 100us delay for that. + * + * Note also that a similar handling was tested by Synopsys + * (thanks a lot Paul) and nothing bad has come out of it. + * In short, what we're doing is: + * + * - Issue EndTransfer WITH CMDIOC bit set + * - Wait 100us + */ + cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); @@ -1899,6 +1904,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; + + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) @@ -2156,14 +2163,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) } dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 89dcf15..e426ad6 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -491,7 +491,7 @@ static int ehci_wait_for_port(int port); * Return -ENODEV for any general failure * Return -EIO if wait for port fails */ -int dbgp_external_startup(void) +static int _dbgp_external_startup(void) { int devnum; struct usb_debug_descriptor dbgp_desc; @@ -613,6 +613,11 @@ err: goto try_again; return -ENODEV; } + +int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup(); +} EXPORT_SYMBOL_GPL(dbgp_external_startup); static int ehci_reset_port(int port) @@ -804,7 +809,7 @@ try_next_port: dbgp_ehci_status("ehci skip - already configured"); } - ret = dbgp_external_startup(); + ret = _dbgp_external_startup(); if (ret == -EIO) goto next_debug_port; @@ -934,7 +939,7 @@ static void early_dbgp_write(struct console *con, const char *str, u32 n) ctrl = readl(&ehci_debug->control); if (!(ctrl & DBGP_ENABLED)) { dbgp_not_safe = 1; - dbgp_external_startup(); + _dbgp_external_startup(); } else { cmd |= CMD_RUN; writel(cmd, &ehci_regs->command); @@ -974,10 +979,14 @@ struct console early_dbgp_console = { .index = -1, }; -int dbgp_reset_prep(void) +int dbgp_reset_prep(struct usb_hcd *hcd) { + int ret = xen_dbgp_reset_prep(hcd); u32 ctrl; + if (ret) + return ret; + dbgp_not_safe = 1; if (!ehci_debug) return 0; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 51ab5fd..dfb51a4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -154,16 +154,25 @@ config USB_LPC32XX config USB_ATMEL_USBA tristate "Atmel USBA" - select USB_GADGET_DUALSPEED depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 help USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. +config USB_BCM63XX_UDC + tristate "Broadcom BCM63xx Peripheral Controller" + depends on BCM63XX + help + Many Broadcom BCM63xx chipsets (such as the BCM6328) have a + high speed USB Device Port with support for four fixed endpoints + (plus endpoint zero). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "bcm63xx_udc". + config USB_FSL_USB2 tristate "Freescale Highspeed USB DR Peripheral Controller" depends on FSL_SOC || ARCH_MXC - select USB_GADGET_DUALSPEED select USB_FSL_MPH_DR_OF if OF help Some of Freescale PowerPC and i.MX processors have a High Speed @@ -179,7 +188,6 @@ config USB_FSL_USB2 config USB_FUSB300 tristate "Faraday FUSB300 USB Peripheral Controller" depends on !PHYS_ADDR_T_64BIT - select USB_GADGET_DUALSPEED help Faraday usb device controller FUSB300 driver @@ -227,7 +235,6 @@ config USB_PXA25X_SMALL config USB_R8A66597 tristate "Renesas R8A66597 USB Peripheral Controller" - select USB_GADGET_DUALSPEED help R8A66597 is a discrete USB host and peripheral controller chip that supports both full and high speed USB 2.0 data transfers. @@ -240,7 +247,6 @@ config USB_R8A66597 config USB_RENESAS_USBHS_UDC tristate 'Renesas USBHS controller' depends on USB_RENESAS_USBHS - select USB_GADGET_DUALSPEED help Renesas USBHS is a discrete USB host and peripheral controller chip that supports both full and high speed USB 2.0 data transfers. @@ -268,7 +274,6 @@ config USB_PXA27X config USB_S3C_HSOTG tristate "S3C HS/OtG USB Device controller" depends on S3C_DEV_USB_HSOTG - select USB_GADGET_DUALSPEED help The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. @@ -305,7 +310,6 @@ config USB_S3C2410_DEBUG config USB_S3C_HSUDC tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" depends on ARCH_S3C24XX - select USB_GADGET_DUALSPEED help Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC integrated with dual speed USB 2.0 device controller. It has @@ -315,7 +319,6 @@ config USB_S3C_HSUDC config USB_MV_UDC tristate "Marvell USB2.0 Device Controller" - select USB_GADGET_DUALSPEED help Marvell Socs (including PXA and MMP series) include a high speed USB2.0 OTG controller, which can be configured as high speed or @@ -338,14 +341,12 @@ config USB_MV_U3D config USB_GADGET_MUSB_HDRC tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)" depends on USB_MUSB_HDRC - select USB_GADGET_DUALSPEED help This OTG-capable silicon IP is used in dual designs including the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin config USB_M66592 tristate "Renesas M66592 USB Peripheral Controller" - select USB_GADGET_DUALSPEED help M66592 is a discrete USB peripheral controller chip that supports both full and high speed USB 2.0 data transfers. @@ -362,7 +363,6 @@ config USB_M66592 config USB_AMD5536UDC tristate "AMD5536 UDC" depends on PCI - select USB_GADGET_DUALSPEED help The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. It is a USB Highspeed DMA capable USB device controller. Beside ep0 @@ -389,7 +389,6 @@ config USB_FSL_QE config USB_NET2272 tristate "PLX NET2272" - select USB_GADGET_DUALSPEED help PLX NET2272 is a USB peripheral controller which supports both full and high speed USB 2.0 data transfers. @@ -413,7 +412,6 @@ config USB_NET2272_DMA config USB_NET2280 tristate "NetChip 228x" depends on PCI - select USB_GADGET_DUALSPEED help NetChip 2280 / 2282 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. @@ -443,7 +441,6 @@ config USB_GOKU config USB_EG20T tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" depends on PCI - select USB_GADGET_DUALSPEED help This is a USB device driver for EG20T PCH. EG20T PCH is the platform controller hub that is used in Intel's @@ -470,8 +467,6 @@ config USB_EG20T config USB_DUMMY_HCD tristate "Dummy HCD (DEVELOPMENT)" depends on USB=y || (USB=m && USB_GADGET=m) - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED help This host controller driver emulates USB, looping all data transfer requests back to a USB "gadget driver" in the same host. The host @@ -496,18 +491,15 @@ config USB_DUMMY_HCD endmenu -# Selected by UDC drivers that support high-speed operation. -config USB_GADGET_DUALSPEED - bool - -# Selected by UDC drivers that support super-speed opperation -config USB_GADGET_SUPERSPEED - bool - depends on USB_GADGET_DUALSPEED - # # USB Gadget Drivers # + +# composite based drivers +config USB_LIBCOMPOSITE + tristate + depends on USB_GADGET + choice tristate "USB Gadget Drivers" default USB_ETH @@ -531,6 +523,7 @@ choice config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" + select USB_LIBCOMPOSITE help Gadget Zero is a two-configuration device. It either sinks and sources bulk data; or it loops back a configurable number of @@ -564,8 +557,9 @@ config USB_ZERO_HNPTEST one serve as the USB host instead (in the "B-Host" role). config USB_AUDIO - tristate "Audio Gadget (EXPERIMENTAL)" + tristate "Audio Gadget" depends on SND + select USB_LIBCOMPOSITE select SND_PCM help This Gadget Audio driver is compatible with USB Audio Class @@ -594,6 +588,7 @@ config GADGET_UAC1 config USB_ETH tristate "Ethernet Gadget (with CDC Ethernet support)" depends on NET + select USB_LIBCOMPOSITE select CRC32 help This driver implements Ethernet style communication, in one of @@ -629,6 +624,7 @@ config USB_ETH config USB_ETH_RNDIS bool "RNDIS support" depends on USB_ETH + select USB_LIBCOMPOSITE default y help Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, @@ -647,6 +643,7 @@ config USB_ETH_RNDIS config USB_ETH_EEM bool "Ethernet Emulation Model (EEM) support" depends on USB_ETH + select USB_LIBCOMPOSITE default n help CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM @@ -663,6 +660,7 @@ config USB_ETH_EEM config USB_G_NCM tristate "Network Control Model (NCM) support" depends on NET + select USB_LIBCOMPOSITE select CRC32 help This driver implements USB CDC NCM subclass standard. NCM is @@ -674,8 +672,7 @@ config USB_G_NCM dynamically linked module called "g_ncm". config USB_GADGETFS - tristate "Gadget Filesystem (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Gadget Filesystem" help This driver provides a filesystem based API that lets user mode programs implement a single-configuration USB device, including @@ -683,15 +680,12 @@ config USB_GADGETFS All endpoints, transfer speeds, and transfer types supported by the hardware are available, through read() and write() calls. - Currently, this option is still labelled as EXPERIMENTAL because - of existing race conditions in the underlying in-kernel AIO core. - Say "y" to link the driver statically, or "m" to build a dynamically linked module called "gadgetfs". config USB_FUNCTIONFS - tristate "Function Filesystem (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Function Filesystem" + select USB_LIBCOMPOSITE select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) help The Function Filesystem (FunctionFS) lets one create USB @@ -755,6 +749,7 @@ config USB_FILE_STORAGE_TEST config USB_MASS_STORAGE tristate "Mass Storage Gadget" depends on BLOCK + select USB_LIBCOMPOSITE help The Mass Storage Gadget acts as a USB Mass Storage disk drive. As its storage repository it can use a regular file or a block @@ -770,6 +765,7 @@ config USB_MASS_STORAGE config USB_GADGET_TARGET tristate "USB Gadget Target Fabric Module" depends on TARGET_CORE + select USB_LIBCOMPOSITE help This fabric is an USB gadget. Two USB protocols are supported that is BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is @@ -779,6 +775,7 @@ config USB_GADGET_TARGET config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" + select USB_LIBCOMPOSITE help The Serial Gadget talks to the Linux-USB generic serial driver. This driver supports a CDC-ACM module option, which can be used @@ -797,8 +794,9 @@ config USB_G_SERIAL make MS-Windows work with CDC ACM. config USB_MIDI_GADGET - tristate "MIDI Gadget (EXPERIMENTAL)" - depends on SND && EXPERIMENTAL + tristate "MIDI Gadget" + depends on SND + select USB_LIBCOMPOSITE select SND_RAWMIDI help The MIDI Gadget acts as a USB Audio device, with one MIDI @@ -812,6 +810,7 @@ config USB_MIDI_GADGET config USB_G_PRINTER tristate "Printer Gadget" + select USB_LIBCOMPOSITE help The Printer Gadget channels data between the USB host and a userspace program driving the print engine. The user space @@ -828,6 +827,7 @@ config USB_G_PRINTER config USB_CDC_COMPOSITE tristate "CDC Composite Device (Ethernet and ACM)" depends on NET + select USB_LIBCOMPOSITE help This driver provides two functions in one configuration: a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. @@ -842,6 +842,7 @@ config USB_CDC_COMPOSITE config USB_G_NOKIA tristate "Nokia composite gadget" depends on PHONET + select USB_LIBCOMPOSITE help The Nokia composite gadget provides support for acm, obex and phonet in only one composite gadget driver. @@ -852,6 +853,7 @@ config USB_G_NOKIA config USB_G_ACM_MS tristate "CDC Composite Device (ACM and mass storage)" depends on BLOCK + select USB_LIBCOMPOSITE help This driver provides two functions in one configuration: a mass storage, and a CDC ACM (serial port) link. @@ -860,9 +862,10 @@ config USB_G_ACM_MS dynamically linked module called "g_acm_ms". config USB_G_MULTI - tristate "Multifunction Composite Gadget (EXPERIMENTAL)" + tristate "Multifunction Composite Gadget" depends on BLOCK && NET select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS + select USB_LIBCOMPOSITE help The Multifunction Composite Gadget provides Ethernet (RNDIS and/or CDC Ethernet), mass storage and ACM serial link @@ -903,6 +906,7 @@ config USB_G_MULTI_CDC config USB_G_HID tristate "HID Gadget" + select USB_LIBCOMPOSITE help The HID gadget driver provides generic emulation of USB Human Interface Devices (HID). @@ -913,8 +917,10 @@ config USB_G_HID Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_hid". +# Standalone / single function gadgets config USB_G_DBGP tristate "EHCI Debug Device Gadget" + select USB_LIBCOMPOSITE help This gadget emulates an EHCI Debug device. This is useful when you want to interact with an EHCI Debug Port. diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 3fd8cd0..307be5f 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -4,6 +4,9 @@ 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 obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o @@ -16,6 +19,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o +obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o fsl_usb2_udc-y := fsl_udc_core.o fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 75b8a69..5a7f289 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -15,7 +15,7 @@ */ #include <linux/kernel.h> -#include <linux/utsname.h> +#include <linux/module.h> #include "u_serial.h" @@ -41,15 +41,12 @@ * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" #include "u_serial.c" #include "f_acm.c" #include "f_mass_storage.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, @@ -89,17 +86,11 @@ static const struct usb_descriptor_header *otg_desc[] = { NULL, }; - /* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -157,7 +148,6 @@ static struct usb_configuration acm_ms_config_driver = { static int __init acm_ms_bind(struct usb_composite_dev *cdev) { - int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; void *retp; @@ -174,44 +164,22 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) goto fail0; } - /* set bcdDevice */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - } else { - WARNING(cdev, "controller '%s' not recognized; trying %s\n", - gadget->name, - acm_ms_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - /* * Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail1; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration */ status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); if (status < 0) goto fail1; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC); fsg_common_put(&fsg_common); @@ -232,11 +200,12 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver acm_ms_driver = { +static __refdata struct usb_composite_driver acm_ms_driver = { .name = "g_acm_ms", .dev = &device_desc, .max_speed = USB_SPEED_SUPER, .strings = dev_strings, + .bind = acm_ms_bind, .unbind = __exit_p(acm_ms_unbind), }; @@ -246,7 +215,7 @@ MODULE_LICENSE("GPL v2"); static int __init init(void) { - return usb_composite_probe(&acm_ms_driver, acm_ms_bind); + return usb_composite_probe(&acm_ms_driver); } module_init(init); diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 187d211..fc0ec5e 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1401,7 +1401,7 @@ static int udc_wakeup(struct usb_gadget *gadget) } static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int amd5536_stop(struct usb_gadget_driver *driver); /* gadget operations */ static const struct usb_gadget_ops udc_ops = { @@ -1914,7 +1914,7 @@ static int setup_ep0(struct udc *dev) /* Called by gadget driver to register itself */ static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct udc *dev = udc; int retval; @@ -1932,7 +1932,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget); + retval = bind(&dev->gadget, driver); /* Some gadget drivers use both ep0 directions. * NOTE: to gadget driver, ep0 is just one endpoint... diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 1e35963..89d90b5 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -469,7 +469,7 @@ static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); - struct at91_udc *udc = ep->udc; + struct at91_udc *udc; u16 maxpacket; u32 tmp; unsigned long flags; @@ -483,6 +483,7 @@ static int at91_ep_enable(struct usb_ep *_ep, return -EINVAL; } + udc = ep->udc; if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { DBG("bogus device state\n"); return -ESHUTDOWN; @@ -1699,7 +1700,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) int retval; struct resource *res; - if (!dev->platform_data) { + if (!dev->platform_data && !pdev->dev.of_node) { /* small (so we copy it) but critical! */ DBG("missing platform_data\n"); return -ENODEV; diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 9889924..231b0ef 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -12,35 +12,21 @@ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> -#include <linux/utsname.h> +#include <linux/module.h> +#include <linux/usb/composite.h> +#include "gadget_chips.h" #define DRIVER_DESC "Linux USB Audio Gadget" #define DRIVER_VERSION "Feb 2, 2012" -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" +USB_GADGET_COMPOSITE_OPTIONS(); /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -149,39 +135,18 @@ static struct usb_configuration audio_config_driver = { static int __init audio_bind(struct usb_composite_dev *cdev) { - int gcnum; int status; - gcnum = usb_gadget_controller_number(cdev->gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - ERROR(cdev, "controller '%s' not recognized; trying %s\n", - cdev->gadget->name, - audio_config_driver.label); - device_desc.bcdDevice = - __constant_cpu_to_le16(0x0300 | 0x0099); - } - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - cdev->gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; status = usb_add_config(cdev, &audio_config_driver, audio_do_config); if (status < 0) goto fail; + usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION); return 0; @@ -198,17 +163,18 @@ static int __exit audio_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver audio_driver = { +static __refdata struct usb_composite_driver audio_driver = { .name = "g_audio", .dev = &device_desc, .strings = audio_strings, .max_speed = USB_SPEED_HIGH, + .bind = audio_bind, .unbind = __exit_p(audio_unbind), }; static int __init init(void) { - return usb_composite_probe(&audio_driver, audio_bind); + return usb_composite_probe(&audio_driver); } module_init(init); diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c new file mode 100644 index 0000000..9ca7922 --- /dev/null +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -0,0 +1,2464 @@ +/* + * bcm63xx_udc.c -- BCM63xx UDC high/full speed USB device controller + * + * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com> + * Copyright (C) 2012 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/clk.h> +#include <linux/compiler.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kconfig.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/workqueue.h> + +#include <bcm63xx_cpu.h> +#include <bcm63xx_iudma.h> +#include <bcm63xx_dev_usb_usbd.h> +#include <bcm63xx_io.h> +#include <bcm63xx_regs.h> + +#define DRV_MODULE_NAME "bcm63xx_udc" + +static const char bcm63xx_ep0name[] = "ep0"; +static const char *const bcm63xx_ep_name[] = { + bcm63xx_ep0name, + "ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int", +}; + +static bool use_fullspeed; +module_param(use_fullspeed, bool, S_IRUGO); +MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only"); + +/* + * RX IRQ coalescing options: + * + * false (default) - one IRQ per DATAx packet. Slow but reliable. The + * driver is able to pass the "testusb" suite and recover from conditions like: + * + * 1) Device queues up a 2048-byte RX IUDMA transaction on an OUT bulk ep + * 2) Host sends 512 bytes of data + * 3) Host decides to reconfigure the device and sends SET_INTERFACE + * 4) Device shuts down the endpoint and cancels the RX transaction + * + * true - one IRQ per transfer, for transfers <= 2048B. Generates + * considerably fewer IRQs, but error recovery is less robust. Does not + * reliably pass "testusb". + * + * TX always uses coalescing, because we can cancel partially complete TX + * transfers by repeatedly flushing the FIFO. The hardware doesn't allow + * this on RX. + */ +static bool irq_coalesce; +module_param(irq_coalesce, bool, S_IRUGO); +MODULE_PARM_DESC(irq_coalesce, "take one IRQ per RX transfer"); + +#define BCM63XX_NUM_EP 5 +#define BCM63XX_NUM_IUDMA 6 +#define BCM63XX_NUM_FIFO_PAIRS 3 + +#define IUDMA_RESET_TIMEOUT_US 10000 + +#define IUDMA_EP0_RXCHAN 0 +#define IUDMA_EP0_TXCHAN 1 + +#define IUDMA_MAX_FRAGMENT 2048 +#define BCM63XX_MAX_CTRL_PKT 64 + +#define BCMEP_CTRL 0x00 +#define BCMEP_ISOC 0x01 +#define BCMEP_BULK 0x02 +#define BCMEP_INTR 0x03 + +#define BCMEP_OUT 0x00 +#define BCMEP_IN 0x01 + +#define BCM63XX_SPD_FULL 1 +#define BCM63XX_SPD_HIGH 0 + +#define IUDMA_DMAC_OFFSET 0x200 +#define IUDMA_DMAS_OFFSET 0x400 + +enum bcm63xx_ep0_state { + EP0_REQUEUE, + EP0_IDLE, + EP0_IN_DATA_PHASE_SETUP, + EP0_IN_DATA_PHASE_COMPLETE, + EP0_OUT_DATA_PHASE_SETUP, + EP0_OUT_DATA_PHASE_COMPLETE, + EP0_OUT_STATUS_PHASE, + EP0_IN_FAKE_STATUS_PHASE, + EP0_SHUTDOWN, +}; + +static const char __maybe_unused bcm63xx_ep0_state_names[][32] = { + "REQUEUE", + "IDLE", + "IN_DATA_PHASE_SETUP", + "IN_DATA_PHASE_COMPLETE", + "OUT_DATA_PHASE_SETUP", + "OUT_DATA_PHASE_COMPLETE", + "OUT_STATUS_PHASE", + "IN_FAKE_STATUS_PHASE", + "SHUTDOWN", +}; + +/** + * struct iudma_ch_cfg - Static configuration for an IUDMA channel. + * @ep_num: USB endpoint number. + * @n_bds: Number of buffer descriptors in the ring. + * @ep_type: Endpoint type (control, bulk, interrupt). + * @dir: Direction (in, out). + * @n_fifo_slots: Number of FIFO entries to allocate for this channel. + * @max_pkt_hs: Maximum packet size in high speed mode. + * @max_pkt_fs: Maximum packet size in full speed mode. + */ +struct iudma_ch_cfg { + int ep_num; + int n_bds; + int ep_type; + int dir; + int n_fifo_slots; + int max_pkt_hs; + int max_pkt_fs; +}; + +static const struct iudma_ch_cfg iudma_defaults[] = { + + /* This controller was designed to support a CDC/RNDIS application. + It may be possible to reconfigure some of the endpoints, but + the hardware limitations (FIFO sizing and number of DMA channels) + may significantly impact flexibility and/or stability. Change + these values at your own risk. + + ep_num ep_type n_fifo_slots max_pkt_fs + idx | n_bds | dir | max_pkt_hs | + | | | | | | | | */ + [0] = { -1, 4, BCMEP_CTRL, BCMEP_OUT, 32, 64, 64 }, + [1] = { 0, 4, BCMEP_CTRL, BCMEP_OUT, 32, 64, 64 }, + [2] = { 2, 16, BCMEP_BULK, BCMEP_OUT, 128, 512, 64 }, + [3] = { 1, 16, BCMEP_BULK, BCMEP_IN, 128, 512, 64 }, + [4] = { 4, 4, BCMEP_INTR, BCMEP_OUT, 32, 64, 64 }, + [5] = { 3, 4, BCMEP_INTR, BCMEP_IN, 32, 64, 64 }, +}; + +struct bcm63xx_udc; + +/** + * struct iudma_ch - Represents the current state of a single IUDMA channel. + * @ch_idx: IUDMA channel index (0 to BCM63XX_NUM_IUDMA-1). + * @ep_num: USB endpoint number. -1 for ep0 RX. + * @enabled: Whether bcm63xx_ep_enable() has been called. + * @max_pkt: "Chunk size" on the USB interface. Based on interface speed. + * @is_tx: true for TX, false for RX. + * @bep: Pointer to the associated endpoint. NULL for ep0 RX. + * @udc: Reference to the device controller. + * @read_bd: Next buffer descriptor to reap from the hardware. + * @write_bd: Next BD available for a new packet. + * @end_bd: Points to the final BD in the ring. + * @n_bds_used: Number of BD entries currently occupied. + * @bd_ring: Base pointer to the BD ring. + * @bd_ring_dma: Physical (DMA) address of bd_ring. + * @n_bds: Total number of BDs in the ring. + * + * ep0 has two IUDMA channels (IUDMA_EP0_RXCHAN and IUDMA_EP0_TXCHAN), as it is + * bidirectional. The "struct usb_ep" associated with ep0 is for TX (IN) + * only. + * + * Each bulk/intr endpoint has a single IUDMA channel and a single + * struct usb_ep. + */ +struct iudma_ch { + unsigned int ch_idx; + int ep_num; + bool enabled; + int max_pkt; + bool is_tx; + struct bcm63xx_ep *bep; + struct bcm63xx_udc *udc; + + struct bcm_enet_desc *read_bd; + struct bcm_enet_desc *write_bd; + struct bcm_enet_desc *end_bd; + int n_bds_used; + + struct bcm_enet_desc *bd_ring; + dma_addr_t bd_ring_dma; + unsigned int n_bds; +}; + +/** + * struct bcm63xx_ep - Internal (driver) state of a single endpoint. + * @ep_num: USB endpoint number. + * @iudma: Pointer to IUDMA channel state. + * @ep: USB gadget layer representation of the EP. + * @udc: Reference to the device controller. + * @queue: Linked list of outstanding requests for this EP. + * @halted: 1 if the EP is stalled; 0 otherwise. + */ +struct bcm63xx_ep { + unsigned int ep_num; + struct iudma_ch *iudma; + struct usb_ep ep; + struct bcm63xx_udc *udc; + struct list_head queue; + unsigned halted:1; +}; + +/** + * struct bcm63xx_req - Internal (driver) state of a single request. + * @queue: Links back to the EP's request list. + * @req: USB gadget layer representation of the request. + * @offset: Current byte offset into the data buffer (next byte to queue). + * @bd_bytes: Number of data bytes in outstanding BD entries. + * @iudma: IUDMA channel used for the request. + */ +struct bcm63xx_req { + struct list_head queue; /* ep's requests */ + struct usb_request req; + unsigned int offset; + unsigned int bd_bytes; + struct iudma_ch *iudma; +}; + +/** + * struct bcm63xx_udc - Driver/hardware private context. + * @lock: Spinlock to mediate access to this struct, and (most) HW regs. + * @dev: Generic Linux device structure. + * @pd: Platform data (board/port info). + * @usbd_clk: Clock descriptor for the USB device block. + * @usbh_clk: Clock descriptor for the USB host block. + * @gadget: USB slave device. + * @driver: Driver for USB slave devices. + * @usbd_regs: Base address of the USBD/USB20D block. + * @iudma_regs: Base address of the USBD's associated IUDMA block. + * @bep: Array of endpoints, including ep0. + * @iudma: Array of all IUDMA channels used by this controller. + * @cfg: USB configuration number, from SET_CONFIGURATION wValue. + * @iface: USB interface number, from SET_INTERFACE wIndex. + * @alt_iface: USB alt interface number, from SET_INTERFACE wValue. + * @ep0_ctrl_req: Request object for bcm63xx_udc-initiated ep0 transactions. + * @ep0_ctrl_buf: Data buffer for ep0_ctrl_req. + * @ep0state: Current state of the ep0 state machine. + * @ep0_wq: Workqueue struct used to wake up the ep0 state machine. + * @wedgemap: Bitmap of wedged endpoints. + * @ep0_req_reset: USB reset is pending. + * @ep0_req_set_cfg: Need to spoof a SET_CONFIGURATION packet. + * @ep0_req_set_iface: Need to spoof a SET_INTERFACE packet. + * @ep0_req_shutdown: Driver is shutting down; requesting ep0 to halt activity. + * @ep0_req_completed: ep0 request has completed; worker has not seen it yet. + * @ep0_reply: Pending reply from gadget driver. + * @ep0_request: Outstanding ep0 request. + * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>. + * @debugfs_usbd: debugfs file "usbd" for controller state. + * @debugfs_iudma: debugfs file "usbd" for IUDMA state. + */ +struct bcm63xx_udc { + spinlock_t lock; + + struct device *dev; + struct bcm63xx_usbd_platform_data *pd; + struct clk *usbd_clk; + struct clk *usbh_clk; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + void __iomem *usbd_regs; + void __iomem *iudma_regs; + + struct bcm63xx_ep bep[BCM63XX_NUM_EP]; + struct iudma_ch iudma[BCM63XX_NUM_IUDMA]; + + int cfg; + int iface; + int alt_iface; + + struct bcm63xx_req ep0_ctrl_req; + u8 *ep0_ctrl_buf; + + int ep0state; + struct work_struct ep0_wq; + + unsigned long wedgemap; + + unsigned ep0_req_reset:1; + unsigned ep0_req_set_cfg:1; + unsigned ep0_req_set_iface:1; + unsigned ep0_req_shutdown:1; + + unsigned ep0_req_completed:1; + struct usb_request *ep0_reply; + struct usb_request *ep0_request; + + struct dentry *debugfs_root; + struct dentry *debugfs_usbd; + struct dentry *debugfs_iudma; +}; + +static const struct usb_ep_ops bcm63xx_udc_ep_ops; + +/*********************************************************************** + * Convenience functions + ***********************************************************************/ + +static inline struct bcm63xx_udc *gadget_to_udc(struct usb_gadget *g) +{ + return container_of(g, struct bcm63xx_udc, gadget); +} + +static inline struct bcm63xx_ep *our_ep(struct usb_ep *ep) +{ + return container_of(ep, struct bcm63xx_ep, ep); +} + +static inline struct bcm63xx_req *our_req(struct usb_request *req) +{ + return container_of(req, struct bcm63xx_req, req); +} + +static inline u32 usbd_readl(struct bcm63xx_udc *udc, u32 off) +{ + return bcm_readl(udc->usbd_regs + off); +} + +static inline void usbd_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +{ + bcm_writel(val, udc->usbd_regs + off); +} + +static inline u32 usb_dma_readl(struct bcm63xx_udc *udc, u32 off) +{ + return bcm_readl(udc->iudma_regs + off); +} + +static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +{ + bcm_writel(val, udc->iudma_regs + off); +} + +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +{ + return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +} + +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +{ + bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +} + +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +{ + return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +} + +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +{ + bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +} + +static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) +{ + if (is_enabled) { + clk_enable(udc->usbh_clk); + clk_enable(udc->usbd_clk); + udelay(10); + } else { + clk_disable(udc->usbd_clk); + clk_disable(udc->usbh_clk); + } +} + +/*********************************************************************** + * Low-level IUDMA / FIFO operations + ***********************************************************************/ + +/** + * bcm63xx_ep_dma_select - Helper function to set up the init_sel signal. + * @udc: Reference to the device controller. + * @idx: Desired init_sel value. + * + * The "init_sel" signal is used as a selection index for both endpoints + * and IUDMA channels. Since these do not map 1:1, the use of this signal + * depends on the context. + */ +static void bcm63xx_ep_dma_select(struct bcm63xx_udc *udc, int idx) +{ + u32 val = usbd_readl(udc, USBD_CONTROL_REG); + + val &= ~USBD_CONTROL_INIT_SEL_MASK; + val |= idx << USBD_CONTROL_INIT_SEL_SHIFT; + usbd_writel(udc, val, USBD_CONTROL_REG); +} + +/** + * bcm63xx_set_stall - Enable/disable stall on one endpoint. + * @udc: Reference to the device controller. + * @bep: Endpoint on which to operate. + * @is_stalled: true to enable stall, false to disable. + * + * See notes in bcm63xx_update_wedge() regarding automatic clearing of + * halt/stall conditions. + */ +static void bcm63xx_set_stall(struct bcm63xx_udc *udc, struct bcm63xx_ep *bep, + bool is_stalled) +{ + u32 val; + + val = USBD_STALL_UPDATE_MASK | + (is_stalled ? USBD_STALL_ENABLE_MASK : 0) | + (bep->ep_num << USBD_STALL_EPNUM_SHIFT); + usbd_writel(udc, val, USBD_STALL_REG); +} + +/** + * bcm63xx_fifo_setup - (Re)initialize FIFO boundaries and settings. + * @udc: Reference to the device controller. + * + * These parameters depend on the USB link speed. Settings are + * per-IUDMA-channel-pair. + */ +static void bcm63xx_fifo_setup(struct bcm63xx_udc *udc) +{ + int is_hs = udc->gadget.speed == USB_SPEED_HIGH; + u32 i, val, rx_fifo_slot, tx_fifo_slot; + + /* set up FIFO boundaries and packet sizes; this is done in pairs */ + rx_fifo_slot = tx_fifo_slot = 0; + for (i = 0; i < BCM63XX_NUM_IUDMA; i += 2) { + const struct iudma_ch_cfg *rx_cfg = &iudma_defaults[i]; + const struct iudma_ch_cfg *tx_cfg = &iudma_defaults[i + 1]; + + bcm63xx_ep_dma_select(udc, i >> 1); + + val = (rx_fifo_slot << USBD_RXFIFO_CONFIG_START_SHIFT) | + ((rx_fifo_slot + rx_cfg->n_fifo_slots - 1) << + USBD_RXFIFO_CONFIG_END_SHIFT); + rx_fifo_slot += rx_cfg->n_fifo_slots; + usbd_writel(udc, val, USBD_RXFIFO_CONFIG_REG); + usbd_writel(udc, + is_hs ? rx_cfg->max_pkt_hs : rx_cfg->max_pkt_fs, + USBD_RXFIFO_EPSIZE_REG); + + val = (tx_fifo_slot << USBD_TXFIFO_CONFIG_START_SHIFT) | + ((tx_fifo_slot + tx_cfg->n_fifo_slots - 1) << + USBD_TXFIFO_CONFIG_END_SHIFT); + tx_fifo_slot += tx_cfg->n_fifo_slots; + usbd_writel(udc, val, USBD_TXFIFO_CONFIG_REG); + usbd_writel(udc, + is_hs ? tx_cfg->max_pkt_hs : tx_cfg->max_pkt_fs, + USBD_TXFIFO_EPSIZE_REG); + + usbd_readl(udc, USBD_TXFIFO_EPSIZE_REG); + } +} + +/** + * bcm63xx_fifo_reset_ep - Flush a single endpoint's FIFO. + * @udc: Reference to the device controller. + * @ep_num: Endpoint number. + */ +static void bcm63xx_fifo_reset_ep(struct bcm63xx_udc *udc, int ep_num) +{ + u32 val; + + bcm63xx_ep_dma_select(udc, ep_num); + + val = usbd_readl(udc, USBD_CONTROL_REG); + val |= USBD_CONTROL_FIFO_RESET_MASK; + usbd_writel(udc, val, USBD_CONTROL_REG); + usbd_readl(udc, USBD_CONTROL_REG); +} + +/** + * bcm63xx_fifo_reset - Flush all hardware FIFOs. + * @udc: Reference to the device controller. + */ +static void bcm63xx_fifo_reset(struct bcm63xx_udc *udc) +{ + int i; + + for (i = 0; i < BCM63XX_NUM_FIFO_PAIRS; i++) + bcm63xx_fifo_reset_ep(udc, i); +} + +/** + * bcm63xx_ep_init - Initial (one-time) endpoint initialization. + * @udc: Reference to the device controller. + */ +static void bcm63xx_ep_init(struct bcm63xx_udc *udc) +{ + u32 i, val; + + for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { + const struct iudma_ch_cfg *cfg = &iudma_defaults[i]; + + if (cfg->ep_num < 0) + continue; + + bcm63xx_ep_dma_select(udc, cfg->ep_num); + val = (cfg->ep_type << USBD_EPNUM_TYPEMAP_TYPE_SHIFT) | + ((i >> 1) << USBD_EPNUM_TYPEMAP_DMA_CH_SHIFT); + usbd_writel(udc, val, USBD_EPNUM_TYPEMAP_REG); + } +} + +/** + * bcm63xx_ep_setup - Configure per-endpoint settings. + * @udc: Reference to the device controller. + * + * This needs to be rerun if the speed/cfg/intf/altintf changes. + */ +static void bcm63xx_ep_setup(struct bcm63xx_udc *udc) +{ + u32 val, i; + + usbd_writel(udc, USBD_CSR_SETUPADDR_DEF, USBD_CSR_SETUPADDR_REG); + + for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { + const struct iudma_ch_cfg *cfg = &iudma_defaults[i]; + int max_pkt = udc->gadget.speed == USB_SPEED_HIGH ? + cfg->max_pkt_hs : cfg->max_pkt_fs; + int idx = cfg->ep_num; + + udc->iudma[i].max_pkt = max_pkt; + + if (idx < 0) + continue; + udc->bep[idx].ep.maxpacket = max_pkt; + + val = (idx << USBD_CSR_EP_LOG_SHIFT) | + (cfg->dir << USBD_CSR_EP_DIR_SHIFT) | + (cfg->ep_type << USBD_CSR_EP_TYPE_SHIFT) | + (udc->cfg << USBD_CSR_EP_CFG_SHIFT) | + (udc->iface << USBD_CSR_EP_IFACE_SHIFT) | + (udc->alt_iface << USBD_CSR_EP_ALTIFACE_SHIFT) | + (max_pkt << USBD_CSR_EP_MAXPKT_SHIFT); + usbd_writel(udc, val, USBD_CSR_EP_REG(idx)); + } +} + +/** + * iudma_write - Queue a single IUDMA transaction. + * @udc: Reference to the device controller. + * @iudma: IUDMA channel to use. + * @breq: Request containing the transaction data. + * + * For RX IUDMA, this will queue a single buffer descriptor, as RX IUDMA + * does not honor SOP/EOP so the handling of multiple buffers is ambiguous. + * So iudma_write() may be called several times to fulfill a single + * usb_request. + * + * For TX IUDMA, this can queue multiple buffer descriptors if needed. + */ +static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma, + struct bcm63xx_req *breq) +{ + int first_bd = 1, last_bd = 0, extra_zero_pkt = 0; + unsigned int bytes_left = breq->req.length - breq->offset; + const int max_bd_bytes = !irq_coalesce && !iudma->is_tx ? + iudma->max_pkt : IUDMA_MAX_FRAGMENT; + + iudma->n_bds_used = 0; + breq->bd_bytes = 0; + breq->iudma = iudma; + + if ((bytes_left % iudma->max_pkt == 0) && bytes_left && breq->req.zero) + extra_zero_pkt = 1; + + do { + struct bcm_enet_desc *d = iudma->write_bd; + u32 dmaflags = 0; + unsigned int n_bytes; + + if (d == iudma->end_bd) { + dmaflags |= DMADESC_WRAP_MASK; + iudma->write_bd = iudma->bd_ring; + } else { + iudma->write_bd++; + } + iudma->n_bds_used++; + + n_bytes = min_t(int, bytes_left, max_bd_bytes); + if (n_bytes) + dmaflags |= n_bytes << DMADESC_LENGTH_SHIFT; + else + dmaflags |= (1 << DMADESC_LENGTH_SHIFT) | + DMADESC_USB_ZERO_MASK; + + dmaflags |= DMADESC_OWNER_MASK; + if (first_bd) { + dmaflags |= DMADESC_SOP_MASK; + first_bd = 0; + } + + /* + * extra_zero_pkt forces one more iteration through the loop + * after all data is queued up, to send the zero packet + */ + if (extra_zero_pkt && !bytes_left) + extra_zero_pkt = 0; + + if (!iudma->is_tx || iudma->n_bds_used == iudma->n_bds || + (n_bytes == bytes_left && !extra_zero_pkt)) { + last_bd = 1; + dmaflags |= DMADESC_EOP_MASK; + } + + d->address = breq->req.dma + breq->offset; + mb(); + d->len_stat = dmaflags; + + breq->offset += n_bytes; + breq->bd_bytes += n_bytes; + bytes_left -= n_bytes; + } while (!last_bd); + + usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, + ENETDMAC_CHANCFG_REG(iudma->ch_idx)); +} + +/** + * iudma_read - Check for IUDMA buffer completion. + * @udc: Reference to the device controller. + * @iudma: IUDMA channel to use. + * + * This checks to see if ALL of the outstanding BDs on the DMA channel + * have been filled. If so, it returns the actual transfer length; + * otherwise it returns -EBUSY. + */ +static int iudma_read(struct bcm63xx_udc *udc, struct iudma_ch *iudma) +{ + int i, actual_len = 0; + struct bcm_enet_desc *d = iudma->read_bd; + + if (!iudma->n_bds_used) + return -EINVAL; + + for (i = 0; i < iudma->n_bds_used; i++) { + u32 dmaflags; + + dmaflags = d->len_stat; + + if (dmaflags & DMADESC_OWNER_MASK) + return -EBUSY; + + actual_len += (dmaflags & DMADESC_LENGTH_MASK) >> + DMADESC_LENGTH_SHIFT; + if (d == iudma->end_bd) + d = iudma->bd_ring; + else + d++; + } + + iudma->read_bd = d; + iudma->n_bds_used = 0; + return actual_len; +} + +/** + * iudma_reset_channel - Stop DMA on a single channel. + * @udc: Reference to the device controller. + * @iudma: IUDMA channel to reset. + */ +static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) +{ + int timeout = IUDMA_RESET_TIMEOUT_US; + struct bcm_enet_desc *d; + int ch_idx = iudma->ch_idx; + + if (!iudma->is_tx) + bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num)); + + /* stop DMA, then wait for the hardware to wrap up */ + usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); + + while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & + ENETDMAC_CHANCFG_EN_MASK) { + udelay(1); + + /* repeatedly flush the FIFO data until the BD completes */ + if (iudma->is_tx && iudma->ep_num >= 0) + bcm63xx_fifo_reset_ep(udc, iudma->ep_num); + + if (!timeout--) { + dev_err(udc->dev, "can't reset IUDMA channel %d\n", + ch_idx); + break; + } + if (timeout == IUDMA_RESET_TIMEOUT_US / 2) { + dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n", + ch_idx); + usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, + ENETDMAC_CHANCFG_REG(ch_idx)); + } + } + usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); + + /* don't leave "live" HW-owned entries for the next guy to step on */ + for (d = iudma->bd_ring; d <= iudma->end_bd; d++) + d->len_stat = 0; + mb(); + + iudma->read_bd = iudma->write_bd = iudma->bd_ring; + iudma->n_bds_used = 0; + + /* set up IRQs, UBUS burst size, and BD base for this channel */ + usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, + ENETDMAC_IRMASK_REG(ch_idx)); + usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); + + usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); + usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); +} + +/** + * iudma_init_channel - One-time IUDMA channel initialization. + * @udc: Reference to the device controller. + * @ch_idx: Channel to initialize. + */ +static int iudma_init_channel(struct bcm63xx_udc *udc, unsigned int ch_idx) +{ + struct iudma_ch *iudma = &udc->iudma[ch_idx]; + const struct iudma_ch_cfg *cfg = &iudma_defaults[ch_idx]; + unsigned int n_bds = cfg->n_bds; + struct bcm63xx_ep *bep = NULL; + + iudma->ep_num = cfg->ep_num; + iudma->ch_idx = ch_idx; + iudma->is_tx = !!(ch_idx & 0x01); + if (iudma->ep_num >= 0) { + bep = &udc->bep[iudma->ep_num]; + bep->iudma = iudma; + INIT_LIST_HEAD(&bep->queue); + } + + iudma->bep = bep; + iudma->udc = udc; + + /* ep0 is always active; others are controlled by the gadget driver */ + if (iudma->ep_num <= 0) + iudma->enabled = true; + + iudma->n_bds = n_bds; + iudma->bd_ring = dmam_alloc_coherent(udc->dev, + n_bds * sizeof(struct bcm_enet_desc), + &iudma->bd_ring_dma, GFP_KERNEL); + if (!iudma->bd_ring) + return -ENOMEM; + iudma->end_bd = &iudma->bd_ring[n_bds - 1]; + + return 0; +} + +/** + * iudma_init - One-time initialization of all IUDMA channels. + * @udc: Reference to the device controller. + * + * Enable DMA, flush channels, and enable global IUDMA IRQs. + */ +static int iudma_init(struct bcm63xx_udc *udc) +{ + int i, rc; + + usb_dma_writel(udc, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); + + for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { + rc = iudma_init_channel(udc, i); + if (rc) + return rc; + iudma_reset_channel(udc, &udc->iudma[i]); + } + + usb_dma_writel(udc, BIT(BCM63XX_NUM_IUDMA)-1, ENETDMA_GLB_IRQMASK_REG); + return 0; +} + +/** + * iudma_uninit - Uninitialize IUDMA channels. + * @udc: Reference to the device controller. + * + * Kill global IUDMA IRQs, flush channels, and kill DMA. + */ +static void iudma_uninit(struct bcm63xx_udc *udc) +{ + int i; + + usb_dma_writel(udc, 0, ENETDMA_GLB_IRQMASK_REG); + + for (i = 0; i < BCM63XX_NUM_IUDMA; i++) + iudma_reset_channel(udc, &udc->iudma[i]); + + usb_dma_writel(udc, 0, ENETDMA_CFG_REG); +} + +/*********************************************************************** + * Other low-level USBD operations + ***********************************************************************/ + +/** + * bcm63xx_set_ctrl_irqs - Mask/unmask control path interrupts. + * @udc: Reference to the device controller. + * @enable_irqs: true to enable, false to disable. + */ +static void bcm63xx_set_ctrl_irqs(struct bcm63xx_udc *udc, bool enable_irqs) +{ + u32 val; + + usbd_writel(udc, 0, USBD_STATUS_REG); + + val = BIT(USBD_EVENT_IRQ_USB_RESET) | + BIT(USBD_EVENT_IRQ_SETUP) | + BIT(USBD_EVENT_IRQ_SETCFG) | + BIT(USBD_EVENT_IRQ_SETINTF) | + BIT(USBD_EVENT_IRQ_USB_LINK); + usbd_writel(udc, enable_irqs ? val : 0, USBD_EVENT_IRQ_MASK_REG); + usbd_writel(udc, val, USBD_EVENT_IRQ_STATUS_REG); +} + +/** + * bcm63xx_select_phy_mode - Select between USB device and host mode. + * @udc: Reference to the device controller. + * @is_device: true for device, false for host. + * + * This should probably be reworked to use the drivers/usb/otg + * infrastructure. + * + * By default, the AFE/pullups are disabled in device mode, until + * bcm63xx_select_pullup() is called. + */ +static void bcm63xx_select_phy_mode(struct bcm63xx_udc *udc, bool is_device) +{ + u32 val, portmask = BIT(udc->pd->port_no); + + if (BCMCPU_IS_6328()) { + /* configure pinmux to sense VBUS signal */ + val = bcm_gpio_readl(GPIO_PINMUX_OTHR_REG); + val &= ~GPIO_PINMUX_OTHR_6328_USB_MASK; + val |= is_device ? GPIO_PINMUX_OTHR_6328_USB_DEV : + GPIO_PINMUX_OTHR_6328_USB_HOST; + bcm_gpio_writel(val, GPIO_PINMUX_OTHR_REG); + } + + val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG); + if (is_device) { + val |= (portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT); + val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT); + } else { + val &= ~(portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT); + val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT); + } + bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG); + + val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG); + if (is_device) + val |= USBH_PRIV_SWAP_USBD_MASK; + else + val &= ~USBH_PRIV_SWAP_USBD_MASK; + bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG); +} + +/** + * bcm63xx_select_pullup - Enable/disable the pullup on D+ + * @udc: Reference to the device controller. + * @is_on: true to enable the pullup, false to disable. + * + * If the pullup is active, the host will sense a FS/HS device connected to + * the port. If the pullup is inactive, the host will think the USB + * device has been disconnected. + */ +static void bcm63xx_select_pullup(struct bcm63xx_udc *udc, bool is_on) +{ + u32 val, portmask = BIT(udc->pd->port_no); + + val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG); + if (is_on) + val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT); + else + val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT); + bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG); +} + +/** + * bcm63xx_uninit_udc_hw - Shut down the hardware prior to driver removal. + * @udc: Reference to the device controller. + * + * This just masks the IUDMA IRQs and releases the clocks. It is assumed + * that bcm63xx_udc_stop() has already run, and the clocks are stopped. + */ +static void bcm63xx_uninit_udc_hw(struct bcm63xx_udc *udc) +{ + set_clocks(udc, true); + iudma_uninit(udc); + set_clocks(udc, false); + + clk_put(udc->usbd_clk); + clk_put(udc->usbh_clk); +} + +/** + * bcm63xx_init_udc_hw - Initialize the controller hardware and data structures. + * @udc: Reference to the device controller. + */ +static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc) +{ + int i, rc = 0; + u32 val; + + udc->ep0_ctrl_buf = devm_kzalloc(udc->dev, BCM63XX_MAX_CTRL_PKT, + GFP_KERNEL); + if (!udc->ep0_ctrl_buf) + return -ENOMEM; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + for (i = 0; i < BCM63XX_NUM_EP; i++) { + struct bcm63xx_ep *bep = &udc->bep[i]; + + bep->ep.name = bcm63xx_ep_name[i]; + bep->ep_num = i; + bep->ep.ops = &bcm63xx_udc_ep_ops; + list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list); + bep->halted = 0; + bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT; + bep->udc = udc; + bep->ep.desc = NULL; + INIT_LIST_HEAD(&bep->queue); + } + + udc->gadget.ep0 = &udc->bep[0].ep; + list_del(&udc->bep[0].ep.ep_list); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->ep0state = EP0_SHUTDOWN; + + udc->usbh_clk = clk_get(udc->dev, "usbh"); + if (IS_ERR(udc->usbh_clk)) + return -EIO; + + udc->usbd_clk = clk_get(udc->dev, "usbd"); + if (IS_ERR(udc->usbd_clk)) { + clk_put(udc->usbh_clk); + return -EIO; + } + + set_clocks(udc, true); + + val = USBD_CONTROL_AUTO_CSRS_MASK | + USBD_CONTROL_DONE_CSRS_MASK | + (irq_coalesce ? USBD_CONTROL_RXZSCFG_MASK : 0); + usbd_writel(udc, val, USBD_CONTROL_REG); + + val = USBD_STRAPS_APP_SELF_PWR_MASK | + USBD_STRAPS_APP_RAM_IF_MASK | + USBD_STRAPS_APP_CSRPRGSUP_MASK | + USBD_STRAPS_APP_8BITPHY_MASK | + USBD_STRAPS_APP_RMTWKUP_MASK; + + if (udc->gadget.max_speed == USB_SPEED_HIGH) + val |= (BCM63XX_SPD_HIGH << USBD_STRAPS_SPEED_SHIFT); + else + val |= (BCM63XX_SPD_FULL << USBD_STRAPS_SPEED_SHIFT); + usbd_writel(udc, val, USBD_STRAPS_REG); + + bcm63xx_set_ctrl_irqs(udc, false); + + usbd_writel(udc, 0, USBD_EVENT_IRQ_CFG_LO_REG); + + val = USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_ENUM_ON) | + USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_SET_CSRS); + usbd_writel(udc, val, USBD_EVENT_IRQ_CFG_HI_REG); + + rc = iudma_init(udc); + set_clocks(udc, false); + if (rc) + bcm63xx_uninit_udc_hw(udc); + + return 0; +} + +/*********************************************************************** + * Standard EP gadget operations + ***********************************************************************/ + +/** + * bcm63xx_ep_enable - Enable one endpoint. + * @ep: Endpoint to enable. + * @desc: Contains max packet, direction, etc. + * + * Most of the endpoint parameters are fixed in this controller, so there + * isn't much for this function to do. + */ +static int bcm63xx_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + struct iudma_ch *iudma = bep->iudma; + unsigned long flags; + + if (!ep || !desc || ep->name == bcm63xx_ep0name) + return -EINVAL; + + if (!udc->driver) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc->lock, flags); + if (iudma->enabled) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EINVAL; + } + + iudma->enabled = true; + BUG_ON(!list_empty(&bep->queue)); + + iudma_reset_channel(udc, iudma); + + bep->halted = 0; + bcm63xx_set_stall(udc, bep, false); + clear_bit(bep->ep_num, &udc->wedgemap); + + ep->desc = desc; + ep->maxpacket = usb_endpoint_maxp(desc); + + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +/** + * bcm63xx_ep_disable - Disable one endpoint. + * @ep: Endpoint to disable. + */ +static int bcm63xx_ep_disable(struct usb_ep *ep) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + struct iudma_ch *iudma = bep->iudma; + struct list_head *pos, *n; + unsigned long flags; + + if (!ep || !ep->desc) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (!iudma->enabled) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EINVAL; + } + iudma->enabled = false; + + iudma_reset_channel(udc, iudma); + + if (!list_empty(&bep->queue)) { + list_for_each_safe(pos, n, &bep->queue) { + struct bcm63xx_req *breq = + list_entry(pos, struct bcm63xx_req, queue); + + usb_gadget_unmap_request(&udc->gadget, &breq->req, + iudma->is_tx); + list_del(&breq->queue); + breq->req.status = -ESHUTDOWN; + + spin_unlock_irqrestore(&udc->lock, flags); + breq->req.complete(&iudma->bep->ep, &breq->req); + spin_lock_irqsave(&udc->lock, flags); + } + } + ep->desc = NULL; + + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +/** + * bcm63xx_udc_alloc_request - Allocate a new request. + * @ep: Endpoint associated with the request. + * @mem_flags: Flags to pass to kzalloc(). + */ +static struct usb_request *bcm63xx_udc_alloc_request(struct usb_ep *ep, + gfp_t mem_flags) +{ + struct bcm63xx_req *breq; + + breq = kzalloc(sizeof(*breq), mem_flags); + if (!breq) + return NULL; + return &breq->req; +} + +/** + * bcm63xx_udc_free_request - Free a request. + * @ep: Endpoint associated with the request. + * @req: Request to free. + */ +static void bcm63xx_udc_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + struct bcm63xx_req *breq = our_req(req); + kfree(breq); +} + +/** + * bcm63xx_udc_queue - Queue up a new request. + * @ep: Endpoint associated with the request. + * @req: Request to add. + * @mem_flags: Unused. + * + * If the queue is empty, start this request immediately. Otherwise, add + * it to the list. + * + * ep0 replies are sent through this function from the gadget driver, but + * they are treated differently because they need to be handled by the ep0 + * state machine. (Sometimes they are replies to control requests that + * were spoofed by this driver, and so they shouldn't be transmitted at all.) + */ +static int bcm63xx_udc_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t mem_flags) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + struct bcm63xx_req *breq = our_req(req); + unsigned long flags; + int rc = 0; + + if (unlikely(!req || !req->complete || !req->buf || !ep)) + return -EINVAL; + + req->actual = 0; + req->status = 0; + breq->offset = 0; + + if (bep == &udc->bep[0]) { + /* only one reply per request, please */ + if (udc->ep0_reply) + return -EINVAL; + + udc->ep0_reply = req; + schedule_work(&udc->ep0_wq); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + if (!bep->iudma->enabled) { + rc = -ESHUTDOWN; + goto out; + } + + rc = usb_gadget_map_request(&udc->gadget, req, bep->iudma->is_tx); + if (rc == 0) { + list_add_tail(&breq->queue, &bep->queue); + if (list_is_singular(&bep->queue)) + iudma_write(udc, bep->iudma, breq); + } + +out: + spin_unlock_irqrestore(&udc->lock, flags); + return rc; +} + +/** + * bcm63xx_udc_dequeue - Remove a pending request from the queue. + * @ep: Endpoint associated with the request. + * @req: Request to remove. + * + * If the request is not at the head of the queue, this is easy - just nuke + * it. If the request is at the head of the queue, we'll need to stop the + * DMA transaction and then queue up the successor. + */ +static int bcm63xx_udc_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + struct bcm63xx_req *breq = our_req(req), *cur; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&udc->lock, flags); + if (list_empty(&bep->queue)) { + rc = -EINVAL; + goto out; + } + + cur = list_first_entry(&bep->queue, struct bcm63xx_req, queue); + usb_gadget_unmap_request(&udc->gadget, &breq->req, bep->iudma->is_tx); + + if (breq == cur) { + iudma_reset_channel(udc, bep->iudma); + list_del(&breq->queue); + + if (!list_empty(&bep->queue)) { + struct bcm63xx_req *next; + + next = list_first_entry(&bep->queue, + struct bcm63xx_req, queue); + iudma_write(udc, bep->iudma, next); + } + } else { + list_del(&breq->queue); + } + +out: + spin_unlock_irqrestore(&udc->lock, flags); + + req->status = -ESHUTDOWN; + req->complete(ep, req); + + return rc; +} + +/** + * bcm63xx_udc_set_halt - Enable/disable STALL flag in the hardware. + * @ep: Endpoint to halt. + * @value: Zero to clear halt; nonzero to set halt. + * + * See comments in bcm63xx_update_wedge(). + */ +static int bcm63xx_udc_set_halt(struct usb_ep *ep, int value) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + bcm63xx_set_stall(udc, bep, !!value); + bep->halted = value; + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/** + * bcm63xx_udc_set_wedge - Stall the endpoint until the next reset. + * @ep: Endpoint to wedge. + * + * See comments in bcm63xx_update_wedge(). + */ +static int bcm63xx_udc_set_wedge(struct usb_ep *ep) +{ + struct bcm63xx_ep *bep = our_ep(ep); + struct bcm63xx_udc *udc = bep->udc; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + set_bit(bep->ep_num, &udc->wedgemap); + bcm63xx_set_stall(udc, bep, true); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_ep_ops bcm63xx_udc_ep_ops = { + .enable = bcm63xx_ep_enable, + .disable = bcm63xx_ep_disable, + + .alloc_request = bcm63xx_udc_alloc_request, + .free_request = bcm63xx_udc_free_request, + + .queue = bcm63xx_udc_queue, + .dequeue = bcm63xx_udc_dequeue, + + .set_halt = bcm63xx_udc_set_halt, + .set_wedge = bcm63xx_udc_set_wedge, +}; + +/*********************************************************************** + * EP0 handling + ***********************************************************************/ + +/** + * bcm63xx_ep0_setup_callback - Drop spinlock to invoke ->setup callback. + * @udc: Reference to the device controller. + * @ctrl: 8-byte SETUP request. + */ +static int bcm63xx_ep0_setup_callback(struct bcm63xx_udc *udc, + struct usb_ctrlrequest *ctrl) +{ + int rc; + + spin_unlock_irq(&udc->lock); + rc = udc->driver->setup(&udc->gadget, ctrl); + spin_lock_irq(&udc->lock); + return rc; +} + +/** + * bcm63xx_ep0_spoof_set_cfg - Synthesize a SET_CONFIGURATION request. + * @udc: Reference to the device controller. + * + * Many standard requests are handled automatically in the hardware, but + * we still need to pass them to the gadget driver so that it can + * reconfigure the interfaces/endpoints if necessary. + * + * Unfortunately we are not able to send a STALL response if the host + * requests an invalid configuration. If this happens, we'll have to be + * content with printing a warning. + */ +static int bcm63xx_ep0_spoof_set_cfg(struct bcm63xx_udc *udc) +{ + struct usb_ctrlrequest ctrl; + int rc; + + ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_DEVICE; + ctrl.bRequest = USB_REQ_SET_CONFIGURATION; + ctrl.wValue = cpu_to_le16(udc->cfg); + ctrl.wIndex = 0; + ctrl.wLength = 0; + + rc = bcm63xx_ep0_setup_callback(udc, &ctrl); + if (rc < 0) { + dev_warn_ratelimited(udc->dev, + "hardware auto-acked bad SET_CONFIGURATION(%d) request\n", + udc->cfg); + } + return rc; +} + +/** + * bcm63xx_ep0_spoof_set_iface - Synthesize a SET_INTERFACE request. + * @udc: Reference to the device controller. + */ +static int bcm63xx_ep0_spoof_set_iface(struct bcm63xx_udc *udc) +{ + struct usb_ctrlrequest ctrl; + int rc; + + ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_INTERFACE; + ctrl.bRequest = USB_REQ_SET_INTERFACE; + ctrl.wValue = cpu_to_le16(udc->alt_iface); + ctrl.wIndex = cpu_to_le16(udc->iface); + ctrl.wLength = 0; + + rc = bcm63xx_ep0_setup_callback(udc, &ctrl); + if (rc < 0) { + dev_warn_ratelimited(udc->dev, + "hardware auto-acked bad SET_INTERFACE(%d,%d) request\n", + udc->iface, udc->alt_iface); + } + return rc; +} + +/** + * bcm63xx_ep0_map_write - dma_map and iudma_write a single request. + * @udc: Reference to the device controller. + * @ch_idx: IUDMA channel number. + * @req: USB gadget layer representation of the request. + */ +static void bcm63xx_ep0_map_write(struct bcm63xx_udc *udc, int ch_idx, + struct usb_request *req) +{ + struct bcm63xx_req *breq = our_req(req); + struct iudma_ch *iudma = &udc->iudma[ch_idx]; + + BUG_ON(udc->ep0_request); + udc->ep0_request = req; + + req->actual = 0; + breq->offset = 0; + usb_gadget_map_request(&udc->gadget, req, iudma->is_tx); + iudma_write(udc, iudma, breq); +} + +/** + * bcm63xx_ep0_complete - Set completion status and "stage" the callback. + * @udc: Reference to the device controller. + * @req: USB gadget layer representation of the request. + * @status: Status to return to the gadget driver. + */ +static void bcm63xx_ep0_complete(struct bcm63xx_udc *udc, + struct usb_request *req, int status) +{ + req->status = status; + if (status) + req->actual = 0; + if (req->complete) { + spin_unlock_irq(&udc->lock); + req->complete(&udc->bep[0].ep, req); + spin_lock_irq(&udc->lock); + } +} + +/** + * bcm63xx_ep0_nuke_reply - Abort request from the gadget driver due to + * reset/shutdown. + * @udc: Reference to the device controller. + * @is_tx: Nonzero for TX (IN), zero for RX (OUT). + */ +static void bcm63xx_ep0_nuke_reply(struct bcm63xx_udc *udc, int is_tx) +{ + struct usb_request *req = udc->ep0_reply; + + udc->ep0_reply = NULL; + usb_gadget_unmap_request(&udc->gadget, req, is_tx); + if (udc->ep0_request == req) { + udc->ep0_req_completed = 0; + udc->ep0_request = NULL; + } + bcm63xx_ep0_complete(udc, req, -ESHUTDOWN); +} + +/** + * bcm63xx_ep0_read_complete - Close out the pending ep0 request; return + * transfer len. + * @udc: Reference to the device controller. + */ +static int bcm63xx_ep0_read_complete(struct bcm63xx_udc *udc) +{ + struct usb_request *req = udc->ep0_request; + + udc->ep0_req_completed = 0; + udc->ep0_request = NULL; + + return req->actual; +} + +/** + * bcm63xx_ep0_internal_request - Helper function to submit an ep0 request. + * @udc: Reference to the device controller. + * @ch_idx: IUDMA channel number. + * @length: Number of bytes to TX/RX. + * + * Used for simple transfers performed by the ep0 worker. This will always + * use ep0_ctrl_req / ep0_ctrl_buf. + */ +static void bcm63xx_ep0_internal_request(struct bcm63xx_udc *udc, int ch_idx, + int length) +{ + struct usb_request *req = &udc->ep0_ctrl_req.req; + + req->buf = udc->ep0_ctrl_buf; + req->length = length; + req->complete = NULL; + + bcm63xx_ep0_map_write(udc, ch_idx, req); +} + +/** + * bcm63xx_ep0_do_setup - Parse new SETUP packet and decide how to handle it. + * @udc: Reference to the device controller. + * + * EP0_IDLE probably shouldn't ever happen. EP0_REQUEUE means we're ready + * for the next packet. Anything else means the transaction requires multiple + * stages of handling. + */ +static enum bcm63xx_ep0_state bcm63xx_ep0_do_setup(struct bcm63xx_udc *udc) +{ + int rc; + struct usb_ctrlrequest *ctrl = (void *)udc->ep0_ctrl_buf; + + rc = bcm63xx_ep0_read_complete(udc); + + if (rc < 0) { + dev_err(udc->dev, "missing SETUP packet\n"); + return EP0_IDLE; + } + + /* + * Handle 0-byte IN STATUS acknowledgement. The hardware doesn't + * ALWAYS deliver these 100% of the time, so if we happen to see one, + * just throw it away. + */ + if (rc == 0) + return EP0_REQUEUE; + + /* Drop malformed SETUP packets */ + if (rc != sizeof(*ctrl)) { + dev_warn_ratelimited(udc->dev, + "malformed SETUP packet (%d bytes)\n", rc); + return EP0_REQUEUE; + } + + /* Process new SETUP packet arriving on ep0 */ + rc = bcm63xx_ep0_setup_callback(udc, ctrl); + if (rc < 0) { + bcm63xx_set_stall(udc, &udc->bep[0], true); + return EP0_REQUEUE; + } + + if (!ctrl->wLength) + return EP0_REQUEUE; + else if (ctrl->bRequestType & USB_DIR_IN) + return EP0_IN_DATA_PHASE_SETUP; + else + return EP0_OUT_DATA_PHASE_SETUP; +} + +/** + * bcm63xx_ep0_do_idle - Check for outstanding requests if ep0 is idle. + * @udc: Reference to the device controller. + * + * In state EP0_IDLE, the RX descriptor is either pending, or has been + * filled with a SETUP packet from the host. This function handles new + * SETUP packets, control IRQ events (which can generate fake SETUP packets), + * and reset/shutdown events. + * + * Returns 0 if work was done; -EAGAIN if nothing to do. + */ +static int bcm63xx_ep0_do_idle(struct bcm63xx_udc *udc) +{ + if (udc->ep0_req_reset) { + udc->ep0_req_reset = 0; + } else if (udc->ep0_req_set_cfg) { + udc->ep0_req_set_cfg = 0; + if (bcm63xx_ep0_spoof_set_cfg(udc) >= 0) + udc->ep0state = EP0_IN_FAKE_STATUS_PHASE; + } else if (udc->ep0_req_set_iface) { + udc->ep0_req_set_iface = 0; + if (bcm63xx_ep0_spoof_set_iface(udc) >= 0) + udc->ep0state = EP0_IN_FAKE_STATUS_PHASE; + } else if (udc->ep0_req_completed) { + udc->ep0state = bcm63xx_ep0_do_setup(udc); + return udc->ep0state == EP0_IDLE ? -EAGAIN : 0; + } else if (udc->ep0_req_shutdown) { + udc->ep0_req_shutdown = 0; + udc->ep0_req_completed = 0; + udc->ep0_request = NULL; + iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]); + usb_gadget_unmap_request(&udc->gadget, + &udc->ep0_ctrl_req.req, 0); + + /* bcm63xx_udc_pullup() is waiting for this */ + mb(); + udc->ep0state = EP0_SHUTDOWN; + } else if (udc->ep0_reply) { + /* + * This could happen if a USB RESET shows up during an ep0 + * transaction (especially if a laggy driver like gadgetfs + * is in use). + */ + dev_warn(udc->dev, "nuking unexpected reply\n"); + bcm63xx_ep0_nuke_reply(udc, 0); + } else { + return -EAGAIN; + } + + return 0; +} + +/** + * bcm63xx_ep0_one_round - Handle the current ep0 state. + * @udc: Reference to the device controller. + * + * Returns 0 if work was done; -EAGAIN if nothing to do. + */ +static int bcm63xx_ep0_one_round(struct bcm63xx_udc *udc) +{ + enum bcm63xx_ep0_state ep0state = udc->ep0state; + bool shutdown = udc->ep0_req_reset || udc->ep0_req_shutdown; + + switch (udc->ep0state) { + case EP0_REQUEUE: + /* set up descriptor to receive SETUP packet */ + bcm63xx_ep0_internal_request(udc, IUDMA_EP0_RXCHAN, + BCM63XX_MAX_CTRL_PKT); + ep0state = EP0_IDLE; + break; + case EP0_IDLE: + return bcm63xx_ep0_do_idle(udc); + case EP0_IN_DATA_PHASE_SETUP: + /* + * Normal case: TX request is in ep0_reply (queued by the + * callback), or will be queued shortly. When it's here, + * send it to the HW and go to EP0_IN_DATA_PHASE_COMPLETE. + * + * Shutdown case: Stop waiting for the reply. Just + * REQUEUE->IDLE. The gadget driver is NOT expected to + * queue anything else now. + */ + if (udc->ep0_reply) { + bcm63xx_ep0_map_write(udc, IUDMA_EP0_TXCHAN, + udc->ep0_reply); + ep0state = EP0_IN_DATA_PHASE_COMPLETE; + } else if (shutdown) { + ep0state = EP0_REQUEUE; + } + break; + case EP0_IN_DATA_PHASE_COMPLETE: { + /* + * Normal case: TX packet (ep0_reply) is in flight; wait for + * it to finish, then go back to REQUEUE->IDLE. + * + * Shutdown case: Reset the TX channel, send -ESHUTDOWN + * completion to the gadget driver, then REQUEUE->IDLE. + */ + if (udc->ep0_req_completed) { + udc->ep0_reply = NULL; + bcm63xx_ep0_read_complete(udc); + /* + * the "ack" sometimes gets eaten (see + * bcm63xx_ep0_do_idle) + */ + ep0state = EP0_REQUEUE; + } else if (shutdown) { + iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]); + bcm63xx_ep0_nuke_reply(udc, 1); + ep0state = EP0_REQUEUE; + } + break; + } + case EP0_OUT_DATA_PHASE_SETUP: + /* Similar behavior to EP0_IN_DATA_PHASE_SETUP */ + if (udc->ep0_reply) { + bcm63xx_ep0_map_write(udc, IUDMA_EP0_RXCHAN, + udc->ep0_reply); + ep0state = EP0_OUT_DATA_PHASE_COMPLETE; + } else if (shutdown) { + ep0state = EP0_REQUEUE; + } + break; + case EP0_OUT_DATA_PHASE_COMPLETE: { + /* Similar behavior to EP0_IN_DATA_PHASE_COMPLETE */ + if (udc->ep0_req_completed) { + udc->ep0_reply = NULL; + bcm63xx_ep0_read_complete(udc); + + /* send 0-byte ack to host */ + bcm63xx_ep0_internal_request(udc, IUDMA_EP0_TXCHAN, 0); + ep0state = EP0_OUT_STATUS_PHASE; + } else if (shutdown) { + iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]); + bcm63xx_ep0_nuke_reply(udc, 0); + ep0state = EP0_REQUEUE; + } + break; + } + case EP0_OUT_STATUS_PHASE: + /* + * Normal case: 0-byte OUT ack packet is in flight; wait + * for it to finish, then go back to REQUEUE->IDLE. + * + * Shutdown case: just cancel the transmission. Don't bother + * calling the completion, because it originated from this + * function anyway. Then go back to REQUEUE->IDLE. + */ + if (udc->ep0_req_completed) { + bcm63xx_ep0_read_complete(udc); + ep0state = EP0_REQUEUE; + } else if (shutdown) { + iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]); + udc->ep0_request = NULL; + ep0state = EP0_REQUEUE; + } + break; + case EP0_IN_FAKE_STATUS_PHASE: { + /* + * Normal case: we spoofed a SETUP packet and are now + * waiting for the gadget driver to send a 0-byte reply. + * This doesn't actually get sent to the HW because the + * HW has already sent its own reply. Once we get the + * response, return to IDLE. + * + * Shutdown case: return to IDLE immediately. + * + * Note that the ep0 RX descriptor has remained queued + * (and possibly unfilled) during this entire transaction. + * The HW datapath (IUDMA) never even sees SET_CONFIGURATION + * or SET_INTERFACE transactions. + */ + struct usb_request *r = udc->ep0_reply; + + if (!r) { + if (shutdown) + ep0state = EP0_IDLE; + break; + } + + bcm63xx_ep0_complete(udc, r, 0); + udc->ep0_reply = NULL; + ep0state = EP0_IDLE; + break; + } + case EP0_SHUTDOWN: + break; + } + + if (udc->ep0state == ep0state) + return -EAGAIN; + + udc->ep0state = ep0state; + return 0; +} + +/** + * bcm63xx_ep0_process - ep0 worker thread / state machine. + * @w: Workqueue struct. + * + * bcm63xx_ep0_process is triggered any time an event occurs on ep0. It + * is used to synchronize ep0 events and ensure that both HW and SW events + * occur in a well-defined order. When the ep0 IUDMA queues are idle, it may + * synthesize SET_CONFIGURATION / SET_INTERFACE requests that were consumed + * by the USBD hardware. + * + * The worker function will continue iterating around the state machine + * until there is nothing left to do. Usually "nothing left to do" means + * that we're waiting for a new event from the hardware. + */ +static void bcm63xx_ep0_process(struct work_struct *w) +{ + struct bcm63xx_udc *udc = container_of(w, struct bcm63xx_udc, ep0_wq); + spin_lock_irq(&udc->lock); + while (bcm63xx_ep0_one_round(udc) == 0) + ; + spin_unlock_irq(&udc->lock); +} + +/*********************************************************************** + * Standard UDC gadget operations + ***********************************************************************/ + +/** + * bcm63xx_udc_get_frame - Read current SOF frame number from the HW. + * @gadget: USB slave device. + */ +static int bcm63xx_udc_get_frame(struct usb_gadget *gadget) +{ + struct bcm63xx_udc *udc = gadget_to_udc(gadget); + + return (usbd_readl(udc, USBD_STATUS_REG) & + USBD_STATUS_SOF_MASK) >> USBD_STATUS_SOF_SHIFT; +} + +/** + * bcm63xx_udc_pullup - Enable/disable pullup on D+ line. + * @gadget: USB slave device. + * @is_on: 0 to disable pullup, 1 to enable. + * + * See notes in bcm63xx_select_pullup(). + */ +static int bcm63xx_udc_pullup(struct usb_gadget *gadget, int is_on) +{ + struct bcm63xx_udc *udc = gadget_to_udc(gadget); + unsigned long flags; + int i, rc = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (is_on && udc->ep0state == EP0_SHUTDOWN) { + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->ep0state = EP0_REQUEUE; + bcm63xx_fifo_setup(udc); + bcm63xx_fifo_reset(udc); + bcm63xx_ep_setup(udc); + + bitmap_zero(&udc->wedgemap, BCM63XX_NUM_EP); + for (i = 0; i < BCM63XX_NUM_EP; i++) + bcm63xx_set_stall(udc, &udc->bep[i], false); + + bcm63xx_set_ctrl_irqs(udc, true); + bcm63xx_select_pullup(gadget_to_udc(gadget), true); + rc = 0; + } else if (!is_on && udc->ep0state != EP0_SHUTDOWN) { + bcm63xx_select_pullup(gadget_to_udc(gadget), false); + + udc->ep0_req_shutdown = 1; + spin_unlock_irqrestore(&udc->lock, flags); + + while (1) { + schedule_work(&udc->ep0_wq); + if (udc->ep0state == EP0_SHUTDOWN) + break; + msleep(50); + } + bcm63xx_set_ctrl_irqs(udc, false); + cancel_work_sync(&udc->ep0_wq); + return 0; + } + + spin_unlock_irqrestore(&udc->lock, flags); + return rc; +} + +/** + * bcm63xx_udc_start - Start the controller. + * @gadget: USB slave device. + * @driver: Driver for USB slave devices. + */ +static int bcm63xx_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct bcm63xx_udc *udc = gadget_to_udc(gadget); + unsigned long flags; + + if (!driver || driver->max_speed < USB_SPEED_HIGH || + !driver->setup) + return -EINVAL; + if (!udc) + return -ENODEV; + if (udc->driver) + return -EBUSY; + + spin_lock_irqsave(&udc->lock, flags); + + set_clocks(udc, true); + bcm63xx_fifo_setup(udc); + bcm63xx_ep_init(udc); + bcm63xx_ep_setup(udc); + bcm63xx_fifo_reset(udc); + bcm63xx_select_phy_mode(udc, true); + + 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); + + return 0; +} + +/** + * bcm63xx_udc_stop - Shut down the controller. + * @gadget: USB slave device. + * @driver: Driver for USB slave devices. + */ +static int bcm63xx_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct bcm63xx_udc *udc = gadget_to_udc(gadget); + unsigned long flags; + + 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 + * will often complain: + * + * hub 1-0:1.0: port 1 disabled by hub (EMI?), re-enabling... + */ + msleep(100); + + bcm63xx_select_phy_mode(udc, false); + set_clocks(udc, false); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops bcm63xx_udc_ops = { + .get_frame = bcm63xx_udc_get_frame, + .pullup = bcm63xx_udc_pullup, + .udc_start = bcm63xx_udc_start, + .udc_stop = bcm63xx_udc_stop, +}; + +/*********************************************************************** + * IRQ handling + ***********************************************************************/ + +/** + * bcm63xx_update_cfg_iface - Read current configuration/interface settings. + * @udc: Reference to the device controller. + * + * This controller intercepts SET_CONFIGURATION and SET_INTERFACE messages. + * The driver never sees the raw control packets coming in on the ep0 + * IUDMA channel, but at least we get an interrupt event to tell us that + * new values are waiting in the USBD_STATUS register. + */ +static void bcm63xx_update_cfg_iface(struct bcm63xx_udc *udc) +{ + u32 reg = usbd_readl(udc, USBD_STATUS_REG); + + udc->cfg = (reg & USBD_STATUS_CFG_MASK) >> USBD_STATUS_CFG_SHIFT; + udc->iface = (reg & USBD_STATUS_INTF_MASK) >> USBD_STATUS_INTF_SHIFT; + udc->alt_iface = (reg & USBD_STATUS_ALTINTF_MASK) >> + USBD_STATUS_ALTINTF_SHIFT; + bcm63xx_ep_setup(udc); +} + +/** + * bcm63xx_update_link_speed - Check to see if the link speed has changed. + * @udc: Reference to the device controller. + * + * The link speed update coincides with a SETUP IRQ. Returns 1 if the + * speed has changed, so that the caller can update the endpoint settings. + */ +static int bcm63xx_update_link_speed(struct bcm63xx_udc *udc) +{ + u32 reg = usbd_readl(udc, USBD_STATUS_REG); + enum usb_device_speed oldspeed = udc->gadget.speed; + + switch ((reg & USBD_STATUS_SPD_MASK) >> USBD_STATUS_SPD_SHIFT) { + case BCM63XX_SPD_HIGH: + udc->gadget.speed = USB_SPEED_HIGH; + break; + case BCM63XX_SPD_FULL: + udc->gadget.speed = USB_SPEED_FULL; + break; + default: + /* this should never happen */ + udc->gadget.speed = USB_SPEED_UNKNOWN; + dev_err(udc->dev, + "received SETUP packet with invalid link speed\n"); + return 0; + } + + if (udc->gadget.speed != oldspeed) { + dev_info(udc->dev, "link up, %s-speed mode\n", + udc->gadget.speed == USB_SPEED_HIGH ? "high" : "full"); + return 1; + } else { + return 0; + } +} + +/** + * bcm63xx_update_wedge - Iterate through wedged endpoints. + * @udc: Reference to the device controller. + * @new_status: true to "refresh" wedge status; false to clear it. + * + * On a SETUP interrupt, we need to manually "refresh" the wedge status + * because the controller hardware is designed to automatically clear + * stalls in response to a CLEAR_FEATURE request from the host. + * + * On a RESET interrupt, we do want to restore all wedged endpoints. + */ +static void bcm63xx_update_wedge(struct bcm63xx_udc *udc, bool new_status) +{ + int i; + + for_each_set_bit(i, &udc->wedgemap, BCM63XX_NUM_EP) { + bcm63xx_set_stall(udc, &udc->bep[i], new_status); + if (!new_status) + clear_bit(i, &udc->wedgemap); + } +} + +/** + * bcm63xx_udc_ctrl_isr - ISR for control path events (USBD). + * @irq: IRQ number (unused). + * @dev_id: Reference to the device controller. + * + * This is where we handle link (VBUS) down, USB reset, speed changes, + * SET_CONFIGURATION, and SET_INTERFACE events. + */ +static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id) +{ + struct bcm63xx_udc *udc = dev_id; + u32 stat; + bool disconnected = false; + + stat = usbd_readl(udc, USBD_EVENT_IRQ_STATUS_REG) & + usbd_readl(udc, USBD_EVENT_IRQ_MASK_REG); + + usbd_writel(udc, stat, USBD_EVENT_IRQ_STATUS_REG); + + spin_lock(&udc->lock); + if (stat & BIT(USBD_EVENT_IRQ_USB_LINK)) { + /* VBUS toggled */ + + if (!(usbd_readl(udc, USBD_EVENTS_REG) & + USBD_EVENTS_USB_LINK_MASK) && + udc->gadget.speed != USB_SPEED_UNKNOWN) + dev_info(udc->dev, "link down\n"); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + disconnected = true; + } + if (stat & BIT(USBD_EVENT_IRQ_USB_RESET)) { + bcm63xx_fifo_setup(udc); + bcm63xx_fifo_reset(udc); + bcm63xx_ep_setup(udc); + + bcm63xx_update_wedge(udc, false); + + udc->ep0_req_reset = 1; + schedule_work(&udc->ep0_wq); + disconnected = true; + } + if (stat & BIT(USBD_EVENT_IRQ_SETUP)) { + if (bcm63xx_update_link_speed(udc)) { + bcm63xx_fifo_setup(udc); + bcm63xx_ep_setup(udc); + } + bcm63xx_update_wedge(udc, true); + } + if (stat & BIT(USBD_EVENT_IRQ_SETCFG)) { + bcm63xx_update_cfg_iface(udc); + udc->ep0_req_set_cfg = 1; + schedule_work(&udc->ep0_wq); + } + if (stat & BIT(USBD_EVENT_IRQ_SETINTF)) { + bcm63xx_update_cfg_iface(udc); + udc->ep0_req_set_iface = 1; + schedule_work(&udc->ep0_wq); + } + spin_unlock(&udc->lock); + + if (disconnected && udc->driver) + udc->driver->disconnect(&udc->gadget); + + return IRQ_HANDLED; +} + +/** + * bcm63xx_udc_data_isr - ISR for data path events (IUDMA). + * @irq: IRQ number (unused). + * @dev_id: Reference to the IUDMA channel that generated the interrupt. + * + * For the two ep0 channels, we have special handling that triggers the + * ep0 worker thread. For normal bulk/intr channels, either queue up + * the next buffer descriptor for the transaction (incomplete transaction), + * or invoke the completion callback (complete transactions). + */ +static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id) +{ + struct iudma_ch *iudma = dev_id; + struct bcm63xx_udc *udc = iudma->udc; + struct bcm63xx_ep *bep; + struct usb_request *req = NULL; + struct bcm63xx_req *breq = NULL; + int rc; + bool is_done = false; + + spin_lock(&udc->lock); + + usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, + ENETDMAC_IR_REG(iudma->ch_idx)); + bep = iudma->bep; + rc = iudma_read(udc, iudma); + + /* special handling for EP0 RX (0) and TX (1) */ + if (iudma->ch_idx == IUDMA_EP0_RXCHAN || + iudma->ch_idx == IUDMA_EP0_TXCHAN) { + req = udc->ep0_request; + breq = our_req(req); + + /* a single request could require multiple submissions */ + if (rc >= 0) { + req->actual += rc; + + if (req->actual >= req->length || breq->bd_bytes > rc) { + udc->ep0_req_completed = 1; + is_done = true; + schedule_work(&udc->ep0_wq); + + /* "actual" on a ZLP is 1 byte */ + req->actual = min(req->actual, req->length); + } else { + /* queue up the next BD (same request) */ + iudma_write(udc, iudma, breq); + } + } + } else if (!list_empty(&bep->queue)) { + breq = list_first_entry(&bep->queue, struct bcm63xx_req, queue); + req = &breq->req; + + if (rc >= 0) { + req->actual += rc; + + if (req->actual >= req->length || breq->bd_bytes > rc) { + is_done = true; + list_del(&breq->queue); + + req->actual = min(req->actual, req->length); + + if (!list_empty(&bep->queue)) { + struct bcm63xx_req *next; + + next = list_first_entry(&bep->queue, + struct bcm63xx_req, queue); + iudma_write(udc, iudma, next); + } + } else { + iudma_write(udc, iudma, breq); + } + } + } + spin_unlock(&udc->lock); + + if (is_done) { + usb_gadget_unmap_request(&udc->gadget, req, iudma->is_tx); + if (req->complete) + req->complete(&bep->ep, req); + } + + return IRQ_HANDLED; +} + +/*********************************************************************** + * Debug filesystem + ***********************************************************************/ + +/* + * bcm63xx_usbd_dbg_show - Show USBD controller state. + * @s: seq_file to which the information will be written. + * @p: Unused. + * + * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/usbd + */ +static int bcm63xx_usbd_dbg_show(struct seq_file *s, void *p) +{ + struct bcm63xx_udc *udc = s->private; + + if (!udc->driver) + return -ENODEV; + + seq_printf(s, "ep0 state: %s\n", + bcm63xx_ep0_state_names[udc->ep0state]); + seq_printf(s, " pending requests: %s%s%s%s%s%s%s\n", + udc->ep0_req_reset ? "reset " : "", + udc->ep0_req_set_cfg ? "set_cfg " : "", + udc->ep0_req_set_iface ? "set_iface " : "", + udc->ep0_req_shutdown ? "shutdown " : "", + udc->ep0_request ? "pending " : "", + udc->ep0_req_completed ? "completed " : "", + udc->ep0_reply ? "reply " : ""); + seq_printf(s, "cfg: %d; iface: %d; alt_iface: %d\n", + udc->cfg, udc->iface, udc->alt_iface); + seq_printf(s, "regs:\n"); + seq_printf(s, " control: %08x; straps: %08x; status: %08x\n", + usbd_readl(udc, USBD_CONTROL_REG), + usbd_readl(udc, USBD_STRAPS_REG), + usbd_readl(udc, USBD_STATUS_REG)); + seq_printf(s, " events: %08x; stall: %08x\n", + usbd_readl(udc, USBD_EVENTS_REG), + usbd_readl(udc, USBD_STALL_REG)); + + return 0; +} + +/* + * bcm63xx_iudma_dbg_show - Show IUDMA status and descriptors. + * @s: seq_file to which the information will be written. + * @p: Unused. + * + * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/iudma + */ +static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p) +{ + struct bcm63xx_udc *udc = s->private; + int ch_idx, i; + u32 sram2, sram3; + + if (!udc->driver) + return -ENODEV; + + for (ch_idx = 0; ch_idx < BCM63XX_NUM_IUDMA; ch_idx++) { + struct iudma_ch *iudma = &udc->iudma[ch_idx]; + struct list_head *pos; + + seq_printf(s, "IUDMA channel %d -- ", ch_idx); + switch (iudma_defaults[ch_idx].ep_type) { + case BCMEP_CTRL: + seq_printf(s, "control"); + break; + case BCMEP_BULK: + seq_printf(s, "bulk"); + break; + case BCMEP_INTR: + seq_printf(s, "interrupt"); + break; + } + seq_printf(s, ch_idx & 0x01 ? " tx" : " rx"); + seq_printf(s, " [ep%d]:\n", + max_t(int, iudma_defaults[ch_idx].ep_num, 0)); + seq_printf(s, " cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", + usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), + usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), + usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), + usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); + + sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); + sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); + seq_printf(s, " base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", + usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), + sram2 >> 16, sram2 & 0xffff, + sram3 >> 16, sram3 & 0xffff, + usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); + seq_printf(s, " desc: %d/%d used", iudma->n_bds_used, + iudma->n_bds); + + if (iudma->bep) { + i = 0; + list_for_each(pos, &iudma->bep->queue) + i++; + seq_printf(s, "; %d queued\n", i); + } else { + seq_printf(s, "\n"); + } + + for (i = 0; i < iudma->n_bds; i++) { + struct bcm_enet_desc *d = &iudma->bd_ring[i]; + + seq_printf(s, " %03x (%02x): len_stat: %04x_%04x; pa %08x", + i * sizeof(*d), i, + d->len_stat >> 16, d->len_stat & 0xffff, + d->address); + if (d == iudma->read_bd) + seq_printf(s, " <<RD"); + if (d == iudma->write_bd) + seq_printf(s, " <<WR"); + seq_printf(s, "\n"); + } + + seq_printf(s, "\n"); + } + + return 0; +} + +static int bcm63xx_usbd_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, bcm63xx_usbd_dbg_show, inode->i_private); +} + +static int bcm63xx_iudma_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, bcm63xx_iudma_dbg_show, inode->i_private); +} + +static const struct file_operations usbd_dbg_fops = { + .owner = THIS_MODULE, + .open = bcm63xx_usbd_dbg_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + +static const struct file_operations iudma_dbg_fops = { + .owner = THIS_MODULE, + .open = bcm63xx_iudma_dbg_open, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, +}; + + +/** + * bcm63xx_udc_init_debugfs - Create debugfs entries. + * @udc: Reference to the device controller. + */ +static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) +{ + struct dentry *root, *usbd, *iudma; + + if (!IS_ENABLED(CONFIG_USB_GADGET_DEBUG_FS)) + return; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + + usbd = debugfs_create_file("usbd", 0400, root, udc, + &usbd_dbg_fops); + if (!usbd) + goto err_usbd; + iudma = debugfs_create_file("iudma", 0400, root, udc, + &iudma_dbg_fops); + if (!iudma) + goto err_iudma; + + udc->debugfs_root = root; + udc->debugfs_usbd = usbd; + udc->debugfs_iudma = iudma; + return; +err_iudma: + debugfs_remove(usbd); +err_usbd: + debugfs_remove(root); +err_root: + dev_err(udc->dev, "debugfs is not available\n"); +} + +/** + * bcm63xx_udc_cleanup_debugfs - Remove debugfs entries. + * @udc: Reference to the device controller. + * + * debugfs_remove() is safe to call with a NULL argument. + */ +static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) +{ + debugfs_remove(udc->debugfs_iudma); + debugfs_remove(udc->debugfs_usbd); + debugfs_remove(udc->debugfs_root); + udc->debugfs_iudma = NULL; + udc->debugfs_usbd = NULL; + udc->debugfs_root = NULL; +} + +/*********************************************************************** + * 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. + * + * Note that platform data is required, because pd.port_no varies from chip + * to chip and is used to switch the correct USB port to device mode. + */ +static int __devinit bcm63xx_udc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bcm63xx_usbd_platform_data *pd = dev->platform_data; + struct bcm63xx_udc *udc; + struct resource *res; + int rc = -ENOMEM, i, irq; + + udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL); + if (!udc) { + dev_err(dev, "cannot allocate memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, udc); + udc->dev = dev; + udc->pd = pd; + + if (!pd) { + dev_err(dev, "missing platform data\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "error finding USBD resource\n"); + return -ENXIO; + } + udc->usbd_regs = devm_request_and_ioremap(dev, res); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "error finding IUDMA resource\n"); + return -ENXIO; + } + udc->iudma_regs = devm_request_and_ioremap(dev, res); + + if (!udc->usbd_regs || !udc->iudma_regs) { + dev_err(dev, "error requesting resources\n"); + return -ENXIO; + } + + 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; + else + udc->gadget.max_speed = USB_SPEED_FULL; + + /* request clocks, allocate buffers, and clear any pending IRQs */ + rc = bcm63xx_init_udc_hw(udc); + if (rc) + return rc; + + rc = -ENXIO; + + /* IRQ resource #0: control interrupt (VBUS, speed, etc.) */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource #0\n"); + goto out_uninit; + } + if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0, + dev_name(dev), udc) < 0) { + dev_err(dev, "error requesting IRQ #%d\n", irq); + goto out_uninit; + } + + /* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */ + for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { + irq = platform_get_irq(pdev, i + 1); + if (irq < 0) { + dev_err(dev, "missing IRQ resource #%d\n", i + 1); + goto out_uninit; + } + if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0, + dev_name(dev), &udc->iudma[i]) < 0) { + dev_err(dev, "error requesting IRQ #%d\n", irq); + goto out_uninit; + } + } + + 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; +} + +/** + * bcm63xx_udc_remove - Remove the device from the system. + * @pdev: Platform device struct from the bcm63xx BSP code. + */ +static int __devexit bcm63xx_udc_remove(struct platform_device *pdev) +{ + struct bcm63xx_udc *udc = platform_get_drvdata(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); + bcm63xx_uninit_udc_hw(udc); + + return 0; +} + +static struct platform_driver bcm63xx_udc_driver = { + .probe = bcm63xx_udc_probe, + .remove = __devexit_p(bcm63xx_udc_remove), + .driver = { + .name = DRV_MODULE_NAME, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(bcm63xx_udc_driver); + +MODULE_DESCRIPTION("BCM63xx USB Peripheral Controller"); +MODULE_AUTHOR("Kevin Cernekee <cernekee@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_MODULE_NAME); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 725550f..1e4bb77 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -11,7 +11,6 @@ */ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/module.h> #include "u_ether.h" @@ -34,6 +33,7 @@ #define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */ /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); /* * Kbuild is not very cooperative with respect to linking separately @@ -43,10 +43,6 @@ * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" #include "u_serial.c" #include "f_acm.c" #include "f_ecm.c" @@ -92,15 +88,10 @@ static const struct usb_descriptor_header *otg_desc[] = { /* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -152,7 +143,6 @@ static struct usb_configuration cdc_config_driver = { static int __init cdc_bind(struct usb_composite_dev *cdev) { - int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; @@ -172,47 +162,22 @@ static int __init cdc_bind(struct usb_composite_dev *cdev) if (status < 0) goto fail0; - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - WARNING(cdev, "controller '%s' not recognized; trying %s\n", - gadget->name, - cdc_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail1; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration */ status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config); if (status < 0) goto fail1; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC); @@ -232,11 +197,12 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver cdc_driver = { +static __refdata struct usb_composite_driver cdc_driver = { .name = "g_cdc", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = cdc_bind, .unbind = __exit_p(cdc_unbind), }; @@ -246,7 +212,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_probe(&cdc_driver, cdc_bind); + return usb_composite_probe(&cdc_driver); } module_init(init); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3f72110..957f973 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -28,44 +28,6 @@ * with the relevant device-wide data. */ -/* big enough to hold our biggest descriptor */ -#define USB_BUFSIZ 1024 - -static struct usb_composite_driver *composite; -static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); - -/* Some systems will need runtime overrides for the product identifiers - * published in the device descriptor, either numbers or strings or both. - * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -static ushort idVendor; -module_param(idVendor, ushort, 0644); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, 0644); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, 0644); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, 0644); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, 0644); -MODULE_PARM_DESC(iProduct, "USB Product string"); - -static char *iSerialNumber; -module_param(iSerialNumber, charp, 0644); -MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); - -static char composite_manufacturer[50]; - -/*-------------------------------------------------------------------------*/ /** * next_ep_desc() - advance to the next EP descriptor * @t: currect pointer within descriptor array @@ -192,6 +154,7 @@ ep_found: } return 0; } +EXPORT_SYMBOL_GPL(config_ep_by_speed); /** * usb_add_function() - add a function to a configuration @@ -250,6 +213,7 @@ done: function->name, function, value); return value; } +EXPORT_SYMBOL_GPL(usb_add_function); /** * usb_function_deactivate - prevent function and gadget enumeration @@ -286,6 +250,7 @@ int usb_function_deactivate(struct usb_function *function) spin_unlock_irqrestore(&cdev->lock, flags); return status; } +EXPORT_SYMBOL_GPL(usb_function_deactivate); /** * usb_function_activate - allow function and gadget enumeration @@ -300,9 +265,10 @@ int usb_function_deactivate(struct usb_function *function) int usb_function_activate(struct usb_function *function) { struct usb_composite_dev *cdev = function->config->cdev; + unsigned long flags; int status = 0; - spin_lock(&cdev->lock); + spin_lock_irqsave(&cdev->lock, flags); if (WARN_ON(cdev->deactivations == 0)) status = -EINVAL; @@ -312,9 +278,10 @@ int usb_function_activate(struct usb_function *function) status = usb_gadget_connect(cdev->gadget); } - spin_unlock(&cdev->lock); + spin_unlock_irqrestore(&cdev->lock, flags); return status; } +EXPORT_SYMBOL_GPL(usb_function_activate); /** * usb_interface_id() - allocate an unused interface ID @@ -351,16 +318,18 @@ int usb_interface_id(struct usb_configuration *config, } return -ENODEV; } +EXPORT_SYMBOL_GPL(usb_interface_id); static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { struct usb_config_descriptor *c = buf; void *next = buf + USB_DT_CONFIG_SIZE; - int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; + int len; struct usb_function *f; int status; + len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE; /* write the config descriptor */ c = buf; c->bLength = USB_DT_CONFIG_SIZE; @@ -790,6 +759,7 @@ done: config->bConfigurationValue, status); return status; } +EXPORT_SYMBOL_GPL(usb_add_config); static void remove_config(struct usb_composite_dev *cdev, struct usb_configuration *config) @@ -889,10 +859,10 @@ static int lookup_string( static int get_string(struct usb_composite_dev *cdev, void *buf, u16 language, int id) { + struct usb_composite_driver *composite = cdev->driver; struct usb_configuration *c; struct usb_function *f; int len; - const char *str; /* Yes, not only is USB's I18N support probably more than most * folk will ever care about ... also, it's all supported here. @@ -932,26 +902,6 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } - /* Otherwise, look up and return a specified string. First - * check if the string has not been overridden. - */ - if (cdev->manufacturer_override == id) - str = iManufacturer ?: composite->iManufacturer ?: - composite_manufacturer; - else if (cdev->product_override == id) - str = iProduct ?: composite->iProduct; - else if (cdev->serial_override == id) - str = iSerialNumber ?: composite->iSerialNumber; - else - str = NULL; - if (str) { - struct usb_gadget_strings strings = { - .language = language, - .strings = &(struct usb_string) { 0xff, str } - }; - return usb_gadget_get_string(&strings, 0xff, buf); - } - /* String IDs are device-scoped, so we look up each string * table we're told about. These lookups are infrequent; * simpler-is-better here. @@ -1003,6 +953,7 @@ int usb_string_id(struct usb_composite_dev *cdev) } return -ENODEV; } +EXPORT_SYMBOL_GPL(usb_string_id); /** * usb_string_ids() - allocate unused string IDs in batch @@ -1034,6 +985,7 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) return 0; } +EXPORT_SYMBOL_GPL(usb_string_ids_tab); /** * usb_string_ids_n() - allocate unused string IDs in batch @@ -1062,7 +1014,7 @@ int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) c->next_string_id += n; return next + 1; } - +EXPORT_SYMBOL_GPL(usb_string_ids_n); /*-------------------------------------------------------------------------*/ @@ -1359,8 +1311,8 @@ static void composite_disconnect(struct usb_gadget *gadget) spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) reset_config(cdev); - if (composite->disconnect) - composite->disconnect(cdev); + if (cdev->driver->disconnect) + cdev->driver->disconnect(cdev); spin_unlock_irqrestore(&cdev->lock, flags); } @@ -1396,35 +1348,67 @@ composite_unbind(struct usb_gadget *gadget) struct usb_configuration, list); remove_config(cdev, c); } - if (composite->unbind) - composite->unbind(cdev); + if (cdev->driver->unbind) + cdev->driver->unbind(cdev); if (cdev->req) { kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } device_remove_file(&gadget->dev, &dev_attr_suspended); + kfree(cdev->def_manufacturer); kfree(cdev); set_gadget_data(gadget, NULL); - composite = NULL; } -static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) +static void update_unchanged_dev_desc(struct usb_device_descriptor *new, + const struct usb_device_descriptor *old) { - if (!*desc) { - int ret = usb_string_id(cdev); - if (unlikely(ret < 0)) - WARNING(cdev, "failed to override string ID\n"); - else - *desc = ret; - } + __le16 idVendor; + __le16 idProduct; + __le16 bcdDevice; + u8 iSerialNumber; + u8 iManufacturer; + u8 iProduct; - return *desc; + /* + * these variables may have been set in + * usb_composite_overwrite_options() + */ + idVendor = new->idVendor; + idProduct = new->idProduct; + bcdDevice = new->bcdDevice; + iSerialNumber = new->iSerialNumber; + iManufacturer = new->iManufacturer; + iProduct = new->iProduct; + + *new = *old; + if (idVendor) + new->idVendor = idVendor; + if (idProduct) + new->idProduct = idProduct; + if (bcdDevice) + new->bcdDevice = bcdDevice; + else + new->bcdDevice = cpu_to_le16(get_default_bcdDevice()); + if (iSerialNumber) + new->iSerialNumber = iSerialNumber; + if (iManufacturer) + new->iManufacturer = iManufacturer; + if (iProduct) + new->iProduct = iProduct; } -static int composite_bind(struct usb_gadget *gadget) +static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv) +{ + return container_of(gdrv, struct usb_composite_driver, gadget_driver); +} + +static int composite_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *gdriver) { struct usb_composite_dev *cdev; + struct usb_composite_driver *composite = to_cdriver(gdriver); int status = -ENOMEM; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); @@ -1440,13 +1424,12 @@ static int composite_bind(struct usb_gadget *gadget) cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) goto fail; - cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); + cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; - cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; /* @@ -1467,49 +1450,11 @@ static int composite_bind(struct usb_gadget *gadget) * serial number), register function drivers, potentially update * power state and consumption, etc */ - status = composite_gadget_bind(cdev); + status = composite->bind(cdev); if (status < 0) goto fail; - cdev->desc = *composite->dev; - - /* standardized runtime overrides for device ID data */ - if (idVendor) - cdev->desc.idVendor = cpu_to_le16(idVendor); - else - idVendor = le16_to_cpu(cdev->desc.idVendor); - if (idProduct) - cdev->desc.idProduct = cpu_to_le16(idProduct); - else - idProduct = le16_to_cpu(cdev->desc.idProduct); - if (bcdDevice) - cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); - else - bcdDevice = le16_to_cpu(cdev->desc.bcdDevice); - - /* string overrides */ - if (iManufacturer || !cdev->desc.iManufacturer) { - if (!iManufacturer && !composite->iManufacturer && - !*composite_manufacturer) - snprintf(composite_manufacturer, - sizeof composite_manufacturer, - "%s %s with %s", - init_utsname()->sysname, - init_utsname()->release, - gadget->name); - - cdev->manufacturer_override = - override_id(cdev, &cdev->desc.iManufacturer); - } - - if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) - cdev->product_override = - override_id(cdev, &cdev->desc.iProduct); - - if (iSerialNumber || - (!cdev->desc.iSerialNumber && composite->iSerialNumber)) - cdev->serial_override = - override_id(cdev, &cdev->desc.iSerialNumber); + update_unchanged_dev_desc(&cdev->desc, composite->dev); /* has userspace failed to provide a serial number? */ if (composite->needs_serial && !cdev->desc.iSerialNumber) @@ -1546,8 +1491,8 @@ composite_suspend(struct usb_gadget *gadget) f->suspend(f); } } - if (composite->suspend) - composite->suspend(cdev); + if (cdev->driver->suspend) + cdev->driver->suspend(cdev); cdev->suspended = 1; @@ -1565,8 +1510,8 @@ composite_resume(struct usb_gadget *gadget) * suspend/resume callbacks? */ DBG(cdev, "resume\n"); - if (composite->resume) - composite->resume(cdev); + if (cdev->driver->resume) + cdev->driver->resume(cdev); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { if (f->resume) @@ -1584,13 +1529,8 @@ composite_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ -static struct usb_gadget_driver composite_driver = { -#ifdef CONFIG_USB_GADGET_SUPERSPEED - .max_speed = USB_SPEED_SUPER, -#else - .max_speed = USB_SPEED_HIGH, -#endif - +static const struct usb_gadget_driver composite_driver_template = { + .bind = composite_bind, .unbind = composite_unbind, .setup = composite_setup, @@ -1623,25 +1563,26 @@ static struct usb_gadget_driver composite_driver = { * while it was binding. That would usually be done in order to wait for * some userspace participation. */ -int usb_composite_probe(struct usb_composite_driver *driver, - int (*bind)(struct usb_composite_dev *cdev)) +int usb_composite_probe(struct usb_composite_driver *driver) { - if (!driver || !driver->dev || !bind || composite) + struct usb_gadget_driver *gadget_driver; + + if (!driver || !driver->dev || !driver->bind) return -EINVAL; if (!driver->name) driver->name = "composite"; - if (!driver->iProduct) - driver->iProduct = driver->name; - composite_driver.function = (char *) driver->name; - composite_driver.driver.name = driver->name; - composite_driver.max_speed = - min_t(u8, composite_driver.max_speed, driver->max_speed); - composite = driver; - composite_gadget_bind = bind; - - return usb_gadget_probe_driver(&composite_driver, composite_bind); + + driver->gadget_driver = composite_driver_template; + gadget_driver = &driver->gadget_driver; + + gadget_driver->function = (char *) driver->name; + gadget_driver->driver.name = driver->name; + gadget_driver->max_speed = driver->max_speed; + + return usb_gadget_probe_driver(gadget_driver); } +EXPORT_SYMBOL_GPL(usb_composite_probe); /** * usb_composite_unregister() - unregister a composite driver @@ -1652,10 +1593,9 @@ int usb_composite_probe(struct usb_composite_driver *driver, */ void usb_composite_unregister(struct usb_composite_driver *driver) { - if (composite != driver) - return; - usb_gadget_unregister_driver(&composite_driver); + usb_gadget_unregister_driver(&driver->gadget_driver); } +EXPORT_SYMBOL_GPL(usb_composite_unregister); /** * usb_composite_setup_continue() - Continue with the control transfer @@ -1692,4 +1632,60 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) spin_unlock_irqrestore(&cdev->lock, flags); } +EXPORT_SYMBOL_GPL(usb_composite_setup_continue); + +static char *composite_default_mfr(struct usb_gadget *gadget) +{ + char *mfr; + int len; + + len = snprintf(NULL, 0, "%s %s with %s", init_utsname()->sysname, + init_utsname()->release, gadget->name); + len++; + mfr = kmalloc(len, GFP_KERNEL); + if (!mfr) + return NULL; + snprintf(mfr, len, "%s %s with %s", init_utsname()->sysname, + init_utsname()->release, gadget->name); + return mfr; +} + +void usb_composite_overwrite_options(struct usb_composite_dev *cdev, + struct usb_composite_overwrite *covr) +{ + struct usb_device_descriptor *desc = &cdev->desc; + struct usb_gadget_strings *gstr = cdev->driver->strings[0]; + struct usb_string *dev_str = gstr->strings; + + if (covr->idVendor) + desc->idVendor = cpu_to_le16(covr->idVendor); + + if (covr->idProduct) + desc->idProduct = cpu_to_le16(covr->idProduct); + + if (covr->bcdDevice) + desc->bcdDevice = cpu_to_le16(covr->bcdDevice); + + if (covr->serial_number) { + desc->iSerialNumber = dev_str[USB_GADGET_SERIAL_IDX].id; + dev_str[USB_GADGET_SERIAL_IDX].s = covr->serial_number; + } + if (covr->manufacturer) { + desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id; + dev_str[USB_GADGET_MANUFACTURER_IDX].s = covr->manufacturer; + + } else if (!strlen(dev_str[USB_GADGET_MANUFACTURER_IDX].s)) { + desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id; + cdev->def_manufacturer = composite_default_mfr(cdev->gadget); + dev_str[USB_GADGET_MANUFACTURER_IDX].s = cdev->def_manufacturer; + } + + if (covr->product) { + desc->iProduct = dev_str[USB_GADGET_PRODUCT_IDX].id; + dev_str[USB_GADGET_PRODUCT_IDX].s = covr->product; + } +} +EXPORT_SYMBOL_GPL(usb_composite_overwrite_options); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 7542a72..e3a9892 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -12,6 +12,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/list.h> #include <linux/string.h> #include <linux/device.h> @@ -53,7 +54,7 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen, } return dest - (u8 *)buf; } - +EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); /** * usb_gadget_config_buf - builts a complete configuration descriptor @@ -106,6 +107,7 @@ int usb_gadget_config_buf( cp->bmAttributes |= USB_CONFIG_ATT_ONE; return len; } +EXPORT_SYMBOL_GPL(usb_gadget_config_buf); /** * usb_copy_descriptors - copy a vector of USB descriptors @@ -155,4 +157,4 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } - +EXPORT_SYMBOL_GPL(usb_copy_descriptors); diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 19d7bb0..87d1650 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -13,9 +13,6 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -/* See comments in "zero.c" */ -#include "epautoconf.c" - #ifdef CONFIG_USB_G_DBGP_SERIAL #include "u_serial.c" #endif @@ -292,7 +289,8 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget) +static int __init dbgp_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { int err, stp; @@ -402,9 +400,10 @@ fail: return err; } -static struct usb_gadget_driver dbgp_driver = { +static __refdata struct usb_gadget_driver dbgp_driver = { .function = "dbgp", .max_speed = USB_SPEED_HIGH, + .bind = dbgp_bind, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, @@ -416,7 +415,7 @@ static struct usb_gadget_driver dbgp_driver = { static int __init dbgp_init(void) { - return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind); + return usb_gadget_probe_driver(&dbgp_driver); } static void __exit dbgp_exit(void) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index afdbb1c..0f7541b 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -909,6 +909,7 @@ 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; @@ -923,6 +924,7 @@ 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; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 51f3d42..a777f7b 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/device.h> @@ -22,17 +23,6 @@ #include "gadget_chips.h" - -/* we must assign addresses for configurable endpoints (like net2280) */ -static unsigned epnum; - -// #define MANY_ENDPOINTS -#ifdef MANY_ENDPOINTS -/* more than 15 configurable endpoints */ -static unsigned in_epnum; -#endif - - /* * This should work with endpoints from controller drivers sharing the * same endpoint naming convention. By example: @@ -176,16 +166,14 @@ ep_matches ( if (isdigit (ep->name [2])) { u8 num = simple_strtoul (&ep->name [2], NULL, 10); desc->bEndpointAddress |= num; -#ifdef MANY_ENDPOINTS } else if (desc->bEndpointAddress & USB_DIR_IN) { - if (++in_epnum > 15) + if (++gadget->in_epnum > 15) return 0; - desc->bEndpointAddress = USB_DIR_IN | in_epnum; -#endif + desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; } else { - if (++epnum > 15) + if (++gadget->out_epnum > 15) return 0; - desc->bEndpointAddress |= epnum; + desc->bEndpointAddress |= gadget->out_epnum; } /* report (variable) full speed bulk maxpacket */ @@ -328,6 +316,7 @@ found_ep: ep->comp_desc = NULL; return ep; } +EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); /** * usb_ep_autoconfig() - choose an endpoint matching the @@ -367,7 +356,7 @@ struct usb_ep *usb_ep_autoconfig( { return usb_ep_autoconfig_ss(gadget, desc, NULL); } - +EXPORT_SYMBOL_GPL(usb_ep_autoconfig); /** * usb_ep_autoconfig_reset - reset endpoint autoconfig state @@ -385,9 +374,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) list_for_each_entry (ep, &gadget->ep_list, ep_list) { ep->driver_data = NULL; } -#ifdef MANY_ENDPOINTS - in_epnum = 0; -#endif - epnum = 0; + gadget->in_epnum = 0; + gadget->out_epnum = 0; } - +EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index a28f6ff..18c3f42 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -14,8 +14,6 @@ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> -#include <linux/utsname.h> - #if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS @@ -102,11 +100,6 @@ static inline bool has_rndis(void) * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_ecm.c" #include "f_subset.c" #ifdef USB_ETH_RNDIS @@ -117,6 +110,7 @@ static inline bool has_rndis(void) #include "u_ether.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. @@ -195,17 +189,10 @@ static const struct usb_descriptor_header *otg_desc[] = { NULL, }; - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = PREFIX DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = PREFIX DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -288,7 +275,6 @@ static struct usb_configuration eth_config_driver = { static int __init eth_bind(struct usb_composite_dev *cdev) { - int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; @@ -323,42 +309,15 @@ static int __init eth_bind(struct usb_composite_dev *cdev) device_desc.bNumConfigurations = 2; } - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - dev_warn(&gadget->dev, - "controller '%s' not recognized; trying %s\n", - gadget->name, - eth_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration(s); RNDIS first, if it's used */ if (has_rndis()) { @@ -372,6 +331,7 @@ static int __init eth_bind(struct usb_composite_dev *cdev) if (status < 0) goto fail; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC); @@ -388,11 +348,12 @@ static int __exit eth_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver eth_driver = { +static __refdata struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, + .bind = eth_bind, .unbind = __exit_p(eth_unbind), }; @@ -402,7 +363,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_probe(ð_driver, eth_bind); + return usb_composite_probe(ð_driver); } module_init(init); diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 30b908f..95bc94f 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -897,10 +897,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) return -ENOMEM; /* export host's Ethernet address in CDC format */ - snprintf(ecm->ethaddr, sizeof ecm->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); + snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr); ecm_string_defs[1].s = ecm->ethaddr; ecm->port.cdc_filter = DEFAULT_FILTER; diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 16a8b1c..511e527 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -10,7 +10,6 @@ */ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/module.h> #include <linux/hid.h> #include <linux/cdev.h> @@ -18,6 +17,7 @@ #include <linux/poll.h> #include <linux/uaccess.h> #include <linux/wait.h> +#include <linux/sched.h> #include <linux/usb/g_hid.h> static int major, minors; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4f1142e..3a7668b 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -213,7 +213,6 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/freezer.h> -#include <linux/utsname.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -349,7 +348,6 @@ struct fsg_config { const char *vendor_name; /* 8 characters or less */ const char *product_name; /* 16 characters or less */ - u16 release; char can_stall; }; @@ -2773,18 +2771,7 @@ buffhds_first_it: bh->next = common->buffhds; /* Prepare inquiryString */ - if (cfg->release != 0xffff) { - i = cfg->release; - } else { - i = usb_gadget_controller_number(gadget); - if (i >= 0) { - i = 0x0300 + i; - } else { - WARNING(common, "controller '%s' not recognized\n", - gadget->name); - i = 0x0399; - } - } + i = get_default_bcdDevice(); snprintf(common->inquiry_string, sizeof common->inquiry_string, "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", /* Assume product name dependent on the first LUN */ @@ -3110,7 +3097,6 @@ fsg_config_from_params(struct fsg_config *cfg, /* Let MSF use defaults */ cfg->vendor_name = 0; cfg->product_name = 0; - cfg->release = 0xffff; cfg->ops = NULL; cfg->private_data = NULL; diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 2f7e8f2..8ed1259 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/utsname.h> #include <linux/device.h> #include <sound/core.h> diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index aab8ede..b651b52 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1346,10 +1346,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) return -ENOMEM; /* export host's Ethernet address in CDC format */ - snprintf(ncm->ethaddr, sizeof ncm->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); + snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr); ncm_string_defs[1].s = ncm->ethaddr; spin_lock_init(&ncm->lock); diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 5c1b68b..3c126fd 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -795,7 +795,7 @@ static int sourcesink_setup(struct usb_configuration *c, u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); - req->length = USB_BUFSIZ; + req->length = USB_COMP_EP0_BUFSIZ; /* composite driver infrastructure handles everything except * the two control test requests. diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 21ab474..4060c0b 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -436,10 +436,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) return -ENOMEM; /* export host's Ethernet address in CDC format */ - snprintf(geth->ethaddr, sizeof geth->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); + snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr); geth_string_defs[1].s = geth->ethaddr; geth->port.cdc_filter = DEFAULT_FILTER; diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index e7cc4de..d3c6cff 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -463,7 +463,7 @@ snd_fail: return err; } -static int __devexit snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a896d73..3f7d640 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -251,26 +251,12 @@ #include <linux/freezer.h> #include <linux/utsname.h> +#include <linux/usb/composite.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include "gadget_chips.h" - - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - -/*-------------------------------------------------------------------------*/ - #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" #define DRIVER_VERSION "1 September 2010" @@ -3213,7 +3199,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) static int __init check_parameters(struct fsg_dev *fsg) { int prot; - int gcnum; /* Store the default values */ mod_data.transport_type = USB_PR_BULK; @@ -3228,16 +3213,8 @@ static int __init check_parameters(struct fsg_dev *fsg) if (gadget_is_at91(fsg->gadget)) mod_data.can_stall = 0; - if (mod_data.release == 0xffff) { // Parameter wasn't set - gcnum = usb_gadget_controller_number(fsg->gadget); - if (gcnum >= 0) - mod_data.release = 0x0300 + gcnum; - else { - WARNING(fsg, "controller '%s' not recognized\n", - fsg->gadget->name); - mod_data.release = 0x0399; - } - } + if (mod_data.release == 0xffff) + mod_data.release = get_default_bcdDevice(); prot = simple_strtol(mod_data.protocol_parm, NULL, 0); @@ -3331,7 +3308,8 @@ static int __init check_parameters(struct fsg_dev *fsg) } -static int __init fsg_bind(struct usb_gadget *gadget) +static int __init fsg_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { struct fsg_dev *fsg = the_fsg; int rc; @@ -3603,9 +3581,10 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ -static struct usb_gadget_driver fsg_driver = { +static __refdata struct usb_gadget_driver fsg_driver = { .max_speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, + .bind = fsg_bind, .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, @@ -3653,7 +3632,8 @@ static int __init fsg_init(void) if ((rc = fsg_alloc()) != 0) return rc; fsg = the_fsg; - if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0) + rc = usb_gadget_probe_driver(&fsg_driver); + if (rc != 0) kref_put(&fsg->ref, fsg_release); return rc; } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 3def828..6ae70cb 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1255,7 +1255,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) } static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int fsl_stop(struct usb_gadget_driver *driver); /* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { @@ -1951,7 +1951,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) * Called by initialization code of gadget drivers *----------------------------------------------------------------*/ static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { int retval = -ENODEV; unsigned long flags = 0; @@ -1976,7 +1976,7 @@ static int fsl_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&udc_controller->lock, flags); /* bind udc driver to gadget driver */ - retval = bind(&udc_controller->gadget); + retval = bind(&udc_controller->gadget, driver); if (retval) { VDBG("bind to %s --> %d", driver->driver.name, retval); udc_controller->gadget.dev.driver = NULL; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index cdd9454..72cd5e6 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1311,7 +1311,7 @@ static void init_controller(struct fusb300 *fusb300) static struct fusb300 *the_controller; static int fusb300_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct fusb300 *fusb300 = the_controller; int retval; @@ -1339,7 +1339,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver, goto error; } - retval = bind(&fusb300->gadget); + retval = bind(&fusb300->gadget, driver); if (retval) { pr_err("bind to driver error (%d)\n", retval); device_del(&fusb300->gadget.dev); diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index d3ace90..3953dd4 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -13,7 +13,6 @@ #define pr_fmt(fmt) "g_ffs: " fmt #include <linux/module.h> -#include <linux/utsname.h> /* * kbuild is not very cooperative with respect to linking separately @@ -22,12 +21,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS # if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS @@ -76,6 +69,8 @@ struct gfs_ffs_obj { struct ffs_data *ffs_data; }; +USB_GADGET_COMPOSITE_OPTIONS(); + static struct usb_device_descriptor gfs_dev_desc = { .bLength = sizeof gfs_dev_desc, .bDescriptorType = USB_DT_DEVICE, @@ -117,6 +112,9 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = { /* String IDs are assigned dynamically */ static struct usb_string gfs_strings[] = { + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { .s = "FunctionFS + RNDIS" }, #endif @@ -163,13 +161,13 @@ static int gfs_bind(struct usb_composite_dev *cdev); static int gfs_unbind(struct usb_composite_dev *cdev); static int gfs_do_config(struct usb_configuration *c); -static struct usb_composite_driver gfs_driver = { +static __refdata struct usb_composite_driver gfs_driver = { .name = DRIVER_NAME, .dev = &gfs_dev_desc, .strings = gfs_dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = gfs_bind, .unbind = gfs_unbind, - .iProduct = DRIVER_DESC, }; static DEFINE_MUTEX(gfs_lock); @@ -268,7 +266,7 @@ static int functionfs_ready_callback(struct ffs_data *ffs) } gfs_registered = true; - ret = usb_composite_probe(&gfs_driver, gfs_bind); + ret = usb_composite_probe(&gfs_driver); if (unlikely(ret < 0)) gfs_registered = false; @@ -357,6 +355,7 @@ static int gfs_bind(struct usb_composite_dev *cdev) ret = usb_string_ids_tab(cdev, gfs_strings); if (unlikely(ret < 0)) goto error; + gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; for (i = func_num; --i; ) { ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); @@ -369,9 +368,10 @@ static int gfs_bind(struct usb_composite_dev *cdev) for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; + int sid = USB_GADGET_FIRST_AVAIL_IDX + i; - c->c.label = gfs_strings[i].s; - c->c.iConfiguration = gfs_strings[i].id; + c->c.label = gfs_strings[sid].s; + c->c.iConfiguration = gfs_strings[sid].id; c->c.bConfigurationValue = 1 + i; c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; @@ -379,7 +379,7 @@ static int gfs_bind(struct usb_composite_dev *cdev) if (unlikely(ret < 0)) goto error_unbind; } - + usb_composite_overwrite_options(cdev, &coverwrite); return 0; error_unbind: diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index b8b3a34..bcd04bc 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -15,6 +15,8 @@ #ifndef __GADGET_CHIPS_H #define __GADGET_CHIPS_H +#include <linux/usb/gadget.h> + /* * NOTICE: the entries below are alphabetical and should be kept * that way. @@ -25,106 +27,12 @@ * If you have forgotten the alphabetical order let VIM/EMACS * do that for you. */ -#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) -#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) -#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) -#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) -#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name)) -#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name)) -#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) -#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) -#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name)) -#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) #define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) -#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name)) #define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) #define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) -#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name)) -#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) -#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) -#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) -#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) - -/** - * usb_gadget_controller_number - support bcdDevice id convention - * @gadget: the controller being driven - * - * Return a 2-digit BCD value associated with the peripheral controller, - * suitable for use as part of a bcdDevice value, or a negative error code. - * - * NOTE: this convention is purely optional, and has no meaning in terms of - * any USB specification. If you want to use a different convention in your - * gadget driver firmware -- maybe a more formal revision ID -- feel free. - * - * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) - * to change their behavior accordingly. For example it might help avoiding - * some chip bug. - */ -static inline int usb_gadget_controller_number(struct usb_gadget *gadget) -{ - if (gadget_is_net2280(gadget)) - return 0x01; - else if (gadget_is_dummy(gadget)) - return 0x02; - else if (gadget_is_pxa(gadget)) - return 0x03; - else if (gadget_is_goku(gadget)) - return 0x06; - else if (gadget_is_omap(gadget)) - return 0x08; - else if (gadget_is_pxa27x(gadget)) - return 0x11; - else if (gadget_is_s3c2410(gadget)) - return 0x12; - else if (gadget_is_at91(gadget)) - return 0x13; - else if (gadget_is_imx(gadget)) - return 0x14; - else if (gadget_is_musbhdrc(gadget)) - return 0x16; - else if (gadget_is_atmel_usba(gadget)) - return 0x18; - else if (gadget_is_fsl_usb2(gadget)) - return 0x19; - else if (gadget_is_amd5536udc(gadget)) - return 0x20; - else if (gadget_is_m66592(gadget)) - return 0x21; - else if (gadget_is_fsl_qe(gadget)) - return 0x22; - else if (gadget_is_ci13xxx_pci(gadget)) - return 0x23; - else if (gadget_is_langwell(gadget)) - return 0x24; - else if (gadget_is_r8a66597(gadget)) - return 0x25; - else if (gadget_is_s3c_hsotg(gadget)) - return 0x26; - else if (gadget_is_pch(gadget)) - return 0x27; - else if (gadget_is_ci13xxx_msm(gadget)) - return 0x28; - else if (gadget_is_renesas_usbhs(gadget)) - return 0x29; - else if (gadget_is_s3c_hsudc(gadget)) - return 0x30; - else if (gadget_is_net2272(gadget)) - return 0x31; - else if (gadget_is_dwc3(gadget)) - return 0x32; - else if (gadget_is_lpc32xx(gadget)) - return 0x33; - - return -ENOENT; -} - /** * gadget_supports_altsettings - return true if altsettings work diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 681bd03..881aab8 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -22,7 +22,6 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/utsname.h> #include <linux/module.h> #include <linux/device.h> @@ -31,16 +30,13 @@ #include <sound/rawmidi.h> #include <linux/usb/ch9.h> +#include <linux/usb/composite.h> #include <linux/usb/gadget.h> #include <linux/usb/audio.h> #include <linux/usb/midi.h> #include "gadget_chips.h" -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" #include "f_midi.c" /*-------------------------------------------------------------------------*/ @@ -51,6 +47,8 @@ MODULE_LICENSE("GPL v2"); static const char shortname[] = "g_midi"; static const char longname[] = "MIDI Gadget"; +USB_GADGET_COMPOSITE_OPTIONS(); + static int index = SNDRV_DEFAULT_IDX1; module_param(index, int, S_IRUGO); MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter."); @@ -85,9 +83,7 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports"); /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 +#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, @@ -102,8 +98,9 @@ static struct usb_device_descriptor device_desc = { }; static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = "Grey Innovation", - [STRING_PRODUCT_IDX].s = "MIDI Gadget", + [USB_GADGET_MANUFACTURER_IDX].s = "Grey Innovation", + [USB_GADGET_PRODUCT_IDX].s = "MIDI Gadget", + [USB_GADGET_SERIAL_IDX].s = "", [STRING_DESCRIPTION_IDX].s = "MIDI", { } /* end of list */ }; @@ -140,61 +137,35 @@ static int __init midi_bind_config(struct usb_configuration *c) static int __init midi_bind(struct usb_composite_dev *cdev) { - struct usb_gadget *gadget = cdev->gadget; - int gcnum, status; - - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; + int status; - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) return status; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - - midi_config.iConfiguration = status; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum < 0) { - /* gmidi is so simple (no altsettings) that - * it SHOULD NOT have problems with bulk-capable hardware. - * so warn about unrecognized controllers, don't panic. - */ - pr_warning("%s: controller '%s' not recognized\n", - __func__, gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x9999); - } else { - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - } + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id; status = usb_add_config(cdev, &midi_config, midi_bind_config); if (status < 0) return status; - + usb_composite_overwrite_options(cdev, &coverwrite); pr_info("%s\n", longname); return 0; } -static struct usb_composite_driver midi_driver = { +static __refdata struct usb_composite_driver midi_driver = { .name = (char *) longname, .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = midi_bind, .unbind = __exit_p(midi_unbind), }; static int __init midi_init(void) { - return usb_composite_probe(&midi_driver, midi_bind); + return usb_composite_probe(&midi_driver); } module_init(midi_init); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 9fd7886..51037cb 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -994,7 +994,7 @@ static int goku_get_frame(struct usb_gadget *_gadget) } static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int goku_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops goku_ops = { @@ -1348,7 +1348,7 @@ static struct goku_udc *the_controller; * the driver might get unbound. */ static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct goku_udc *dev = the_controller; int retval; @@ -1368,7 +1368,7 @@ static int goku_start(struct usb_gadget_driver *driver, driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget); + retval = bind(&dev->gadget, driver); if (retval) { DBG(dev, "bind to driver %s --> error %d\n", driver->driver.name, retval); diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index 3493adf..74130f6 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -15,7 +15,10 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/list.h> +#include <linux/module.h> +#include <linux/usb/composite.h> +#include "gadget_chips.h" #define DRIVER_DESC "HID Gadget" #define DRIVER_VERSION "2010/03/16" @@ -33,12 +36,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_hid.c" @@ -50,6 +47,7 @@ struct hidg_func_node { static LIST_HEAD(hidg_func_list); /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, @@ -92,15 +90,10 @@ static const struct usb_descriptor_header *otg_desc[] = { /* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -150,7 +143,7 @@ static int __init hid_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; struct list_head *tmp; - int status, gcnum, funcs = 0; + int status, funcs = 0; list_for_each(tmp, &hidg_func_list) funcs++; @@ -163,38 +156,22 @@ static int __init hid_bind(struct usb_composite_dev *cdev) if (status < 0) return status; - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else - device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); - - /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) return status; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration */ status = usb_add_config(cdev, &config_driver, do_config); if (status < 0) return status; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); return 0; @@ -242,11 +219,12 @@ static int __devexit hidg_plat_driver_remove(struct platform_device *pdev) /****************************** Some noise ******************************/ -static struct usb_composite_driver hidg_driver = { +static __refdata struct usb_composite_driver hidg_driver = { .name = "g_hid", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = hid_bind, .unbind = __exit_p(hid_unbind), }; @@ -272,7 +250,7 @@ static int __init hidg_init(void) if (status < 0) return status; - status = usb_composite_probe(&hidg_driver, hid_bind); + status = usb_composite_probe(&hidg_driver); if (status < 0) platform_driver_unregister(&hidg_plat_driver); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index e58b164..4bb6d53 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -828,7 +828,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (value == 0) data->state = STATE_EP_ENABLED; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ ep->desc = &data->hs_desc; @@ -836,7 +835,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (value == 0) data->state = STATE_EP_ENABLED; break; -#endif default: DBG(data->dev, "unconnected, %s init abandoned\n", data->name); @@ -1324,7 +1322,6 @@ static const struct file_operations ep0_io_operations = { * Unrecognized ep0 requests may be handled in user space. */ -#ifdef CONFIG_USB_GADGET_DUALSPEED static void make_qualifier (struct dev_data *dev) { struct usb_qualifier_descriptor qual; @@ -1347,7 +1344,6 @@ static void make_qualifier (struct dev_data *dev) memcpy (dev->rbuf, &qual, sizeof qual); } -#endif static int config_buf (struct dev_data *dev, u8 type, unsigned index) @@ -1427,7 +1423,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket; req->buf = dev->dev; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!dev->hs_config) break; @@ -1437,7 +1432,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; case USB_DT_OTHER_SPEED_CONFIG: // FALLTHROUGH -#endif case USB_DT_CONFIG: value = config_buf (dev, w_value >> 8, @@ -1685,8 +1679,8 @@ gadgetfs_unbind (struct usb_gadget *gadget) static struct dev_data *the_device; -static int -gadgetfs_bind (struct usb_gadget *gadget) +static int gadgetfs_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { struct dev_data *dev = the_device; @@ -1763,12 +1757,8 @@ gadgetfs_suspend (struct usb_gadget *gadget) } static struct usb_gadget_driver gadgetfs_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .max_speed = USB_SPEED_HIGH, -#else - .max_speed = USB_SPEED_FULL, -#endif .function = (char *) driver_desc, + .bind = gadgetfs_bind, .unbind = gadgetfs_unbind, .setup = gadgetfs_setup, .disconnect = gadgetfs_disconnect, @@ -1783,7 +1773,8 @@ static struct usb_gadget_driver gadgetfs_driver = { static void gadgetfs_nop(struct usb_gadget *arg) { } -static int gadgetfs_probe (struct usb_gadget *gadget) +static int gadgetfs_probe(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { CHIP = gadget->name; return -EISNAM; @@ -1791,6 +1782,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget) static struct usb_gadget_driver probe_driver = { .max_speed = USB_SPEED_HIGH, + .bind = gadgetfs_probe, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, @@ -1900,7 +1892,12 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* triggers gadgetfs_bind(); then we can enumerate. */ spin_unlock_irq (&dev->lock); - value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind); + if (dev->hs_config) + gadgetfs_driver.max_speed = USB_SPEED_HIGH; + else + gadgetfs_driver.max_speed = USB_SPEED_FULL; + + value = usb_gadget_probe_driver(&gadgetfs_driver); if (value != 0) { kfree (dev->buf); dev->buf = NULL; @@ -2039,7 +2036,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) return -ESRCH; /* fake probe to determine $CHIP */ - (void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe); + usb_gadget_probe_driver(&probe_driver); if (!CHIP) return -ENODEV; diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index f1ec99e..f696fb9 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -141,8 +141,6 @@ struct lpc32xx_ep { u32 totalints; bool wedge; - - const struct usb_endpoint_descriptor *desc; }; /* @@ -556,10 +554,8 @@ static int proc_udc_show(struct seq_file *s, void *unused) if (udc->enabled && udc->vbus) { proc_ep_show(s, &udc->ep[0]); - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) - proc_ep_show(s, ep); - } + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) + proc_ep_show(s, ep); } spin_unlock_irqrestore(&udc->lock, flags); @@ -1453,7 +1449,6 @@ static void udc_reinit(struct lpc32xx_udc *udc) if (i != 0) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->desc = NULL; ep->ep.maxpacket = ep->maxpacket; INIT_LIST_HEAD(&ep->queue); ep->req_pending = 0; @@ -1515,7 +1510,7 @@ static void nuke(struct lpc32xx_ep *ep, int status) done(ep, req, status); } - if (ep->desc && status == -ESHUTDOWN) { + if (status == -ESHUTDOWN) { uda_disable_hwepint(ep->udc, ep->hwep_num); udc_disable_hwep(ep->udc, ep->hwep_num); } @@ -1658,9 +1653,6 @@ static int lpc32xx_ep_disable(struct usb_ep *_ep) nuke(ep, -ESHUTDOWN); - /* restore the endpoint's pristine config */ - ep->desc = NULL; - /* Clear all DMA statuses for this EP */ udc_ep_dma_disable(udc, ep->hwep_num); writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); @@ -1696,7 +1688,7 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep, unsigned long flags; /* Verify EP data */ - if ((!_ep) || (!ep) || (!desc) || (ep->desc) || + if ((!_ep) || (!ep) || (!desc) || (desc->bDescriptorType != USB_DT_ENDPOINT)) { dev_dbg(udc->dev, "bad ep or descriptor\n"); return -EINVAL; @@ -1754,7 +1746,6 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep, /* Initialize endpoint to match the selected descriptor */ ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; - ep->desc = desc; ep->ep.maxpacket = maxpacket; /* Map hardware endpoint from base and direction */ @@ -1837,7 +1828,7 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep, udc = ep->udc; - if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) { + if (!_ep) { dev_dbg(udc->dev, "invalid ep\n"); return -EINVAL; } @@ -1976,7 +1967,7 @@ static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) struct lpc32xx_udc *udc = ep->udc; unsigned long flags; - if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1)) + if ((!ep) || (ep->hwep_num <= 1)) return -EINVAL; /* Don't halt an IN EP */ @@ -2262,7 +2253,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex) case USB_RECIP_ENDPOINT: tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc)) + if ((tmp == 0) || (tmp >= NUM_ENDPOINTS)) return -EOPNOTSUPP; if (wIndex & USB_DIR_IN) { @@ -2599,9 +2590,8 @@ static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) return 0; } -static int lpc32xx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int lpc32xx_stop(struct usb_gadget_driver *driver); +static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *); +static int lpc32xx_stop(struct usb_gadget *, struct usb_gadget_driver *); static const struct usb_gadget_ops lpc32xx_udc_ops = { .get_frame = lpc32xx_get_frame, @@ -2609,8 +2599,8 @@ static const struct usb_gadget_ops lpc32xx_udc_ops = { .set_selfpowered = lpc32xx_set_selfpowered, .vbus_session = lpc32xx_vbus_session, .pullup = lpc32xx_pullup, - .start = lpc32xx_start, - .stop = lpc32xx_stop, + .udc_start = lpc32xx_start, + .udc_stop = lpc32xx_stop, }; static void nop_release(struct device *dev) @@ -2618,10 +2608,9 @@ static void nop_release(struct device *dev) /* nothing to free */ } -static struct lpc32xx_udc controller = { +static const struct lpc32xx_udc controller_template = { .gadget = { .ops = &lpc32xx_udc_ops, - .ep0 = &controller.ep[0].ep, .name = driver_name, .dev = { .init_name = "gadget", @@ -2633,7 +2622,6 @@ static struct lpc32xx_udc controller = { .name = "ep0", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 0, .hwep_num = 0, /* Can be 0 or 1, has special handling */ @@ -2645,7 +2633,6 @@ static struct lpc32xx_udc controller = { .name = "ep1-int", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 2, .hwep_num = 0, /* 2 or 3, will be set later */ @@ -2657,7 +2644,6 @@ static struct lpc32xx_udc controller = { .name = "ep2-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 4, .hwep_num = 0, /* 4 or 5, will be set later */ @@ -2669,7 +2655,6 @@ static struct lpc32xx_udc controller = { .name = "ep3-iso", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 1023, .hwep_num_base = 6, .hwep_num = 0, /* 6 or 7, will be set later */ @@ -2681,7 +2666,6 @@ static struct lpc32xx_udc controller = { .name = "ep4-int", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 8, .hwep_num = 0, /* 8 or 9, will be set later */ @@ -2693,7 +2677,6 @@ static struct lpc32xx_udc controller = { .name = "ep5-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 10, .hwep_num = 0, /* 10 or 11, will be set later */ @@ -2705,7 +2688,6 @@ static struct lpc32xx_udc controller = { .name = "ep6-iso", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 1023, .hwep_num_base = 12, .hwep_num = 0, /* 12 or 13, will be set later */ @@ -2717,7 +2699,6 @@ static struct lpc32xx_udc controller = { .name = "ep7-int", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 14, .hwep_num = 0, @@ -2729,7 +2710,6 @@ static struct lpc32xx_udc controller = { .name = "ep8-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 16, .hwep_num = 0, @@ -2741,7 +2721,6 @@ static struct lpc32xx_udc controller = { .name = "ep9-iso", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 1023, .hwep_num_base = 18, .hwep_num = 0, @@ -2753,7 +2732,6 @@ static struct lpc32xx_udc controller = { .name = "ep10-int", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 20, .hwep_num = 0, @@ -2765,7 +2743,6 @@ static struct lpc32xx_udc controller = { .name = "ep11-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 22, .hwep_num = 0, @@ -2777,7 +2754,6 @@ static struct lpc32xx_udc controller = { .name = "ep12-iso", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 1023, .hwep_num_base = 24, .hwep_num = 0, @@ -2789,7 +2765,6 @@ static struct lpc32xx_udc controller = { .name = "ep13-int", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 26, .hwep_num = 0, @@ -2801,7 +2776,6 @@ static struct lpc32xx_udc controller = { .name = "ep14-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 64, .hwep_num_base = 28, .hwep_num = 0, @@ -2813,7 +2787,6 @@ static struct lpc32xx_udc controller = { .name = "ep15-bulk", .ops = &lpc32xx_ep_ops, }, - .udc = &controller, .maxpacket = 1023, .hwep_num_base = 30, .hwep_num = 0, @@ -2987,14 +2960,13 @@ static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) return IRQ_HANDLED; } -static int lpc32xx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int lpc32xx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct lpc32xx_udc *udc = &controller; - int retval, i; + struct lpc32xx_udc *udc = to_udc(gadget); + int i; - if (!driver || driver->max_speed < USB_SPEED_FULL || - !bind || !driver->setup) { + if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) { dev_err(udc->dev, "bad parameter.\n"); return -EINVAL; } @@ -3011,18 +2983,6 @@ static int lpc32xx_start(struct usb_gadget_driver *driver, udc->selfpowered = 1; udc->vbus = 0; - retval = bind(&udc->gadget); - if (retval) { - dev_err(udc->dev, "bind() returned %d\n", retval); - udc->enabled = 0; - udc->selfpowered = 0; - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return retval; - } - - dev_dbg(udc->dev, "bound to %s\n", driver->driver.name); - /* Force VBUS process once to check for cable insertion */ udc->last_vbus = udc->vbus = 0; schedule_work(&udc->vbus_job); @@ -3034,22 +2994,19 @@ static int lpc32xx_start(struct usb_gadget_driver *driver, return 0; } -static int lpc32xx_stop(struct usb_gadget_driver *driver) +static int lpc32xx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { int i; - struct lpc32xx_udc *udc = &controller; + struct lpc32xx_udc *udc = to_udc(gadget); - if (!driver || driver != udc->driver || !driver->unbind) + if (!driver || driver != udc->driver) return -EINVAL; - /* Disable USB pullup */ - isp1301_pullup_enable(udc, 0, 1); - for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) disable_irq(udc->udp_irq[i]); if (udc->clocked) { - spin_lock(&udc->lock); stop_activity(udc); spin_unlock(&udc->lock); @@ -3069,20 +3026,16 @@ static int lpc32xx_stop(struct usb_gadget_driver *driver) } udc->enabled = 0; - pullup(udc, 0); - - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; - dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name); return 0; } static void lpc32xx_udc_shutdown(struct platform_device *dev) { /* Force disconnect on reboot */ - struct lpc32xx_udc *udc = &controller; + struct lpc32xx_udc *udc = platform_get_drvdata(dev); pullup(udc, 0); } @@ -3120,12 +3073,21 @@ static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; static int __init lpc32xx_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct lpc32xx_udc *udc = &controller; + struct lpc32xx_udc *udc; int retval, i; struct resource *res; dma_addr_t dma_handle; struct device_node *isp1301_node; + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + return -ENOMEM; + + memcpy(udc, &controller_template, sizeof(*udc)); + for (i = 0; i <= 15; i++) + udc->ep[i].udc = udc; + udc->gadget.ep0 = &udc->ep[0].ep; + /* init software state */ udc->gadget.dev.parent = dev; udc->pdev = pdev; @@ -3140,8 +3102,10 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) } udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); - if (!udc->isp1301_i2c_client) - return -EPROBE_DEFER; + if (!udc->isp1301_i2c_client) { + retval = -EPROBE_DEFER; + goto phy_fail; + } dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", udc->isp1301_i2c_client->addr); @@ -3160,8 +3124,10 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) * IORESOURCE_IRQ, USB transceiver interrupt number */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; + if (!res) { + retval = -ENXIO; + goto resource_fail; + } spin_lock_init(&udc->lock); @@ -3171,7 +3137,8 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) if (udc->udp_irq[i] < 0) { dev_err(udc->dev, "irq resource %d not available!\n", i); - return udc->udp_irq[i]; + retval = udc->udp_irq[i]; + goto irq_fail; } } @@ -3179,7 +3146,8 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) udc->io_p_size = resource_size(res); if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) { dev_err(udc->dev, "someone's using UDC memory\n"); - return -EBUSY; + retval = -EBUSY; + goto request_mem_region_fail; } udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size); @@ -3208,7 +3176,7 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg"); if (IS_ERR(udc->usb_otg_clk)) { dev_err(udc->dev, "failed to acquire USB otg clock\n"); - retval = PTR_ERR(udc->usb_slv_clk); + retval = PTR_ERR(udc->usb_otg_clk); goto usb_otg_clk_get_fail; } @@ -3376,7 +3344,11 @@ pll_get_fail: io_map_fail: release_mem_region(udc->io_p_start, udc->io_p_size); dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); - +request_mem_region_fail: +irq_fail: +resource_fail: +phy_fail: + kfree(udc); return retval; } @@ -3414,6 +3386,7 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev) clk_put(udc->usb_pll_clk); iounmap(udc->udp_baseaddr); release_mem_region(udc->io_p_start, udc->io_p_size); + kfree(udc); return 0; } diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index cf6bd62..b6401f1 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1466,7 +1466,7 @@ static struct usb_ep_ops m66592_ep_ops = { static struct m66592 *the_controller; static int m66592_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct m66592 *m66592 = the_controller; int retval; @@ -1492,7 +1492,7 @@ static int m66592_start(struct usb_gadget_driver *driver, goto error; } - retval = bind(&m66592->gadget); + retval = bind(&m66592->gadget, driver); if (retval) { pr_err("bind to driver error (%d)\n", retval); device_del(&m66592->gadget.dev); diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 1f376eb..080e577 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -29,9 +29,8 @@ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/usb/ch9.h> - +#include <linux/module.h> /*-------------------------------------------------------------------------*/ @@ -47,14 +46,10 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" #include "f_mass_storage.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); static struct usb_device_descriptor msg_device_desc = { .bLength = sizeof msg_device_desc, @@ -85,6 +80,22 @@ static const struct usb_descriptor_header *otg_desc[] = { NULL, }; +static struct usb_string strings_dev[] = { + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; /****************************** Configurations ******************************/ @@ -143,10 +154,15 @@ static int __init msg_bind(struct usb_composite_dev *cdev) { int status; - status = usb_add_config(cdev, &msg_config_driver, msg_do_config); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) return status; + msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + status = usb_add_config(cdev, &msg_config_driver, msg_do_config); + if (status < 0) + return status; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&cdev->gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); set_bit(0, &msg_registered); @@ -156,12 +172,13 @@ static int __init msg_bind(struct usb_composite_dev *cdev) /****************************** Some noise ******************************/ -static struct usb_composite_driver msg_driver = { +static __refdata struct usb_composite_driver msg_driver = { .name = "g_mass_storage", .dev = &msg_device_desc, - .iProduct = DRIVER_DESC, .max_speed = USB_SPEED_SUPER, .needs_serial = 1, + .strings = dev_strings, + .bind = msg_bind, }; MODULE_DESCRIPTION(DRIVER_DESC); @@ -170,7 +187,7 @@ MODULE_LICENSE("GPL"); static int __init msg_init(void) { - return usb_composite_probe(&msg_driver, msg_bind); + return usb_composite_probe(&msg_driver); } module_init(msg_init); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index c37fb33..88472bf 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -14,10 +14,8 @@ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/module.h> - #if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS #endif @@ -42,12 +40,6 @@ MODULE_LICENSE("GPL"); * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_mass_storage.c" #include "u_serial.c" @@ -61,7 +53,7 @@ MODULE_LICENSE("GPL"); #endif #include "u_ether.c" - +USB_GADGET_COMPOSITE_OPTIONS(); /***************************** Device Descriptor ****************************/ @@ -112,21 +104,16 @@ static const struct usb_descriptor_header *otg_desc[] = { enum { -#ifdef CONFIG_USB_G_MULTI_RNDIS - MULTI_STRING_RNDIS_CONFIG_IDX, -#endif -#ifdef CONFIG_USB_G_MULTI_CDC + MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX, MULTI_STRING_CDC_CONFIG_IDX, -#endif }; static struct usb_string strings_dev[] = { -#ifdef CONFIG_USB_G_MULTI_RNDIS + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS", -#endif -#ifdef CONFIG_USB_G_MULTI_CDC [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM", -#endif { } /* end of list */ }; @@ -260,7 +247,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev) static int __ref multi_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; - int status, gcnum; + int status; if (!can_support_ecm(cdev->gadget)) { dev_err(&gadget->dev, "controller '%s' not usable\n", @@ -288,19 +275,11 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) } } - /* set bcdDevice */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - } else { - WARNING(cdev, "controller '%s' not recognized\n", gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); - } - /* allocate string IDs */ status = usb_string_ids_tab(cdev, strings_dev); if (unlikely(status < 0)) goto fail2; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register configurations */ status = rndis_config_register(cdev); @@ -310,6 +289,7 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) status = cdc_config_register(cdev); if (unlikely(status < 0)) goto fail2; + usb_composite_overwrite_options(cdev, &coverwrite); /* we're done */ dev_info(&gadget->dev, DRIVER_DESC "\n"); @@ -338,20 +318,20 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev) /****************************** Some noise ******************************/ -static struct usb_composite_driver multi_driver = { +static __refdata struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = multi_bind, .unbind = __exit_p(multi_unbind), - .iProduct = DRIVER_DESC, .needs_serial = 1, }; static int __init multi_init(void) { - return usb_composite_probe(&multi_driver, multi_bind); + return usb_composite_probe(&multi_driver); } module_init(multi_init); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 75db2c3..ea45224 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -51,9 +51,8 @@ #define EPSTATUS_TIMEOUT 10000 #define PRIME_TIMEOUT 10000 #define READSAFE_TIMEOUT 1000 -#define DTD_TIMEOUT 1000 -#define LOOPS_USEC_SHIFT 4 +#define LOOPS_USEC_SHIFT 1 #define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) #define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) @@ -64,7 +63,6 @@ static const char driver_desc[] = DRIVER_DESC; /* controller device global variable */ static struct mv_udc *the_controller; -int mv_usb_otgsc; static void nuke(struct mv_ep *ep, int status); static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); @@ -357,17 +355,24 @@ done: return retval; } - static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, dma_addr_t *dma, int *is_last) { - u32 temp; struct mv_dtd *dtd; struct mv_udc *udc; + struct mv_dqh *dqh; + u32 temp, mult = 0; /* how big will this transfer be? */ - *length = min(req->req.length - req->req.actual, - (unsigned)EP_MAX_LENGTH_TRANSFER); + if (usb_endpoint_xfer_isoc(req->ep->ep.desc)) { + dqh = req->ep->dqh; + mult = (dqh->max_packet_length >> EP_QUEUE_HEAD_MULT_POS) + & 0x3; + *length = min(req->req.length - req->req.actual, + (unsigned)(mult * req->ep->ep.maxpacket)); + } else + *length = min(req->req.length - req->req.actual, + (unsigned)EP_MAX_LENGTH_TRANSFER); udc = req->ep->udc; @@ -375,7 +380,7 @@ static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, * Be careful that no _GFP_HIGHMEM is set, * or we can not use dma_to_virt */ - dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma); + dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, dma); if (dtd == NULL) return dtd; @@ -409,6 +414,8 @@ static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, if (*is_last && !req->req.no_interrupt) temp |= DTD_IOC; + temp |= mult << 10; + dtd->size_ioc_sts = temp; mb(); @@ -708,6 +715,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) struct mv_req *req = container_of(_req, struct mv_req, req); struct mv_udc *udc = ep->udc; unsigned long flags; + int retval; /* catch various bogus parameters */ if (!_req || !req->req.complete || !req->req.buf @@ -719,10 +727,6 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) dev_err(&udc->dev->dev, "%s, bad ep", __func__); return -EINVAL; } - if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - } udc = ep->udc; if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) @@ -755,15 +759,17 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* build dtds and push them to device queue */ if (!req_to_dtd(req)) { - int retval; retval = queue_dtd(ep, req); if (retval) { spin_unlock_irqrestore(&udc->lock, flags); - return retval; + dev_err(&udc->dev->dev, "Failed to queue dtd\n"); + goto err_unmap_dma; } } else { spin_unlock_irqrestore(&udc->lock, flags); - return -ENOMEM; + dev_err(&udc->dev->dev, "Failed to dma_pool_alloc\n"); + retval = -ENOMEM; + goto err_unmap_dma; } /* Update ep0 state */ @@ -775,6 +781,22 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) spin_unlock_irqrestore(&udc->lock, flags); return 0; + +err_unmap_dma: + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ((ep_dir(ep) == EP_DIR_IN) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE)); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ((ep_dir(ep) == EP_DIR_IN) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE)); + + return retval; } static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req) @@ -1065,7 +1087,7 @@ static int udc_reset(struct mv_udc *udc) tmp |= USBMODE_CTRL_MODE_DEVICE; /* turn setup lockout off, require setup tripwire in usbcmd */ - tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE; + tmp |= USBMODE_SETUP_LOCK_OFF; writel(tmp, &udc->op_regs->usbmode); @@ -1199,12 +1221,16 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) udc_start(udc); } } else if (udc->driver && udc->softconnect) { + if (!udc->active) + goto out; + /* stop all the transfer in queue*/ stop_activity(udc, udc->driver); udc_stop(udc); mv_udc_disable(udc); } +out: spin_unlock_irqrestore(&udc->lock, flags); return retval; } @@ -1243,7 +1269,7 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) } static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int mv_udc_stop(struct usb_gadget_driver *driver); /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops mv_ops = { @@ -1348,7 +1374,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) } static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct mv_udc *udc = the_controller; int retval = 0; @@ -1373,7 +1399,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&udc->lock, flags); - retval = bind(&udc->gadget); + retval = bind(&udc->gadget, driver); if (retval) { dev_err(&udc->dev->dev, "bind to driver %s --> %d\n", driver->driver.name, retval); @@ -1499,15 +1525,17 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) } /* prime the data phase */ - if (!req_to_dtd(req)) + if (!req_to_dtd(req)) { retval = queue_dtd(ep, req); - else{ /* no mem */ + if (retval) { + dev_err(&udc->dev->dev, + "Failed to queue dtd when prime status\n"); + goto out; + } + } else{ /* no mem */ retval = -ENOMEM; - goto out; - } - - if (retval) { - dev_err(&udc->dev->dev, "response error on GET_STATUS request\n"); + dev_err(&udc->dev->dev, + "Failed to dma_pool_alloc when prime status\n"); goto out; } @@ -1515,6 +1543,15 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) return 0; out: + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + ((ep_dir(ep) == EP_DIR_IN) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE)); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + return retval; } @@ -2468,9 +2505,11 @@ static void mv_udc_shutdown(struct platform_device *dev) u32 mode; /* reset controller mode to IDLE */ + mv_udc_enable(udc); mode = readl(&udc->op_regs->usbmode); mode &= ~3; writel(mode, &udc->op_regs->usbmode); + mv_udc_disable(udc); } static struct platform_driver udc_driver = { diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index 8953003..a22ad9a 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -20,8 +20,8 @@ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> -#include <linux/utsname.h> - +#include <linux/module.h> +#include <linux/usb/composite.h> #include "u_ether.h" @@ -36,11 +36,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_ncm.c" #include "u_ether.c" @@ -57,6 +52,7 @@ #define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, @@ -97,17 +93,11 @@ static const struct usb_descriptor_header *otg_desc[] = { NULL, }; - /* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 - -static char manufacturer[50]; - static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; @@ -149,7 +139,6 @@ static struct usb_configuration ncm_config_driver = { static int __init gncm_bind(struct usb_composite_dev *cdev) { - int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; @@ -158,48 +147,22 @@ static int __init gncm_bind(struct usb_composite_dev *cdev) if (status < 0) return status; - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - dev_warn(&gadget->dev, - "controller '%s' not recognized; trying %s\n", - gadget->name, - ncm_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; status = usb_add_config(cdev, &ncm_config_driver, ncm_do_config); if (status < 0) goto fail; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", DRIVER_DESC); return 0; @@ -215,11 +178,12 @@ static int __exit gncm_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver ncm_driver = { +static __refdata struct usb_composite_driver ncm_driver = { .name = "g_ncm", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = gncm_bind, .unbind = __exit_p(gncm_unbind), }; @@ -229,7 +193,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_probe(&ncm_driver, gncm_bind); + return usb_composite_probe(&ncm_driver); } module_init(init); diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index c7fb772..661600a 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -16,7 +16,6 @@ */ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/device.h> #include "u_serial.h" @@ -38,11 +37,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "u_serial.c" #include "f_acm.c" #include "f_ecm.c" @@ -52,23 +46,23 @@ #include "u_ether.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); #define NOKIA_VENDOR_ID 0x0421 /* Nokia */ #define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 +#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static char manufacturer_nokia[] = "Nokia"; static const char product_nokia[] = NOKIA_LONG_NAME; static const char description_nokia[] = "PC-Suite Configuration"; static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer_nokia, - [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME, + [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia, + [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME, + [USB_GADGET_SERIAL_IDX].s = "", [STRING_DESCRIPTION_IDX].s = description_nokia, { } /* end of list */ }; @@ -90,6 +84,7 @@ static struct usb_device_descriptor device_desc = { .bDeviceClass = USB_CLASS_COMM, .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), + .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ .bNumConfigurations = 1, @@ -151,7 +146,6 @@ static struct usb_configuration nokia_config_100ma_driver = { static int __init nokia_bind(struct usb_composite_dev *cdev) { - int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; @@ -167,41 +161,17 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) if (status < 0) goto err_ether; - status = usb_string_id(cdev); - if (status < 0) - goto err_usb; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto err_usb; - strings_dev[STRING_PRODUCT_IDX].id = status; - - device_desc.iProduct = status; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - goto err_usb; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + status = strings_dev[STRING_DESCRIPTION_IDX].id; nokia_config_500ma_driver.iConfiguration = status; nokia_config_100ma_driver.iConfiguration = status; - /* set up other descriptors */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM); - else { - /* this should only work with hw that supports altsettings - * and several endpoints, anything else, panic. - */ - pr_err("nokia_bind: controller '%s' not recognized\n", - gadget->name); + if (!gadget_supports_altsettings(gadget)) goto err_usb; - } /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, @@ -214,6 +184,7 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) if (status < 0) goto err_usb; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); return 0; @@ -237,17 +208,18 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver nokia_driver = { +static __refdata struct usb_composite_driver nokia_driver = { .name = "g_nokia", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = nokia_bind, .unbind = __exit_p(nokia_unbind), }; static int __init nokia_init(void) { - return usb_composite_probe(&nokia_driver, nokia_bind); + return usb_composite_probe(&nokia_driver); } module_init(nokia_init); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index f9132ad..2a4749c 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1308,7 +1308,7 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on) } static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int omap_udc_stop(struct usb_gadget_driver *driver); static struct usb_gadget_ops omap_gadget_ops = { @@ -2040,7 +2040,7 @@ static inline int machine_without_vbus_sense(void) } static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { int status = -ENODEV; struct omap_ep *ep; @@ -2082,7 +2082,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver, if (udc->dc_clk != NULL) omap_udc_enable_clock(1); - status = bind(&udc->gadget); + status = bind(&udc->gadget, driver); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); udc->gadget.dev.driver = NULL; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index f4fb71c..6490c00 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -1236,7 +1236,7 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) } static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int pch_udc_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops pch_udc_ops = { .get_frame = pch_udc_pcd_get_frame, @@ -2982,7 +2982,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) } static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct pch_udc_dev *dev = pch_udc; int retval; @@ -3006,7 +3006,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver, dev->gadget.dev.driver = &driver->driver; /* Invoke the bind routine of the gadget driver */ - retval = bind(&dev->gadget); + retval = bind(&dev->gadget, driver); if (retval) { dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n", diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index f1f9290..e156e3f 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -22,7 +22,6 @@ #include <linux/timer.h> #include <linux/list.h> #include <linux/interrupt.h> -#include <linux/utsname.h> #include <linux/device.h> #include <linux/moduleparam.h> #include <linux/fs.h> @@ -38,25 +37,13 @@ #include <asm/unaligned.h> #include <linux/usb/ch9.h> +#include <linux/usb/composite.h> #include <linux/usb/gadget.h> #include <linux/usb/g_printer.h> #include "gadget_chips.h" - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - -/*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_DESC "Printer Gadget" #define DRIVER_VERSION "2007 OCT 06" @@ -120,8 +107,7 @@ static struct printer_dev usb_printer_gadget; * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -static char *iSerialNum; -module_param(iSerialNum, charp, S_IRUGO); +module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNum, "1"); static char *iPNPstring; @@ -141,18 +127,10 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR); * descriptors are built on demand. */ -#define STRING_MANUFACTURER 1 -#define STRING_PRODUCT 2 -#define STRING_SERIALNUM 3 - /* holds our biggest descriptor */ #define USB_DESC_BUFSIZE 256 #define USB_BUFSIZE 8192 -/* This device advertises one configuration. */ -#define DEV_CONFIG_VALUE 1 -#define PRINTER_INTERFACE 0 - static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, @@ -162,16 +140,12 @@ static struct usb_device_descriptor device_desc = { .bDeviceProtocol = 0, .idVendor = cpu_to_le16(PRINTER_VENDOR_NUM), .idProduct = cpu_to_le16(PRINTER_PRODUCT_NUM), - .iManufacturer = STRING_MANUFACTURER, - .iProduct = STRING_PRODUCT, - .iSerialNumber = STRING_SERIALNUM, .bNumConfigurations = 1 }; static struct usb_interface_descriptor intf_desc = { .bLength = sizeof intf_desc, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = PRINTER_INTERFACE, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_PRINTER, .bInterfaceSubClass = 1, /* Printer Sub-Class */ @@ -252,7 +226,6 @@ static const struct usb_descriptor_header *otg_desc[] = { /* descriptors that are built on-demand */ -static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; static char serial_num [40] = "1"; static char pnp_string [1024] = @@ -260,9 +233,9 @@ static char pnp_string [1024] = /* static strings, in UTF-8 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, manufacturer, }, - { STRING_PRODUCT, product_desc, }, - { STRING_SERIALNUM, serial_num, }, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = product_desc, + [USB_GADGET_SERIAL_IDX].s = serial_num, { } /* end of list */ }; @@ -871,25 +844,13 @@ static int set_interface(struct printer_dev *dev, unsigned number) int result = 0; /* Free the current interface */ - switch (dev->interface) { - case PRINTER_INTERFACE: - printer_reset_interface(dev); - break; - } + printer_reset_interface(dev); - switch (number) { - case PRINTER_INTERFACE: - result = set_printer_interface(dev); - if (result) { - printer_reset_interface(dev); - } else { - dev->interface = PRINTER_INTERFACE; - } - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - } + result = set_printer_interface(dev); + if (result) + printer_reset_interface(dev); + else + dev->interface = number; if (!result) INFO(dev, "Using interface %x\n", number); @@ -972,7 +933,7 @@ static int printer_func_setup(struct usb_function *f, switch (ctrl->bRequest) { case 0: /* Get the IEEE-1284 PNP String */ /* Only one printer interface is supported. */ - if ((wIndex>>8) != PRINTER_INTERFACE) + if ((wIndex>>8) != dev->interface) break; value = (pnp_string[0]<<8)|pnp_string[1]; @@ -983,7 +944,7 @@ static int printer_func_setup(struct usb_function *f, case 1: /* Get Port Status */ /* Only one printer interface is supported. */ - if (wIndex != PRINTER_INTERFACE) + if (wIndex != dev->interface) break; *(u8 *)req->buf = dev->printer_status; @@ -992,7 +953,7 @@ static int printer_func_setup(struct usb_function *f, case 2: /* Soft Reset */ /* Only one printer interface is supported. */ - if (wIndex != PRINTER_INTERFACE) + if (wIndex != dev->interface) break; printer_soft_reset(dev); @@ -1020,6 +981,37 @@ unknown: static int __init printer_func_bind(struct usb_configuration *c, struct usb_function *f) { + struct printer_dev *dev = container_of(f, struct printer_dev, function); + struct usb_composite_dev *cdev = c->cdev; + struct usb_ep *in_ep, *out_ep; + int id; + + id = usb_interface_id(c, f); + if (id < 0) + return id; + intf_desc.bInterfaceNumber = id; + + /* all we really need is bulk IN/OUT */ + in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc); + if (!in_ep) { +autoconf_fail: + dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n", + cdev->gadget->name); + return -ENODEV; + } + in_ep->driver_data = in_ep; /* claim */ + + out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc); + if (!out_ep) + goto autoconf_fail; + out_ep->driver_data = out_ep; /* claim */ + + /* assumes that all endpoints are dual-speed */ + hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; + hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + + dev->in_ep = in_ep; + dev->out_ep = out_ep; return 0; } @@ -1035,7 +1027,8 @@ static int printer_func_set_alt(struct usb_function *f, int ret = -ENOTSUPP; if (!alt) - ret = set_interface(dev, PRINTER_INTERFACE); + ret = set_interface(dev, intf); + return ret; } @@ -1107,13 +1100,13 @@ static int __init printer_bind_config(struct usb_configuration *c) { struct usb_gadget *gadget = c->cdev->gadget; struct printer_dev *dev; - struct usb_ep *in_ep, *out_ep; int status = -ENOMEM; - int gcnum; size_t len; u32 i; struct usb_request *req; + usb_ep_autoconfig_reset(gadget); + dev = &usb_printer_gadget; dev->function.name = shortname; @@ -1125,6 +1118,10 @@ static int __init printer_bind_config(struct usb_configuration *c) dev->function.set_alt = printer_func_set_alt; dev->function.disable = printer_func_disable; + status = usb_add_function(c, &dev->function); + if (status) + return status; + /* Setup the sysfs files for the printer gadget. */ dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, NULL, "g_printer"); @@ -1145,23 +1142,6 @@ static int __init printer_bind_config(struct usb_configuration *c) goto fail; } - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - } else { - dev_warn(&gadget->dev, "controller '%s' not recognized\n", - gadget->name); - /* unrecognized, but safe unless bulk is REALLY quirky */ - device_desc.bcdDevice = - cpu_to_le16(0xFFFF); - } - snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - if (iSerialNum) - strlcpy(serial_num, iSerialNum, sizeof serial_num); - if (iPNPstring) strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); @@ -1169,26 +1149,6 @@ static int __init printer_bind_config(struct usb_configuration *c) pnp_string[0] = (len >> 8) & 0xFF; pnp_string[1] = len & 0xFF; - /* all we really need is bulk IN/OUT */ - usb_ep_autoconfig_reset(gadget); - in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc); - if (!in_ep) { -autoconf_fail: - dev_err(&gadget->dev, "can't autoconfigure on %s\n", - gadget->name); - return -ENODEV; - } - in_ep->driver_data = in_ep; /* claim */ - - out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc); - if (!out_ep) - goto autoconf_fail; - out_ep->driver_data = out_ep; /* claim */ - - /* assumes that all endpoints are dual-speed */ - hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; - usb_gadget_set_selfpowered(gadget); if (gadget->is_otg) { @@ -1215,9 +1175,6 @@ autoconf_fail: dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; - dev->in_ep = in_ep; - dev->out_ep = out_ep; - for (i = 0; i < QLEN; i++) { req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); if (!req) { @@ -1250,8 +1207,6 @@ autoconf_fail: dev->gadget = gadget; INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); - INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, - in_ep->name); return 0; fail: @@ -1266,14 +1221,28 @@ static int printer_unbind(struct usb_composite_dev *cdev) static int __init printer_bind(struct usb_composite_dev *cdev) { - return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config); + int ret; + + ret = usb_string_ids_tab(cdev, strings); + if (ret < 0) + return ret; + device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; + device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; + + ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config); + if (ret) + return ret; + usb_composite_overwrite_options(cdev, &coverwrite); + return ret; } -static struct usb_composite_driver printer_driver = { +static __refdata struct usb_composite_driver printer_driver = { .name = shortname, .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, + .bind = printer_bind, .unbind = printer_unbind, }; @@ -1297,7 +1266,7 @@ init(void) return status; } - status = usb_composite_probe(&printer_driver, printer_bind); + status = usb_composite_probe(&printer_driver); if (status) { class_destroy(usb_gadget_class); unregister_chrdev_region(g_printer_devno, 1); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 907ad3e..8efbf08 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -33,7 +33,6 @@ #include <linux/dma-mapping.h> #include <linux/irq.h> #include <linux/clk.h> -#include <linux/err.h> #include <linux/seq_file.h> #include <linux/debugfs.h> #include <linux/io.h> @@ -1000,7 +999,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) } static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int pxa25x_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops pxa25x_udc_ops = { @@ -1258,7 +1257,7 @@ static void udc_enable (struct pxa25x_udc *dev) * the driver might get unbound. */ static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct pxa25x_udc *dev = the_controller; int retval; @@ -1286,7 +1285,7 @@ fail: dev->gadget.dev.driver = NULL; return retval; } - retval = bind(&dev->gadget); + retval = bind(&dev->gadget, driver); if (retval) { DMSG("bind to driver %s --> error %d\n", driver->driver.name, retval); diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 861f4df..2eca1e7 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -225,7 +225,7 @@ dump_state(struct pxa25x_udc *dev) dev->stats.read.bytes, dev->stats.read.ops); for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { - if (dev->ep [i].desc == NULL) + if (dev->ep[i].ep.desc == NULL) continue; DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs); } diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 644b430..979ddad 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1672,7 +1672,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) } static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int pxa27x_udc_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops pxa_udc_ops = { @@ -1803,7 +1803,7 @@ static void udc_enable(struct pxa_udc *udc) * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise */ static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct pxa_udc *udc = the_controller; int retval; @@ -1826,7 +1826,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, dev_err(udc->dev, "device_add error %d\n", retval); goto add_fail; } - retval = bind(&udc->gadget); + retval = bind(&udc->gadget, driver); if (retval) { dev_err(udc->dev, "bind to driver %s --> error %d\n", driver->driver.name, retval); diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index b35babe..e4192b8 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -863,26 +863,8 @@ int rndis_msg_parser(u8 configNr, u8 *buf) */ pr_warning("%s: unknown RNDIS message 0x%08X len %d\n", __func__, MsgType, MsgLength); - { - unsigned i; - for (i = 0; i < MsgLength; i += 16) { - pr_debug("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf [i+1], - buf[i+2], buf[i+3], - buf[i+4], buf [i+5], - buf[i+6], buf[i+7], - buf[i+8], buf [i+9], - buf[i+10], buf[i+11], - buf[i+12], buf [i+13], - buf[i+14], buf[i+15]); - } - } + print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET, + buf, MsgLength); break; } diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 0bb617e..6f696ee 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2197,7 +2197,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) /* issue soft reset */ writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); - timeout = 1000; + timeout = 10000; do { grstctl = readl(hsotg->regs + GRSTCTL); } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); @@ -2207,7 +2207,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) return -EINVAL; } - timeout = 1000; + timeout = 10000; while (1) { u32 grstctl = readl(hsotg->regs + GRSTCTL); @@ -3516,7 +3516,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) hsotg->dev = dev; hsotg->plat = plat; - hsotg->clk = clk_get(&pdev->dev, "otg"); + hsotg->clk = devm_clk_get(&pdev->dev, "otg"); if (IS_ERR(hsotg->clk)) { dev_err(dev, "cannot get otg clock\n"); return PTR_ERR(hsotg->clk); @@ -3667,7 +3667,6 @@ err_supplies: err_clk: clk_disable_unprepare(hsotg->clk); - clk_put(hsotg->clk); return ret; } @@ -3693,7 +3692,6 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); clk_disable_unprepare(hsotg->clk); - clk_put(hsotg->clk); device_unregister(&hsotg->gadget.dev); return 0; diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index e26a4e7..d8e785d 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -135,7 +135,6 @@ struct s3c_hsudc_req { * @dev: The device reference used by probe function. * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed). * @regs: Remapped base address of controller's register space. - * @mem_rsrc: Device memory resource used for remapping device register space. * irq: IRQ number used by the controller. * uclk: Reference to the controller clock. * ep0state: Current state of EP0. @@ -150,7 +149,6 @@ struct s3c_hsudc { struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)]; spinlock_t lock; void __iomem *regs; - struct resource *mem_rsrc; int irq; struct clk *uclk; int ep0state; @@ -835,9 +833,9 @@ static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep, { struct s3c_hsudc_req *hsreq; - hsreq = kzalloc(sizeof *hsreq, gfp_flags); + hsreq = kzalloc(sizeof(*hsreq), gfp_flags); if (!hsreq) - return 0; + return NULL; INIT_LIST_HEAD(&hsreq->queue); return &hsreq->req; @@ -906,16 +904,16 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req, csr = readl((u32)hsudc->regs + offset); if (!(csr & S3C_ESR_TX_SUCCESS) && (s3c_hsudc_write_fifo(hsep, hsreq) == 1)) - hsreq = 0; + hsreq = NULL; } else { csr = readl((u32)hsudc->regs + offset); if ((csr & S3C_ESR_RX_SUCCESS) && (s3c_hsudc_read_fifo(hsep, hsreq) == 1)) - hsreq = 0; + hsreq = NULL; } } - if (hsreq != 0) + if (hsreq) list_add_tail(&hsreq->queue, &hsep->queue); spin_unlock_irqrestore(&hsudc->lock, flags); @@ -1271,7 +1269,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev) struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; int ret, i; - hsudc = kzalloc(sizeof(struct s3c_hsudc) + + hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) + sizeof(struct s3c_hsudc_ep) * pd->epnum, GFP_KERNEL); if (!hsudc) { @@ -1296,25 +1294,12 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "unable to obtain driver resource data\n"); - ret = -ENODEV; - goto err_res; - } - - hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev)); - if (!hsudc->mem_rsrc) { - dev_err(dev, "failed to reserve register area\n"); - ret = -ENODEV; - goto err_res; - } - hsudc->regs = ioremap(res->start, resource_size(res)); + hsudc->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hsudc->regs) { dev_err(dev, "error mapping device register area\n"); ret = -EBUSY; - goto err_remap; + goto err_res; } spin_lock_init(&hsudc->lock); @@ -1337,21 +1322,22 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "unable to obtain IRQ number\n"); - goto err_irq; + goto err_res; } hsudc->irq = ret; - ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc); + ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0, + driver_name, hsudc); if (ret < 0) { dev_err(dev, "irq request failed\n"); - goto err_irq; + goto err_res; } - hsudc->uclk = clk_get(&pdev->dev, "usb-device"); + hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device"); if (IS_ERR(hsudc->uclk)) { dev_err(dev, "failed to find usb-device clock source\n"); ret = PTR_ERR(hsudc->uclk); - goto err_clk; + goto err_res; } clk_enable(hsudc->uclk); @@ -1377,21 +1363,12 @@ err_add_udc: device_unregister(&hsudc->gadget.dev); err_add_device: clk_disable(hsudc->uclk); - clk_put(hsudc->uclk); -err_clk: - free_irq(hsudc->irq, hsudc); -err_irq: - iounmap(hsudc->regs); - -err_remap: - release_mem_region(res->start, resource_size(res)); err_res: if (!IS_ERR_OR_NULL(hsudc->transceiver)) usb_put_phy(hsudc->transceiver); regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); err_supplies: - kfree(hsudc); return ret; } diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index f2e51f5..c33e942 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -12,6 +12,8 @@ * (at your option) any later version. */ +#define pr_fmt(fmt) "s3c2410_udc: " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -27,6 +29,7 @@ #include <linux/clk.h> #include <linux/gpio.h> #include <linux/prefetch.h> +#include <linux/io.h> #include <linux/debugfs.h> #include <linux/seq_file.h> @@ -35,7 +38,6 @@ #include <linux/usb/gadget.h> #include <asm/byteorder.h> -#include <asm/io.h> #include <asm/irq.h> #include <asm/unaligned.h> #include <mach/irqs.h> @@ -115,7 +117,7 @@ static int dprintk(int level, const char *fmt, ...) sizeof(printk_buf)-len, fmt, args); va_end(args); - return printk(KERN_DEBUG "%s", printk_buf); + return pr_debug("%s", printk_buf); } #else static int dprintk(int level, const char *fmt, ...) @@ -125,10 +127,10 @@ static int dprintk(int level, const char *fmt, ...) #endif static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) { - u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg; + u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg; u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; - u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2; - u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2; + u32 ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2; + u32 ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2; addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG); pwr_reg = udc_read(S3C2410_UDC_PWR_REG); @@ -164,10 +166,10 @@ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) "EP2_I_CSR2 : 0x%04X\n" "EP2_O_CSR1 : 0x%04X\n" "EP2_O_CSR2 : 0x%04X\n", - addr_reg,pwr_reg,ep_int_reg,usb_int_reg, + addr_reg, pwr_reg, ep_int_reg, usb_int_reg, ep_int_en_reg, usb_int_en_reg, ep0_csr, - ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2, - ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2 + ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2, + ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2 ); return 0; @@ -230,7 +232,7 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base) { udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY + udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY | S3C2410_UDC_EP0_CSR_DE), S3C2410_UDC_EP0_CSR_REG); } @@ -263,7 +265,7 @@ static void s3c2410_udc_done(struct s3c2410_ep *ep, list_del_init(&req->queue); - if (likely (req->req.status == -EINPROGRESS)) + if (likely(req->req.status == -EINPROGRESS)) req->req.status = status; else status = req->req.status; @@ -280,9 +282,9 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc, if (&ep->queue == NULL) return; - while (!list_empty (&ep->queue)) { + while (!list_empty(&ep->queue)) { struct s3c2410_request *req; - req = list_entry (ep->queue.next, struct s3c2410_request, + req = list_entry(ep->queue.next, struct s3c2410_request, queue); s3c2410_udc_done(ep, req, status); } @@ -389,10 +391,10 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, if (idx == 0) { /* Reset signal => no need to say 'data sent' */ - if (! (udc_read(S3C2410_UDC_USB_INT_REG) + if (!(udc_read(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET)) s3c2410_udc_set_ep0_de_in(base_addr); - ep->dev->ep0state=EP0_IDLE; + ep->dev->ep0state = EP0_IDLE; } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); @@ -406,7 +408,7 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, } else { if (idx == 0) { /* Reset signal => no need to say 'data sent' */ - if (! (udc_read(S3C2410_UDC_USB_INT_REG) + if (!(udc_read(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET)) s3c2410_udc_set_ep0_ipr(base_addr); } else { @@ -442,7 +444,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, u8 *buf; u32 ep_csr; unsigned bufferspace; - int is_last=1; + int is_last = 1; unsigned avail; int fifo_count = 0; u32 idx; @@ -510,7 +512,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, /* Only ep0 debug messages are interesting */ if (idx == 0) dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n", - __func__, fifo_count,is_last); + __func__, fifo_count, is_last); if (is_last) { if (idx == 0) { @@ -542,7 +544,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq) { - unsigned char *outbuf = (unsigned char*)crq; + unsigned char *outbuf = (unsigned char *)crq; int bytes_read = 0; udc_write(0, S3C2410_UDC_INDEX_REG); @@ -648,7 +650,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, switch (crq->bRequest) { case USB_REQ_SET_CONFIGURATION: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n"); + dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...\n"); if (crq->bRequestType == USB_RECIP_DEVICE) { dev->req_config = 1; @@ -657,7 +659,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, break; case USB_REQ_SET_INTERFACE: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n"); + dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...\n"); if (crq->bRequestType == USB_RECIP_INTERFACE) { dev->req_config = 1; @@ -666,7 +668,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, break; case USB_REQ_SET_ADDRESS: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n"); + dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...\n"); if (crq->bRequestType == USB_RECIP_DEVICE) { tmp = crq->wValue & 0x7F; @@ -679,13 +681,12 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, break; case USB_REQ_GET_STATUS: - dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n"); + dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...\n"); s3c2410_udc_clear_ep0_opr(base_addr); if (dev->req_std) { - if (!s3c2410_udc_get_status(dev, crq)) { + if (!s3c2410_udc_get_status(dev, crq)) return; - } } break; @@ -750,7 +751,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, /* deferred i/o == no response yet */ } else if (dev->req_pending) { dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n"); - dev->req_pending=0; + dev->req_pending = 0; } dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]); @@ -801,16 +802,14 @@ static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev) case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n"); - if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) { + if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) s3c2410_udc_write_fifo(ep, req); - } break; case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n"); - if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) { - s3c2410_udc_read_fifo(ep,req); - } + if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req) + s3c2410_udc_read_fifo(ep, req); break; case EP0_END_XFER: @@ -836,7 +835,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) u32 ep_csr1; u32 idx; - if (likely (!list_empty(&ep->queue))) + if (likely(!list_empty(&ep->queue))) req = list_entry(ep->queue.next, struct s3c2410_request, queue); else @@ -858,9 +857,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) return; } - if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) { - s3c2410_udc_write_fifo(ep,req); - } + if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) + s3c2410_udc_write_fifo(ep, req); } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG); @@ -873,9 +871,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) return; } - if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) { - s3c2410_udc_read_fifo(ep,req); - } + if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) + s3c2410_udc_read_fifo(ep, req); } } @@ -1057,7 +1054,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, struct s3c2410_ep *ep; u32 max, tmp; unsigned long flags; - u32 csr1,csr2; + u32 csr1, csr2; u32 int_en_reg; ep = to_s3c2410_ep(_ep); @@ -1073,7 +1070,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, max = usb_endpoint_maxp(desc) & 0x1fff; - local_irq_save (flags); + local_irq_save(flags); _ep->maxpacket = max & 0x7ff; ep->ep.desc = desc; ep->halted = 0; @@ -1117,11 +1114,11 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, /* print some debug message */ tmp = desc->bEndpointAddress; - dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n", - _ep->name,ep->num, tmp, + dprintk(DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n", + _ep->name, ep->num, tmp, desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max); - local_irq_restore (flags); + local_irq_restore(flags); s3c2410_udc_set_halt(_ep, 0); return 0; @@ -1149,7 +1146,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep) ep->ep.desc = NULL; ep->halted = 1; - s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN); + s3c2410_udc_nuke(ep->dev, ep, -ESHUTDOWN); /* disable irqs */ int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); @@ -1170,16 +1167,16 @@ s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags) { struct s3c2410_request *req; - dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags); + dprintk(DEBUG_VERBOSE, "%s(%p,%d)\n", __func__, _ep, mem_flags); if (!_ep) return NULL; - req = kzalloc (sizeof(struct s3c2410_request), mem_flags); + req = kzalloc(sizeof(struct s3c2410_request), mem_flags); if (!req) return NULL; - INIT_LIST_HEAD (&req->queue); + INIT_LIST_HEAD(&req->queue); return &req->req; } @@ -1197,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name)) return; - WARN_ON (!list_empty (&req->queue)); + WARN_ON(!list_empty(&req->queue)); kfree(req); } @@ -1220,12 +1217,12 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, } dev = ep->dev; - if (unlikely (!dev->driver + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { return -ESHUTDOWN; } - local_irq_save (flags); + local_irq_save(flags); if (unlikely(!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { @@ -1233,7 +1230,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__); else { dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n", - __func__, !_req->complete,!_req->buf, + __func__, !_req->complete, !_req->buf, !list_empty(&req->queue)); } @@ -1299,7 +1296,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, } /* pio or dma irq handler advances the queue. */ - if (likely (req != 0)) + if (likely(req)) list_add_tail(&req->queue, &ep->queue); local_irq_restore(flags); @@ -1329,11 +1326,11 @@ static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req) udc = to_s3c2410_udc(ep->gadget); - local_irq_save (flags); + local_irq_save(flags); - list_for_each_entry (req, &ep->queue, queue) { + list_for_each_entry(req, &ep->queue, queue) { if (&req->req == _req) { - list_del_init (&req->queue); + list_del_init(&req->queue); _req->status = -ECONNRESET; retval = 0; break; @@ -1348,7 +1345,7 @@ static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req) s3c2410_udc_done(ep, req, -ECONNRESET); } - local_irq_restore (flags); + local_irq_restore(flags); return retval; } @@ -1367,7 +1364,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) return -EINVAL; } - local_irq_save (flags); + local_irq_save(flags); idx = ep->bEndpointAddress & 0x7F; @@ -1376,7 +1373,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) s3c2410_udc_set_ep0_de_out(base_addr); } else { udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN) + ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG); @@ -1404,7 +1401,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) } ep->halted = value ? 1 : 0; - local_irq_restore (flags); + local_irq_restore(flags); return 0; } @@ -1484,9 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) } s3c2410_udc_disable(udc); } - } - else + } else { return -EOPNOTSUPP; + } return 0; } @@ -1542,7 +1539,7 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) } static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)); static int s3c2410_udc_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops s3c2410_ops = { @@ -1617,20 +1614,20 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) u32 i; /* device/ep0 records init */ - INIT_LIST_HEAD (&dev->gadget.ep_list); - INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); dev->ep0state = EP0_IDLE; for (i = 0; i < S3C2410_ENDPOINTS; i++) { struct s3c2410_ep *ep = &dev->ep[i]; if (i != 0) - list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; ep->ep.desc = NULL; ep->halted = 0; - INIT_LIST_HEAD (&ep->queue); + INIT_LIST_HEAD(&ep->queue); } } @@ -1668,7 +1665,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) } static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { struct s3c2410_udc *udc = the_controller; int retval; @@ -1683,13 +1680,13 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, return -EBUSY; if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { - printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", + dev_err(&udc->gadget.dev, "Invalid driver: bind %p setup %p speed %d\n", bind, driver->setup, driver->max_speed); return -EINVAL; } #if defined(MODULE) if (!driver->unbind) { - printk(KERN_ERR "Invalid driver: no unbind method\n"); + dev_err(&udc->gadget.dev, "Invalid driver: no unbind method\n"); return -EINVAL; } #endif @@ -1699,15 +1696,17 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, udc->gadget.dev.driver = &driver->driver; /* Bind the driver */ - if ((retval = device_add(&udc->gadget.dev)) != 0) { - printk(KERN_ERR "Error in device_add() : %d\n",retval); + retval = device_add(&udc->gadget.dev); + if (retval) { + dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval); goto register_error; } dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = bind(&udc->gadget)) != 0) { + retval = bind(&udc->gadget, driver); + if (retval) { device_del(&udc->gadget.dev); goto register_error; } @@ -1865,7 +1864,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE; } - spin_lock_init (&udc->lock); + spin_lock_init(&udc->lock); udc_info = pdev->dev.platform_data; rsrc_start = S3C2410_PA_USBDEV; @@ -2028,7 +2027,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) +static int +s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) { s3c2410_udc_command(S3C2410_UDC_P_DISABLE); @@ -2073,7 +2073,7 @@ static int __init udc_init(void) s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL); if (IS_ERR(s3c2410_udc_debugfs_root)) { - printk(KERN_ERR "%s: debugfs dir creation failed %ld\n", + pr_err("%s: debugfs dir creation failed %ld\n", gadget_name, PTR_ERR(s3c2410_udc_debugfs_root)); s3c2410_udc_debugfs_root = NULL; } diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 665c074..44752f5 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -11,7 +11,6 @@ */ #include <linux/kernel.h> -#include <linux/utsname.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -37,17 +36,13 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_acm.c" #include "f_obex.c" #include "f_serial.c" #include "u_serial.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); /* Thanks to NetChip Technologies for donating this product ID. * @@ -61,15 +56,12 @@ /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 - -static char manufacturer[50]; +#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = GS_VERSION_NAME, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME, + [USB_GADGET_SERIAL_IDX].s = "", [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */, { } /* end of list */ }; @@ -94,7 +86,7 @@ static struct usb_device_descriptor device_desc = { /* .bMaxPacketSize0 = f(hardware) */ .idVendor = cpu_to_le16(GS_VENDOR_ID), /* .idProduct = f(use_acm) */ - /* .bcdDevice = f(hardware) */ + .bcdDevice = cpu_to_le16(GS_VERSION_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ .bNumConfigurations = 1, @@ -162,8 +154,6 @@ static struct usb_configuration serial_config_driver = { static int __init gs_bind(struct usb_composite_dev *cdev) { - int gcnum; - struct usb_gadget *gadget = cdev->gadget; int status; status = gserial_setup(cdev->gadget, n_ports); @@ -174,50 +164,14 @@ static int __init gs_bind(struct usb_composite_dev *cdev) * contents can be overridden by the composite_dev glue. */ - /* device description: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto fail; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_PRODUCT_IDX].id = status; - - device_desc.iProduct = status; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + status = strings_dev[STRING_DESCRIPTION_IDX].id; serial_config_driver.iConfiguration = status; - /* set up other descriptors */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); - else { - /* this is so simple (for now, no altsettings) that it - * SHOULD NOT have problems with bulk-capable hardware. - * so warn about unrcognized controllers -- don't panic. - * - * things like configuration and altsetting numbering - * can need hardware-specific attention though. - */ - pr_warning("gs_bind: controller '%s' not recognized\n", - gadget->name); - device_desc.bcdDevice = - cpu_to_le16(GS_VERSION_NUM | 0x0099); - } - if (gadget_is_otg(cdev->gadget)) { serial_config_driver.descriptors = otg_desc; serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -229,6 +183,7 @@ static int __init gs_bind(struct usb_composite_dev *cdev) if (status < 0) goto fail; + usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s\n", GS_VERSION_NAME); return 0; @@ -238,11 +193,12 @@ fail: return status; } -static struct usb_composite_driver gserial_driver = { +static __refdata struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, + .bind = gs_bind, }; static int __init init(void) @@ -271,7 +227,7 @@ static int __init init(void) } strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; - return usb_composite_probe(&gserial_driver, gs_bind); + return usb_composite_probe(&gserial_driver); } module_init(init); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 5444866..eaa1005 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -25,13 +25,10 @@ #include <target/configfs_macros.h> #include <asm/unaligned.h> -#include "usbstring.c" -#include "epautoconf.c" -#include "config.c" -#include "composite.c" - #include "tcm_usb_gadget.h" +USB_GADGET_COMPOSITE_OPTIONS(); + static struct target_fabric_configfs *usbg_fabric_configfs; static inline struct f_uas *to_f_uas(struct usb_function *f) @@ -1977,7 +1974,6 @@ static struct usb_interface_descriptor bot_intf_desc = { .bInterfaceClass = USB_CLASS_MASS_STORAGE, .bInterfaceSubClass = USB_SC_SCSI, .bInterfaceProtocol = USB_PR_BULK, - .iInterface = USB_G_STR_INT_UAS, }; static struct usb_interface_descriptor uasp_intf_desc = { @@ -1988,7 +1984,6 @@ static struct usb_interface_descriptor uasp_intf_desc = { .bInterfaceClass = USB_CLASS_MASS_STORAGE, .bInterfaceSubClass = USB_SC_SCSI, .bInterfaceProtocol = USB_PR_UAS, - .iInterface = USB_G_STR_INT_BBB, }; static struct usb_endpoint_descriptor uasp_bi_desc = { @@ -2209,20 +2204,16 @@ static struct usb_device_descriptor usbg_device_desc = { .bDeviceClass = USB_CLASS_PER_INTERFACE, .idVendor = cpu_to_le16(UAS_VENDOR_ID), .idProduct = cpu_to_le16(UAS_PRODUCT_ID), - .iManufacturer = USB_G_STR_MANUFACTOR, - .iProduct = USB_G_STR_PRODUCT, - .iSerialNumber = USB_G_STR_SERIAL, - .bNumConfigurations = 1, }; static struct usb_string usbg_us_strings[] = { - { USB_G_STR_MANUFACTOR, "Target Manufactor"}, - { USB_G_STR_PRODUCT, "Target Product"}, - { USB_G_STR_SERIAL, "000000000001"}, - { USB_G_STR_CONFIG, "default config"}, - { USB_G_STR_INT_UAS, "USB Attached SCSI"}, - { USB_G_STR_INT_BBB, "Bulk Only Transport"}, + [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor", + [USB_GADGET_PRODUCT_IDX].s = "Target Product", + [USB_GADGET_SERIAL_IDX].s = "000000000001", + [USB_G_STR_CONFIG].s = "default config", + [USB_G_STR_INT_UAS].s = "USB Attached SCSI", + [USB_G_STR_INT_BBB].s = "Bulk Only Transport", { }, }; @@ -2244,7 +2235,6 @@ static int guas_unbind(struct usb_composite_dev *cdev) static struct usb_configuration usbg_config_driver = { .label = "Linux Target", .bConfigurationValue = 1, - .iConfiguration = USB_G_STR_CONFIG, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; @@ -2417,6 +2407,9 @@ static int usbg_cfg_bind(struct usb_configuration *c) fu->function.disable = usbg_disable; fu->tpg = the_only_tpg_I_currently_have; + bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id; + uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id; + ret = usb_add_function(c, &fu->function); if (ret) goto err; @@ -2431,22 +2424,38 @@ static int usb_target_bind(struct usb_composite_dev *cdev) { int ret; + ret = usb_string_ids_tab(cdev, usbg_us_strings); + if (ret) + return ret; + + usbg_device_desc.iManufacturer = + usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id; + usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id; + usbg_device_desc.iSerialNumber = + usbg_us_strings[USB_GADGET_SERIAL_IDX].id; + usbg_config_driver.iConfiguration = + usbg_us_strings[USB_G_STR_CONFIG].id; + ret = usb_add_config(cdev, &usbg_config_driver, usbg_cfg_bind); + if (ret) + return ret; + usb_composite_overwrite_options(cdev, &coverwrite); return 0; } -static struct usb_composite_driver usbg_driver = { +static __refdata struct usb_composite_driver usbg_driver = { .name = "g_target", .dev = &usbg_device_desc, .strings = usbg_strings, .max_speed = USB_SPEED_SUPER, + .bind = usb_target_bind, .unbind = guas_unbind, }; static int usbg_attach(struct usbg_tpg *tpg) { - return usb_composite_probe(&usbg_driver, usb_target_bind); + return usb_composite_probe(&usbg_driver); } static void usbg_detach(struct usbg_tpg *tpg) diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h index bb18999..8289219 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.h +++ b/drivers/usb/gadget/tcm_usb_gadget.h @@ -16,12 +16,11 @@ #define UASP_SS_EP_COMP_LOG_STREAMS 4 #define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS) -#define USB_G_STR_MANUFACTOR 1 -#define USB_G_STR_PRODUCT 2 -#define USB_G_STR_SERIAL 3 -#define USB_G_STR_CONFIG 4 -#define USB_G_STR_INT_UAS 5 -#define USB_G_STR_INT_BBB 6 +enum { + USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX, + USB_G_STR_INT_UAS, + USB_G_STR_INT_BBB, +}; #define USB_G_ALT_INT_BBB 0 #define USB_G_ALT_INT_UAS 1 diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 0e52309..b9c4690 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -14,6 +14,7 @@ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/gfp.h> #include <linux/device.h> #include <linux/ctype.h> @@ -83,17 +84,10 @@ struct eth_dev { #define DEFAULT_QLEN 2 /* double buffering by default */ - -#ifdef CONFIG_USB_GADGET_DUALSPEED - static unsigned qmult = 5; module_param(qmult, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed"); -#else /* full speed (low speed doesn't do bulk) */ -#define qmult 1 -#endif - /* for dual-speed hardware, use deeper queues at high/super speed */ static inline int qlen(struct usb_gadget *gadget) { diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index e5e44f8..f3cd969 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); */ static inline int usb_gadget_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) + int (*bind)(struct usb_gadget *, struct usb_gadget_driver *)) { return gadget->ops->start(driver, bind); } @@ -262,8 +262,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); if (udc_is_newstyle(udc)) { - udc->driver->disconnect(udc->gadget); usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); udc->driver->unbind(udc->gadget); usb_gadget_udc_stop(udc->gadget, udc->driver); } else { @@ -311,13 +311,12 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc); /* ------------------------------------------------------------------------- */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; int ret; - if (!driver || !bind || !driver->setup) + if (!driver || !driver->bind || !driver->setup) return -EINVAL; mutex_lock(&udc_lock); @@ -339,7 +338,7 @@ found: udc->dev.driver = &driver->driver; if (udc_is_newstyle(udc)) { - ret = bind(udc->gadget); + ret = driver->bind(udc->gadget, driver); if (ret) goto err1; ret = usb_gadget_udc_start(udc->gadget, driver); @@ -350,7 +349,7 @@ found: usb_gadget_connect(udc->gadget); } else { - ret = usb_gadget_start(udc->gadget, driver, bind); + ret = usb_gadget_start(udc->gadget, driver, driver->bind); if (ret) goto err1; diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 4d25b90..1f49fce 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -9,6 +9,7 @@ #include <linux/errno.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/list.h> #include <linux/string.h> #include <linux/device.h> @@ -68,4 +69,4 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) buf [1] = USB_DT_STRING; return buf [0]; } - +EXPORT_SYMBOL_GPL(usb_gadget_get_string); diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 120e134..69cf5c2 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -23,16 +23,12 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "uvc_queue.c" #include "uvc_video.c" #include "uvc_v4l2.c" #include "f_uvc.c" +USB_GADGET_COMPOSITE_OPTIONS(); /* -------------------------------------------------------------------------- * Device descriptor */ @@ -47,13 +43,12 @@ static char webcam_config_label[] = "Video"; /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 +#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static struct usb_string webcam_strings[] = { - [STRING_MANUFACTURER_IDX].s = webcam_vendor_label, - [STRING_PRODUCT_IDX].s = webcam_product_label, + [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label, + [USB_GADGET_PRODUCT_IDX].s = webcam_product_label, + [USB_GADGET_SERIAL_IDX].s = "", [STRING_DESCRIPTION_IDX].s = webcam_config_label, { } }; @@ -358,26 +353,22 @@ webcam_bind(struct usb_composite_dev *cdev) /* Allocate string descriptor numbers ... note that string contents * can be overridden by the composite_dev glue. */ - if ((ret = usb_string_id(cdev)) < 0) - goto error; - webcam_strings[STRING_MANUFACTURER_IDX].id = ret; - webcam_device_descriptor.iManufacturer = ret; - - if ((ret = usb_string_id(cdev)) < 0) - goto error; - webcam_strings[STRING_PRODUCT_IDX].id = ret; - webcam_device_descriptor.iProduct = ret; - - if ((ret = usb_string_id(cdev)) < 0) + ret = usb_string_ids_tab(cdev, webcam_strings); + if (ret < 0) goto error; - webcam_strings[STRING_DESCRIPTION_IDX].id = ret; - webcam_config_driver.iConfiguration = ret; + webcam_device_descriptor.iManufacturer = + webcam_strings[USB_GADGET_MANUFACTURER_IDX].id; + webcam_device_descriptor.iProduct = + webcam_strings[USB_GADGET_PRODUCT_IDX].id; + webcam_config_driver.iConfiguration = + webcam_strings[STRING_DESCRIPTION_IDX].id; /* Register our configuration. */ if ((ret = usb_add_config(cdev, &webcam_config_driver, webcam_config_bind)) < 0) goto error; + usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "Webcam Video Gadget\n"); return 0; @@ -390,18 +381,19 @@ error: * Driver */ -static struct usb_composite_driver webcam_driver = { +static __refdata struct usb_composite_driver webcam_driver = { .name = "g_webcam", .dev = &webcam_device_descriptor, .strings = webcam_device_strings, .max_speed = USB_SPEED_SUPER, + .bind = webcam_bind, .unbind = webcam_unbind, }; static int __init webcam_init(void) { - return usb_composite_probe(&webcam_driver, webcam_bind); + return usb_composite_probe(&webcam_driver); } static void __exit diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 12ad516..6bf4c06 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -42,7 +42,6 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/utsname.h> #include <linux/device.h> #include "g_zero.h" @@ -58,15 +57,11 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - #include "f_sourcesink.c" #include "f_loopback.c" /*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_VERSION "Cinco de Mayo 2008" @@ -141,20 +136,13 @@ const struct usb_descriptor_header *otg_desc[] = { #endif /* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_SERIAL_IDX 2 - -static char manufacturer[50]; - /* default serial number takes at least two packets */ static char serial[] = "0123456789.0123456789.0123456789"; static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = longname, - [STRING_SERIAL_IDX].s = serial, + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = longname, + [USB_GADGET_SERIAL_IDX].s = serial, { } /* end of list */ }; @@ -265,30 +253,18 @@ static void zero_resume(struct usb_composite_dev *cdev) static int __init zero_bind(struct usb_composite_dev *cdev) { - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int id; + int status; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_MANUFACTURER_IDX].id = id; - device_desc.iManufacturer = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_PRODUCT_IDX].id = id; - device_desc.iProduct = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_SERIAL_IDX].id = id; - device_desc.iSerialNumber = id; + status = usb_string_ids_tab(cdev, strings_dev); + if (status < 0) + return status; + + device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id; setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); @@ -303,28 +279,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev) loopback_add(cdev, autoresume != 0); } - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - else { - /* gadget zero is so simple (for now, no altsettings) that - * it SHOULD NOT have problems with bulk-capable hardware. - * so just warn about unrcognized controllers -- don't panic. - * - * things like configuration and altsetting numbering - * can need hardware-specific attention though. - */ - pr_warning("%s: controller '%s' not recognized\n", - longname, gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x9999); - } + usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - return 0; } @@ -334,11 +292,12 @@ static int zero_unbind(struct usb_composite_dev *cdev) return 0; } -static struct usb_composite_driver zero_driver = { +static __refdata struct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, + .bind = zero_bind, .unbind = zero_unbind, .suspend = zero_suspend, .resume = zero_resume, @@ -349,7 +308,7 @@ MODULE_LICENSE("GPL"); static int __init init(void) { - return usb_composite_probe(&zero_driver, zero_bind); + return usb_composite_probe(&zero_driver); } module_init(init); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 075d2ec..b1deb0f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -18,8 +18,8 @@ config USB_C67X00_HCD module will be called c67x00. config USB_XHCI_HCD - tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)" - depends on USB && USB_ARCH_HAS_XHCI && EXPERIMENTAL + tristate "xHCI HCD (USB 3.0) support" + depends on USB && USB_ARCH_HAS_XHCI ---help--- The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 "SuperSpeed" host controller hardware. @@ -262,7 +262,7 @@ config USB_ISP116X_HCD config USB_ISP1760_HCD tristate "ISP 1760 HCD support" - depends on USB && EXPERIMENTAL + depends on USB ---help--- The ISP1760 chip is a USB 2.0 host controller. @@ -292,7 +292,7 @@ config USB_OHCI_HCD depends on USB && USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 select USB_OTG_UTILS if ARCH_OMAP - select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008 + depends on USB_ISP1301 || !(ARCH_LPC32XX || ARCH_PNX4008) ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's @@ -376,7 +376,7 @@ config USB_OHCI_HCD_PCI config USB_OHCI_HCD_SSB bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)" - depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL + depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) select USB_HCD_SSB select USB_OHCI_HCD_PLATFORM default n @@ -414,21 +414,21 @@ config USB_CNS3XXX_OHCI config USB_OHCI_HCD_PLATFORM bool "Generic OHCI driver for a platform device" - depends on USB_OHCI_HCD && EXPERIMENTAL + depends on USB_OHCI_HCD default n ---help--- Adds an OHCI host driver for a generic platform device, which - provieds a memory space and an irq. + provides a memory space and an irq. If unsure, say N. config USB_EHCI_HCD_PLATFORM bool "Generic EHCI driver for a platform device" - depends on USB_EHCI_HCD && EXPERIMENTAL + depends on USB_EHCI_HCD default n ---help--- Adds an EHCI host driver for a generic platform device, which - provieds a memory space and an irq. + provides a memory space and an irq. If unsure, say N. @@ -450,7 +450,7 @@ config USB_OHCI_LITTLE_ENDIAN config USB_UHCI_HCD tristate "UHCI HCD (most Intel and VIA) support" - depends on USB && (PCI || SPARC_LEON) + depends on USB && (PCI || SPARC_LEON || ARCH_VT8500) ---help--- The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB @@ -468,7 +468,15 @@ config USB_UHCI_HCD config USB_UHCI_SUPPORT_NON_PCI_HC bool depends on USB_UHCI_HCD - default y if SPARC_LEON + default y if (SPARC_LEON || ARCH_VT8500) + +config USB_UHCI_PLATFORM + bool "Generic UHCI Platform Driver support" + depends on USB_UHCI_SUPPORT_NON_PCI_HC + default y if ARCH_VT8500 + ---help--- + Enable support for generic UHCI platform devices that require no + additional configuration. config USB_UHCI_BIG_ENDIAN_MMIO bool @@ -583,8 +591,7 @@ config USB_RENESAS_USBHS_HCD module will be called renesas-usbhs. config USB_WHCI_HCD - tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Wireless USB Host Controller Interface (WHCI) driver" depends on PCI && USB && UWB select USB_WUSB select UWB_WHCI @@ -596,8 +603,7 @@ config USB_WHCI_HCD will be called "whci-hcd". config USB_HWA_HCD - tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Host Wire Adapter (HWA) driver" depends on USB && UWB select USB_WUSB select UWB_HWA @@ -648,7 +654,7 @@ config USB_OCTEON2_COMMON config USB_HCD_BCMA tristate "BCMA usb host driver" - depends on BCMA && EXPERIMENTAL + depends on BCMA select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD help @@ -660,7 +666,7 @@ config USB_HCD_BCMA config USB_HCD_SSB tristate "SSB usb host driver" - depends on SSB && EXPERIMENTAL + depends on SSB select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD help diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index a47e2cf..411bb74 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -150,31 +150,24 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); retval = -EFAULT; - goto fail_ioremap; + goto fail_request_resource; } - iclk = clk_get(&pdev->dev, "ehci_clk"); + iclk = devm_clk_get(&pdev->dev, "ehci_clk"); if (IS_ERR(iclk)) { dev_err(&pdev->dev, "Error getting interface clock\n"); retval = -ENOENT; - goto fail_get_iclk; + goto fail_request_resource; } - fclk = clk_get(&pdev->dev, "uhpck"); + fclk = devm_clk_get(&pdev->dev, "uhpck"); if (IS_ERR(fclk)) { dev_err(&pdev->dev, "Error getting function clock\n"); retval = -ENOENT; - goto fail_get_fclk; + goto fail_request_resource; } atmel_start_ehci(pdev); @@ -187,13 +180,6 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev) fail_add_hcd: atmel_stop_ehci(pdev); - clk_put(fclk); -fail_get_fclk: - clk_put(iclk); -fail_get_iclk: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); fail_request_resource: usb_put_hcd(hcd); fail_create_hcd: @@ -209,13 +195,9 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev) ehci_shutdown(hcd); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); atmel_stop_ehci(pdev); - clk_put(fclk); - clk_put(iclk); fclk = iclk = NULL; return 0; diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index cba10d6..65c945e 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -98,23 +98,17 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hcd->regs) { - pr_debug("ioremap failed"); + pr_debug("devm_request_and_ioremap failed"); ret = -ENOMEM; - goto err2; + goto err1; } if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) { printk(KERN_INFO "%s: controller init failed!\n", pdev->name); ret = -ENODEV; - goto err3; + goto err1; } ret = usb_add_hcd(hcd, pdev->resource[1].start, @@ -125,10 +119,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) } alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); return ret; @@ -140,8 +130,6 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c index caaa3e5..d91708d 100644 --- a/drivers/usb/host/ehci-cns3xxx.c +++ b/drivers/usb/host/ehci-cns3xxx.c @@ -105,27 +105,17 @@ static int cns3xxx_ehci_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (hcd->regs == NULL) { dev_dbg(dev, "error mapping memory\n"); retval = -EFAULT; - goto err2; + goto err1; } retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval == 0) return retval; - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); @@ -137,8 +127,6 @@ static int cns3xxx_ehci_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); /* * EHCI and OHCI share the same clock and power, diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index f0c00de..1599806 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -653,10 +653,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) seen [seen_count++].qh = p.qh; } else temp = 0; - if (p.qh) { - tag = Q_NEXT_TYPE(ehci, hw->hw_next); - p = p.qh->qh_next; - } + tag = Q_NEXT_TYPE(ehci, hw->hw_next); + p = p.qh->qh_next; break; case Q_TYPE_FSTN: temp = scnprintf (next, size, diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b7451b2..9bfde82 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, usb_put_hcd(hcd); } -static void ehci_fsl_setup_phy(struct usb_hcd *hcd, +static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc, temp; + u32 portsc; struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; @@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->controller_ver) { /* controller version 1.6 or above */ - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | - USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); + setbits32(non_ehci + FSL_SOC_USB_CTRL, + ULPI_PHY_CLK_SEL); + /* + * Due to controller issue of PHY_CLK_VALID in ULPI + * mode, we set USB_CTRL_USB_EN before checking + * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. + */ + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + UTMI_PHY_EN, USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; @@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI: if (pdata->controller_ver) { /* controller version 1.6 or above */ - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | - UTMI_PHY_EN | USB_CTRL_USB_EN); + setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } @@ -262,23 +266,33 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_NONE: break; } + + if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) { + /* check PHY_CLK_VALID to get phy clk valid */ + if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & + PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { + printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); + return -EINVAL; + } + } + ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); + + if (phy_mode != FSL_USB2_PHY_ULPI) + setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); + + return 0; } -static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) +static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) { struct usb_hcd *hcd = ehci_to_hcd(ehci); struct fsl_usb2_platform_data *pdata; void __iomem *non_ehci = hcd->regs; - u32 temp; pdata = hcd->self.controller->platform_data; - /* Enable PHY interface in the control reg. */ if (pdata->have_sysif_regs) { - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); - /* * Turn on cache snooping hardware, since some PowerPC platforms * wholly rely on hardware to deal with cache coherent @@ -293,7 +307,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) + return -EINVAL; if (pdata->operating_mode == FSL_USB2_MPH_HOST) { unsigned int chip, rev, svr; @@ -307,9 +322,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) + return -EINVAL; + if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) - ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); + if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1)) + return -EINVAL; } if (pdata->have_sysif_regs) { @@ -322,12 +340,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) #endif out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); } + + return 0; } /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_fsl_reinit(struct ehci_hcd *ehci) { - ehci_fsl_usb_setup(ehci); + if (ehci_fsl_usb_setup(ehci)) + return -EINVAL; ehci_port_power(ehci, 0); return 0; diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 8840368..dbd292e 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -61,4 +61,5 @@ #define PLL_RESET (1<<8) #define UTMI_PHY_EN (1<<9) #define ULPI_PHY_CLK_SEL (1<<10) +#define PHY_CLK_VALID (1<<17) #endif /* _EHCI_FSL_H */ diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 22ca45c..3180cb3 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -127,12 +127,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) hcd->rsrc_start = res.start; hcd->rsrc_len = resource_size(&res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); @@ -140,9 +134,9 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) goto err_irq; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&op->dev, &res); if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); + pr_err("%s: devm_request_and_ioremap failed\n", __FILE__); rv = -ENOMEM; goto err_ioremap; } @@ -161,17 +155,13 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) rv = usb_add_hcd(hcd, irq, 0); if (rv) - goto err_ehci; + goto err_ioremap; return 0; -err_ehci: - iounmap(hcd->regs); err_ioremap: irq_dispose_mapping(irq); err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: usb_put_hcd(hcd); return rv; @@ -188,9 +178,7 @@ static int ehci_hcd_grlib_remove(struct platform_device *op) usb_remove_hcd(hcd); - iounmap(hcd->regs); irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b05c686..6bf6c42 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -228,7 +228,7 @@ static int ehci_reset (struct ehci_hcd *ehci) /* If the EHCI debug controller is active, special care must be * taken before and after a host controller reset */ - if (ehci->debug && !dbgp_reset_prep()) + if (ehci->debug && !dbgp_reset_prep(ehci_to_hcd(ehci))) ehci->debug = NULL; command |= CMD_RESET; @@ -251,7 +251,7 @@ static int ehci_reset (struct ehci_hcd *ehci) tdi_reset (ehci); if (ehci->debug) - dbgp_external_startup(); + dbgp_external_startup(ehci_to_hcd(ehci)); ehci->port_c_suspend = ehci->suspended_ports = ehci->resuming_ports = 0; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index c788022..914ce93 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -353,10 +353,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd) goto shutdown; if (unlikely(ehci->debug)) { - if (!dbgp_reset_prep()) + if (!dbgp_reset_prep(hcd)) ehci->debug = NULL; else - dbgp_external_startup(); + dbgp_external_startup(hcd); } /* Ideally and we've got a real resume here, and no port's power diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index 488d401..f224c0a 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -98,30 +98,19 @@ static int ixp4xx_ehci_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); retval = -EFAULT; - goto fail_ioremap; + goto fail_request_resource; } retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) - goto fail_add_hcd; + goto fail_request_resource; return retval; -fail_add_hcd: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); fail_request_resource: usb_put_hcd(hcd); fail_create_hcd: @@ -134,8 +123,6 @@ static int ixp4xx_ehci_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c index a283e59..ca75965 100644 --- a/drivers/usb/host/ehci-ls1x.c +++ b/drivers/usb/host/ehci-ls1x.c @@ -106,29 +106,19 @@ static int ehci_hcd_ls1x_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); ret = -EFAULT; - goto err_release_region; + goto err_put_hcd; } - ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) - goto err_iounmap; + goto err_put_hcd; return ret; -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); return ret; @@ -139,8 +129,6 @@ static int ehci_hcd_ls1x_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); return 0; diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 17dd9e9..4af4dc5 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -133,7 +133,7 @@ static int ehci_msm_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; @@ -145,17 +145,17 @@ static int ehci_msm_probe(struct platform_device *pdev) * powering up VBUS, mapping of registers address space and power * management. */ - phy = usb_get_phy(USB_PHY_TYPE_USB2); + phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(phy)) { dev_err(&pdev->dev, "unable to find transceiver\n"); ret = -ENODEV; - goto unmap; + goto put_hcd; } ret = otg_set_host(phy->otg, &hcd->self); if (ret < 0) { dev_err(&pdev->dev, "unable to register with transceiver\n"); - goto put_transceiver; + goto put_hcd; } device_init_wakeup(&pdev->dev, 1); @@ -168,10 +168,6 @@ static int ehci_msm_probe(struct platform_device *pdev) return 0; -put_transceiver: - usb_put_phy(phy); -unmap: - iounmap(hcd->regs); put_hcd: usb_put_hcd(hcd); @@ -187,7 +183,6 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); otg_set_host(phy->otg, NULL); - usb_put_phy(phy); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f6df1cc..f7bfc0b 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -161,7 +161,7 @@ static int mv_ehci_probe(struct platform_device *pdev) return -ENOMEM; size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; - ehci_mv = kzalloc(size, GFP_KERNEL); + ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (ehci_mv == NULL) { dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); retval = -ENOMEM; @@ -175,12 +175,12 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv->clknum = pdata->clknum; for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { ehci_mv->clk[clk_i] = - clk_get(&pdev->dev, pdata->clkname[clk_i]); + devm_clk_get(&pdev->dev, pdata->clkname[clk_i]); if (IS_ERR(ehci_mv->clk[clk_i])) { dev_err(&pdev->dev, "error get clck \"%s\"\n", pdata->clkname[clk_i]); retval = PTR_ERR(ehci_mv->clk[clk_i]); - goto err_put_clk; + goto err_clear_drvdata; } } @@ -188,34 +188,36 @@ static int mv_ehci_probe(struct platform_device *pdev) if (r == NULL) { dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); retval = -ENODEV; - goto err_put_clk; + goto err_clear_drvdata; } - ehci_mv->phy_regs = ioremap(r->start, resource_size(r)); + ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start, + resource_size(r)); if (ehci_mv->phy_regs == 0) { dev_err(&pdev->dev, "failed to map phy I/O memory\n"); retval = -EFAULT; - goto err_put_clk; + goto err_clear_drvdata; } r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); if (!r) { dev_err(&pdev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; - goto err_iounmap_phyreg; + goto err_clear_drvdata; } - ehci_mv->cap_regs = ioremap(r->start, resource_size(r)); + ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, + resource_size(r)); if (ehci_mv->cap_regs == NULL) { dev_err(&pdev->dev, "failed to map I/O memory\n"); retval = -EFAULT; - goto err_iounmap_phyreg; + goto err_clear_drvdata; } retval = mv_ehci_enable(ehci_mv); if (retval) { dev_err(&pdev->dev, "init phy error %d\n", retval); - goto err_iounmap_capreg; + goto err_clear_drvdata; } offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; @@ -239,7 +241,7 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv->mode = pdata->mode; if (ehci_mv->mode == MV_USB_MODE_OTG) { #ifdef CONFIG_USB_OTG_UTILS - ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2); + ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(ehci_mv->otg)) { dev_err(&pdev->dev, "unable to find transceiver\n"); @@ -252,7 +254,7 @@ static int mv_ehci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to register with transceiver\n"); retval = -ENODEV; - goto err_put_transceiver; + goto err_disable_clk; } /* otg will enable clock before use as host */ mv_ehci_disable(ehci_mv); @@ -286,22 +288,10 @@ static int mv_ehci_probe(struct platform_device *pdev) err_set_vbus: if (pdata->set_vbus) pdata->set_vbus(0); -#ifdef CONFIG_USB_OTG_UTILS -err_put_transceiver: - if (!IS_ERR_OR_NULL(ehci_mv->otg)) - usb_put_phy(ehci_mv->otg); -#endif err_disable_clk: mv_ehci_disable(ehci_mv); -err_iounmap_capreg: - iounmap(ehci_mv->cap_regs); -err_iounmap_phyreg: - iounmap(ehci_mv->phy_regs); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(ehci_mv->clk[clk_i]); +err_clear_drvdata: platform_set_drvdata(pdev, NULL); - kfree(ehci_mv); err_put_hcd: usb_put_hcd(hcd); @@ -317,10 +307,8 @@ static int mv_ehci_remove(struct platform_device *pdev) if (hcd->rh_registered) usb_remove_hcd(hcd); - if (!IS_ERR_OR_NULL(ehci_mv->otg)) { + if (!IS_ERR_OR_NULL(ehci_mv->otg)) otg_set_host(ehci_mv->otg->otg, NULL); - usb_put_phy(ehci_mv->otg); - } if (ehci_mv->mode == MV_USB_MODE_HOST) { if (ehci_mv->pdata->set_vbus) @@ -329,15 +317,8 @@ static int mv_ehci_remove(struct platform_device *pdev) mv_ehci_disable(ehci_mv); } - iounmap(ehci_mv->cap_regs); - iounmap(ehci_mv->phy_regs); - - for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) - clk_put(ehci_mv->clk[clk_i]); - platform_set_drvdata(pdev, NULL); - kfree(ehci_mv); usb_put_hcd(hcd); return 0; diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 3420137..959e1a4 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -121,7 +121,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; goto err_alloc; @@ -131,34 +131,28 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) if (!res) { dev_err(dev, "Found HC with no register addr. Check setup!\n"); ret = -ENODEV; - goto err_get_resource; + goto err_alloc; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(dev, "controller already in use\n"); - ret = -EBUSY; - goto err_request_mem; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hcd->regs) { dev_err(dev, "error mapping memory\n"); ret = -EFAULT; - goto err_ioremap; + goto err_alloc; } /* enable clocks */ - priv->usbclk = clk_get(dev, "ipg"); + priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(priv->usbclk)) { ret = PTR_ERR(priv->usbclk); - goto err_clk; + goto err_alloc; } clk_prepare_enable(priv->usbclk); - priv->ahbclk = clk_get(dev, "ahb"); + priv->ahbclk = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(priv->ahbclk)) { ret = PTR_ERR(priv->ahbclk); goto err_clk_ahb; @@ -166,7 +160,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) clk_prepare_enable(priv->ahbclk); /* "dr" device has its own clock on i.MX51 */ - priv->phyclk = clk_get(dev, "phy"); + priv->phyclk = devm_clk_get(&pdev->dev, "phy"); if (IS_ERR(priv->phyclk)) priv->phyclk = NULL; if (priv->phyclk) @@ -245,23 +239,12 @@ err_add: if (pdata && pdata->exit) pdata->exit(pdev); err_init: - if (priv->phyclk) { + if (priv->phyclk) clk_disable_unprepare(priv->phyclk); - clk_put(priv->phyclk); - } clk_disable_unprepare(priv->ahbclk); - clk_put(priv->ahbclk); err_clk_ahb: clk_disable_unprepare(priv->usbclk); - clk_put(priv->usbclk); -err_clk: - iounmap(hcd->regs); -err_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_request_mem: -err_get_resource: - kfree(priv); err_alloc: usb_put_hcd(hcd); return ret; @@ -280,22 +263,14 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) usb_phy_shutdown(pdata->otg); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); clk_disable_unprepare(priv->usbclk); - clk_put(priv->usbclk); clk_disable_unprepare(priv->ahbclk); - clk_put(priv->ahbclk); - if (priv->phyclk) { + if (priv->phyclk) clk_disable_unprepare(priv->phyclk); - clk_put(priv->phyclk); - } - - kfree(priv); return 0; } diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 4b1d896..764e010 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -82,10 +82,14 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; + struct usb_ehci_pdata *pdata = dev->dev.platform_data; int irq; int err = -ENOMEM; - BUG_ON(!dev->dev.platform_data); + if (!pdata) { + WARN_ON(1); + return -ENODEV; + } if (usb_disabled()) return -ENODEV; @@ -101,10 +105,18 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) return -ENXIO; } + if (pdata->power_on) { + err = pdata->power_on(dev); + if (err < 0) + return err; + } + hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, dev_name(&dev->dev)); - if (!hcd) - return -ENOMEM; + if (!hcd) { + err = -ENOMEM; + goto err_power; + } hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); @@ -116,8 +128,10 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) + if (!hcd->regs) { + err = -ENOMEM; goto err_release_region; + } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_iounmap; @@ -132,12 +146,17 @@ err_release_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); +err_power: + if (pdata->power_off) + pdata->power_off(dev); + return err; } static int __devexit ehci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_ehci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); iounmap(hcd->regs); @@ -145,6 +164,9 @@ static int __devexit ehci_platform_remove(struct platform_device *dev) usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); + if (pdata->power_off) + pdata->power_off(dev); + return 0; } @@ -153,14 +175,32 @@ static int __devexit ehci_platform_remove(struct platform_device *dev) static int ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_ehci_pdata *pdata = dev->platform_data; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); bool do_wakeup = device_may_wakeup(dev); + int ret; + + ret = ehci_suspend(hcd, do_wakeup); - return ehci_suspend(hcd, do_wakeup); + if (pdata->power_suspend) + pdata->power_suspend(pdev); + + return ret; } static int ehci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_ehci_pdata *pdata = dev->platform_data; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + + if (pdata->power_on) { + int err = pdata->power_on(pdev); + if (err < 0) + return err; + } ehci_resume(hcd, false); return 0; diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index bbbe89d..fa937d0 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -114,12 +114,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) hcd->rsrc_start = res.start; hcd->rsrc_len = resource_size(&res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); @@ -127,9 +121,9 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) goto err_irq; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&op->dev, &res); if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); + pr_err("%s: devm_request_and_ioremap failed\n", __FILE__); rv = -ENOMEM; goto err_ioremap; } @@ -139,8 +133,10 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) if (np != NULL) { /* claim we really affected by usb23 erratum */ if (!of_address_to_resource(np, 0, &res)) - ehci->ohci_hcctrl_reg = ioremap(res.start + - OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN); + ehci->ohci_hcctrl_reg = + devm_ioremap(&op->dev, + res.start + OHCI_HCCTRL_OFFSET, + OHCI_HCCTRL_LEN); else pr_debug("%s: no ohci offset in fdt\n", __FILE__); if (!ehci->ohci_hcctrl_reg) { @@ -169,19 +165,13 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) rv = usb_add_hcd(hcd, irq, 0); if (rv) - goto err_ehci; + goto err_ioremap; return 0; -err_ehci: - if (ehci->has_amcc_usb23) - iounmap(ehci->ohci_hcctrl_reg); - iounmap(hcd->regs); err_ioremap: irq_dispose_mapping(irq); err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: usb_put_hcd(hcd); return rv; @@ -202,9 +192,7 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op) usb_remove_hcd(hcd); - iounmap(hcd->regs); irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); /* use request_mem_region to test if the ohci driver is loaded. if so * ensure the ohci core is operational. @@ -222,8 +210,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op) pr_debug("%s: no ohci offset in fdt\n", __FILE__); of_node_put(np); } - - iounmap(ehci->ohci_hcctrl_reg); } usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 9d8f1dd..d055503 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -128,7 +128,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) } s5p_ehci->hcd = hcd; - s5p_ehci->clk = clk_get(&pdev->dev, "usbhost"); + s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(s5p_ehci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); @@ -138,7 +138,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) err = clk_enable(s5p_ehci->clk); if (err) - goto fail_clken; + goto fail_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -184,8 +184,6 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) fail_io: clk_disable(s5p_ehci->clk); -fail_clken: - clk_put(s5p_ehci->clk); fail_clk: usb_put_hcd(hcd); return err; @@ -203,7 +201,6 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); clk_disable(s5p_ehci->clk); - clk_put(s5p_ehci->clk); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index 0c9e43c..efad02d 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -112,17 +112,11 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hcd->regs) { pr_debug("ioremap failed"); ret = -ENOMEM; - goto err2; + goto err1; } /* Root hub has integrated TT. */ @@ -135,9 +129,6 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) return ret; } - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); return ret; @@ -148,8 +139,6 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index b3f1e36..6081e1e 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -125,33 +125,27 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); ret = -ENXIO; - goto fail_ioremap; + goto fail_request_resource; } - priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv), + GFP_KERNEL); if (!priv) { dev_dbg(&pdev->dev, "error allocating priv data\n"); ret = -ENOMEM; - goto fail_alloc; + goto fail_request_resource; } /* These are optional, we don't care if they fail */ - priv->fclk = clk_get(&pdev->dev, "usb_fck"); + priv->fclk = devm_clk_get(&pdev->dev, "usb_fck"); if (IS_ERR(priv->fclk)) priv->fclk = NULL; - priv->iclk = clk_get(&pdev->dev, "usb_ick"); + priv->iclk = devm_clk_get(&pdev->dev, "usb_ick"); if (IS_ERR(priv->iclk)) priv->iclk = NULL; @@ -176,14 +170,6 @@ fail_add_hcd: clk_disable(priv->iclk); clk_disable(priv->fclk); - clk_put(priv->iclk); - clk_put(priv->fclk); - - kfree(priv); -fail_alloc: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); fail_request_resource: usb_put_hcd(hcd); fail_create_hcd: @@ -198,19 +184,12 @@ static int __exit ehci_hcd_sh_remove(struct platform_device *pdev) struct usb_hcd *hcd = priv->hcd; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); clk_disable(priv->fclk); clk_disable(priv->iclk); - clk_put(priv->fclk); - clk_put(priv->iclk); - - kfree(priv); - return 0; } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 26dedb3..6223d175 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -27,7 +27,7 @@ #include <linux/of_gpio.h> #include <linux/pm_runtime.h> -#include <mach/usb_phy.h> +#include <linux/usb/tegra_usb_phy.h> #include <mach/iomap.h> #define TEGRA_USB_DMA_ALIGN 32 @@ -49,7 +49,7 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) clk_prepare_enable(tegra->emc_clk); clk_prepare_enable(tegra->clk); - tegra_usb_phy_power_on(tegra->phy); + usb_phy_set_suspend(&tegra->phy->u_phy, 0); tegra->host_resumed = 1; } @@ -58,7 +58,7 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); tegra->host_resumed = 0; - tegra_usb_phy_power_off(tegra->phy); + usb_phy_set_suspend(&tegra->phy->u_phy, 1); clk_disable_unprepare(tegra->clk); clk_disable_unprepare(tegra->emc_clk); } @@ -634,7 +634,8 @@ static int tegra_ehci_probe(struct platform_device *pdev) setup_vbus_gpio(pdev, pdata); - tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL); + tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd), + GFP_KERNEL); if (!tegra) return -ENOMEM; @@ -642,13 +643,12 @@ static int tegra_ehci_probe(struct platform_device *pdev) dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto fail_hcd; + return -ENOMEM; } platform_set_drvdata(pdev, tegra); - tegra->clk = clk_get(&pdev->dev, NULL); + tegra->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tegra->clk)) { dev_err(&pdev->dev, "Can't get ehci clock\n"); err = PTR_ERR(tegra->clk); @@ -657,9 +657,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) err = clk_prepare_enable(tegra->clk); if (err) - goto fail_clken; + goto fail_clk; - tegra->emc_clk = clk_get(&pdev->dev, "emc"); + tegra->emc_clk = devm_clk_get(&pdev->dev, "emc"); if (IS_ERR(tegra->emc_clk)) { dev_err(&pdev->dev, "Can't get emc clock\n"); err = PTR_ERR(tegra->emc_clk); @@ -677,7 +677,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); + hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!hcd->regs) { dev_err(&pdev->dev, "Failed to remap I/O memory\n"); err = -ENOMEM; @@ -702,7 +702,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) default: err = -ENODEV; dev_err(&pdev->dev, "unknown usb instance\n"); - goto fail_phy; + goto fail_io; } } @@ -712,10 +712,12 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (IS_ERR(tegra->phy)) { dev_err(&pdev->dev, "Failed to open USB phy\n"); err = -ENXIO; - goto fail_phy; + goto fail_io; } - err = tegra_usb_phy_power_on(tegra->phy); + usb_phy_init(&tegra->phy->u_phy); + + err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); goto fail; @@ -733,7 +735,8 @@ static int tegra_ehci_probe(struct platform_device *pdev) #ifdef CONFIG_USB_OTG_UTILS if (pdata->operating_mode == TEGRA_USB_OTG) { - tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + tegra->transceiver = + devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (!IS_ERR_OR_NULL(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, &hcd->self); } @@ -757,25 +760,16 @@ static int tegra_ehci_probe(struct platform_device *pdev) fail: #ifdef CONFIG_USB_OTG_UTILS - if (!IS_ERR_OR_NULL(tegra->transceiver)) { + if (!IS_ERR_OR_NULL(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); - usb_put_phy(tegra->transceiver); - } #endif - tegra_usb_phy_close(tegra->phy); -fail_phy: - iounmap(hcd->regs); + usb_phy_shutdown(&tegra->phy->u_phy); fail_io: clk_disable_unprepare(tegra->emc_clk); - clk_put(tegra->emc_clk); fail_emc_clk: clk_disable_unprepare(tegra->clk); -fail_clken: - clk_put(tegra->clk); fail_clk: usb_put_hcd(hcd); -fail_hcd: - kfree(tegra); return err; } @@ -792,26 +786,19 @@ static int tegra_ehci_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); #ifdef CONFIG_USB_OTG_UTILS - if (!IS_ERR_OR_NULL(tegra->transceiver)) { + if (!IS_ERR_OR_NULL(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); - usb_put_phy(tegra->transceiver); - } #endif usb_remove_hcd(hcd); - - tegra_usb_phy_close(tegra->phy); - iounmap(hcd->regs); - usb_put_hcd(hcd); + usb_phy_shutdown(&tegra->phy->u_phy); + clk_disable_unprepare(tegra->clk); - clk_put(tegra->clk); clk_disable_unprepare(tegra->emc_clk); - clk_put(tegra->emc_clk); - kfree(tegra); return 0; } diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index eb896a2..20dbdcb 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -118,7 +118,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci) ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); return; } - ehci_warn(ehci, "Waited too long for the async schedule status, giving up\n"); + ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n", + want, actual); } ehci->ASS_poll_count = 0; @@ -163,7 +164,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); return; } - ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n"); + ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n", + want, actual); } ehci->PSS_poll_count = 0; diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c index 4d147c4..96722bf 100644 --- a/drivers/usb/host/ehci-vt8500.c +++ b/drivers/usb/host/ehci-vt8500.c @@ -16,6 +16,7 @@ * */ +#include <linux/of.h> #include <linux/platform_device.h> static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) @@ -106,17 +107,11 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hcd->regs) { pr_debug("ioremap failed"); ret = -ENOMEM; - goto err2; + goto err1; } ehci = hcd_to_ehci(hcd); @@ -129,9 +124,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev) return ret; } - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); return ret; @@ -142,14 +134,18 @@ static int vt8500_ehci_drv_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); return 0; } +static const struct of_device_id vt8500_ehci_ids[] = { + { .compatible = "via,vt8500-ehci", }, + { .compatible = "wm,prizm-ehci", }, + {} +}; + static struct platform_driver vt8500_ehci_driver = { .probe = vt8500_ehci_drv_probe, .remove = vt8500_ehci_drv_remove, @@ -157,7 +153,9 @@ static struct platform_driver vt8500_ehci_driver = { .driver = { .name = "vt8500-ehci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(vt8500_ehci_ids), } }; MODULE_ALIAS("platform:vt8500-ehci"); +MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 39f24fa..6a3f921a 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -152,12 +152,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) hcd->rsrc_start = res.start; hcd->rsrc_len = resource_size(&res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - irq = irq_of_parse_and_map(dn, 0); if (!irq) { printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); @@ -165,11 +159,11 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) goto err_irq; } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&op->dev, &res); if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); + pr_err("%s: devm_request_and_ioremap failed\n", __FILE__); rv = -ENOMEM; - goto err_ioremap; + goto err_irq; } ehci = hcd_to_ehci(hcd); @@ -200,12 +194,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) if (rv == 0) return 0; - iounmap(hcd->regs); - -err_ioremap: err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: usb_put_hcd(hcd); return rv; @@ -227,9 +216,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op) usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); return 0; diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index 2dc8a40..8f18538 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -261,8 +261,7 @@ static void move_head_to_tail(struct list_head *list) struct list_head *node = list->next; if (!list_empty(list)) { - list_del(node); - list_add_tail(node, list); + list_move_tail(node, list); } } diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 22ff6b3..1e77129 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -133,6 +133,8 @@ static int usb_get_ver_info(struct device_node *np) ver = FSL_USB_VER_1_6; else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2")) ver = FSL_USB_VER_2_2; + else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4")) + ver = FSL_USB_VER_2_4; else /* for previous controller versions */ ver = FSL_USB_VER_OLD; diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index a446386..c60066a 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -355,7 +355,7 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg"); if (IS_ERR(usb_otg_clk)) { dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n"); - ret = PTR_ERR(usb_dev_clk); + ret = PTR_ERR(usb_otg_clk); goto out6; } diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 670c705..e24ec9f 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -83,10 +83,14 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; + struct usb_ohci_pdata *pdata = dev->dev.platform_data; int irq; int err = -ENOMEM; - BUG_ON(!dev->dev.platform_data); + if (!pdata) { + WARN_ON(1); + return -ENODEV; + } if (usb_disabled()) return -ENODEV; @@ -103,10 +107,18 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) return -ENXIO; } + if (pdata->power_on) { + err = pdata->power_on(dev); + if (err < 0) + return err; + } + hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, dev_name(&dev->dev)); - if (!hcd) - return -ENOMEM; + if (!hcd) { + err = -ENOMEM; + goto err_power; + } hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); @@ -118,8 +130,10 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) + if (!hcd->regs) { + err = -ENOMEM; goto err_release_region; + } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_iounmap; @@ -134,12 +148,17 @@ err_release_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); +err_power: + if (pdata->power_off) + pdata->power_off(dev); + return err; } static int __devexit ohci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_ohci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); iounmap(hcd->regs); @@ -147,6 +166,9 @@ static int __devexit ohci_platform_remove(struct platform_device *dev) usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); + if (pdata->power_off) + pdata->power_off(dev); + return 0; } @@ -154,12 +176,28 @@ static int __devexit ohci_platform_remove(struct platform_device *dev) static int ohci_platform_suspend(struct device *dev) { + struct usb_ohci_pdata *pdata = dev->platform_data; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + + if (pdata->power_suspend) + pdata->power_suspend(pdev); + return 0; } static int ohci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_ohci_pdata *pdata = dev->platform_data; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + + if (pdata->power_on) { + int err = pdata->power_on(pdev); + if (err < 0) + return err; + } ohci_finish_controller_resume(hcd); return 0; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index e1a3cc6..77f4402 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -23,6 +23,8 @@ #include <linux/signal.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> #include <mach/hardware.h> #include <mach/ohci.h> #include <mach/pxa3xx-u2d.h> @@ -272,6 +274,67 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) clk_disable_unprepare(ohci->clk); } +#ifdef CONFIG_OF +static const struct of_device_id pxa_ohci_dt_ids[] = { + { .compatible = "marvell,pxa-ohci" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids); + +static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32); + +static int __devinit ohci_pxa_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct pxaohci_platform_data *pdata; + u32 tmp; + + if (!np) + return 0; + + /* Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pxa_ohci_dma_mask; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "marvell,enable-port1", NULL)) + pdata->flags |= ENABLE_PORT1; + if (of_get_property(np, "marvell,enable-port2", NULL)) + pdata->flags |= ENABLE_PORT2; + if (of_get_property(np, "marvell,enable-port3", NULL)) + pdata->flags |= ENABLE_PORT3; + if (of_get_property(np, "marvell,port-sense-low", NULL)) + pdata->flags |= POWER_SENSE_LOW; + if (of_get_property(np, "marvell,power-control-low", NULL)) + pdata->flags |= POWER_CONTROL_LOW; + if (of_get_property(np, "marvell,no-oc-protection", NULL)) + pdata->flags |= NO_OC_PROTECTION; + if (of_get_property(np, "marvell,oc-mode-perport", NULL)) + pdata->flags |= OC_MODE_PERPORT; + if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp)) + pdata->power_on_delay = tmp; + if (!of_property_read_u32(np, "marvell,port-mode", &tmp)) + pdata->port_mode = tmp; + if (!of_property_read_u32(np, "marvell,power-budget", &tmp)) + pdata->power_budget = tmp; + + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static int __devinit ohci_pxa_of_init(struct platform_device *pdev) +{ + return 0; +} +#endif /*-------------------------------------------------------------------------*/ @@ -297,6 +360,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device struct resource *r; struct clk *usb_clk; + retval = ohci_pxa_of_init(pdev); + if (retval) + return retval; + inf = pdev->dev.platform_data; if (!inf) @@ -544,6 +611,7 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { .driver = { .name = "pxa27x-ohci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pxa_ohci_dt_ids), #ifdef CONFIG_PM .pm = &ohci_hcd_pxa27x_pm_ops, #endif diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c index 41e378f..84201cd 100644 --- a/drivers/usb/host/ohci-xls.c +++ b/drivers/usb/host/ohci-xls.c @@ -56,7 +56,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver, goto err3; } - retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval != 0) goto err4; return retval; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 4c634eb..fcc09e5 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2029,15 +2029,14 @@ static int r8a66597_get_frame(struct usb_hcd *hcd) static void collect_usb_address_map(struct usb_device *udev, unsigned long *map) { int chix; + struct usb_device *childdev; if (udev->state == USB_STATE_CONFIGURED && udev->parent && udev->parent->devnum > 1 && udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB) map[udev->devnum/32] |= (1 << (udev->devnum % 32)); - for (chix = 0; chix < udev->maxchild; chix++) { - struct usb_device *childdev = udev->children[chix]; - + usb_hub_for_each_child(udev, chix, childdev) { if (childdev) collect_usb_address_map(childdev, map); } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 91ce1c0..619b05f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -156,7 +156,7 @@ static void setup_packet( writeb(SL_SETUP /* | ep->epnum */, data_reg); writeb(usb_pipedevice(urb->pipe), data_reg); - /* always OUT/data0 */ ; + /* always OUT/data0 */ sl811_write(sl811, bank + SL11H_HOSTCTLREG, control | SL11H_HCTLMASK_OUT); ep->length = 0; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e4db350..4b9e9ab 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -846,6 +846,11 @@ static const char hcd_name[] = "uhci_hcd"; #define PLATFORM_DRIVER uhci_grlib_driver #endif +#ifdef CONFIG_USB_UHCI_PLATFORM +#include "uhci-platform.c" +#define PLATFORM_DRIVER uhci_platform_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) #error "missing bus glue for uhci-hcd" #endif diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c new file mode 100644 index 0000000..e478049 --- /dev/null +++ b/drivers/usb/host/uhci-platform.c @@ -0,0 +1,157 @@ +/* + * Generic UHCI HCD (Host Controller Driver) for Platform Devices + * + * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz> + * + * This file is based on uhci-grlib.c + * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu + */ + +#include <linux/of.h> +#include <linux/platform_device.h> + +static int uhci_platform_init(struct usb_hcd *hcd) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + uhci->rh_numports = uhci_count_ports(hcd); + + /* Set up pointers to to generic functions */ + uhci->reset_hc = uhci_generic_reset_hc; + uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; + + /* No special actions need to be taken for the functions below */ + uhci->configure_hc = NULL; + uhci->resume_detect_interrupts_are_broken = NULL; + uhci->global_suspend_mode_is_broken = NULL; + + /* Reset if the controller isn't already safely quiescent. */ + check_and_reset_hc(uhci); + return 0; +} + +static const struct hc_driver uhci_platform_hc_driver = { + .description = hcd_name, + .product_desc = "Generic UHCI Host Controller", + .hcd_priv_size = sizeof(struct uhci_hcd), + + /* Generic hardware linkage */ + .irq = uhci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + /* Basic lifecycle operations */ + .reset = uhci_platform_init, + .start = uhci_start, +#ifdef CONFIG_PM + .pci_suspend = NULL, + .pci_resume = NULL, + .bus_suspend = uhci_rh_suspend, + .bus_resume = uhci_rh_resume, +#endif + .stop = uhci_stop, + + .urb_enqueue = uhci_urb_enqueue, + .urb_dequeue = uhci_urb_dequeue, + + .endpoint_disable = uhci_hcd_endpoint_disable, + .get_frame_number = uhci_hcd_get_frame_number, + + .hub_status_data = uhci_hub_status_data, + .hub_control = uhci_hub_control, +}; + + +static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct uhci_hcd *uhci; + struct resource *res; + int ret; + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, + pdev->name); + if (!hcd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_err("%s: request_mem_region failed\n", __func__); + ret = -EBUSY; + goto err_rmr; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_err("%s: ioremap failed\n", __func__); + ret = -ENOMEM; + goto err_irq; + } + uhci = hcd_to_uhci(hcd); + + uhci->regs = hcd->regs; + + ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED | + IRQF_SHARED); + if (ret) + goto err_uhci; + + return 0; + +err_uhci: + iounmap(hcd->regs); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return ret; +} + +static int uhci_hcd_platform_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +/* Make sure the controller is quiescent and that we're not using it + * any more. This is mainly for the benefit of programs which, like kexec, + * expect the hardware to be idle: not doing DMA or generating IRQs. + * + * This routine may be called in a damaged or failing kernel. Hence we + * do not acquire the spinlock before shutting down the controller. + */ +static void uhci_hcd_platform_shutdown(struct platform_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + uhci_hc_died(hcd_to_uhci(hcd)); +} + +static const struct of_device_id platform_uhci_ids[] = { + { .compatible = "platform-uhci", }, + {} +}; + +static struct platform_driver uhci_platform_driver = { + .probe = uhci_hcd_platform_probe, + .remove = uhci_hcd_platform_remove, + .shutdown = uhci_hcd_platform_shutdown, + .driver = { + .name = "platform-uhci", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(platform_uhci_ids), + }, +}; diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 1e141f7..c3a6478 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -238,16 +238,16 @@ static struct hc_driver whc_hc_driver = { static int whc_probe(struct umc_dev *umc) { - int ret = -ENOMEM; + int ret; struct usb_hcd *usb_hcd; - struct wusbhc *wusbhc = NULL; - struct whc *whc = NULL; + struct wusbhc *wusbhc; + struct whc *whc; struct device *dev = &umc->dev; usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci"); if (usb_hcd == NULL) { dev_err(dev, "unable to create hcd\n"); - goto error; + return -ENOMEM; } usb_hcd->wireless = 1; diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 76083ae..dc31c42 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -436,7 +436,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u int i; int ntds = 0; struct whc_std *std = NULL; - struct whc_page_list_entry *entry; + struct whc_page_list_entry *new_pl_virt; dma_addr_t prev_end = 0; size_t pl_len; int p = 0; @@ -508,12 +508,15 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); - std->pl_virt = krealloc(std->pl_virt, pl_len, mem_flags); - if (std->pl_virt == NULL) { + new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags); + if (new_pl_virt == NULL) { + kfree(std->pl_virt); + std->pl_virt = NULL; return -ENOMEM; } + std->pl_virt = new_pl_virt; - for (;p < std->num_pointers; p++, entry++) { + for (;p < std->num_pointers; p++) { std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1); } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index d5eb357..aa90ad4 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -29,7 +29,7 @@ #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ PORT_RC | PORT_PLC | PORT_PE) -/* usb 1.1 root hub device descriptor */ +/* USB 3.0 BOS descriptor and a capability descriptor, combined */ static u8 usb_bos_descriptor [] = { USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ USB_DT_BOS, /* __u8 bDescriptorType */ @@ -422,7 +422,7 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, xhci_writel(xhci, temp, port_array[port_id]); } -void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, +static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u16 wake_mask) { u32 temp; @@ -808,6 +808,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); + + temp = usb_acpi_power_manageable(hcd->self.root_hub, + wIndex); + if (temp) + usb_acpi_set_power_state(hcd->self.root_hub, + wIndex, true); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); @@ -907,6 +913,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_disable_port(hcd, xhci, wIndex, port_array[wIndex], temp); break; + case USB_PORT_FEAT_POWER: + xhci_writel(xhci, temp & ~PORT_POWER, + port_array[wIndex]); + + temp = usb_acpi_power_manageable(hcd->self.root_hub, + wIndex); + if (temp) + usb_acpi_set_power_state(hcd->self.root_hub, + wIndex, false); + break; default: goto error; } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 77689bd..487bc08 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1772,6 +1772,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; + struct xhci_cd *cur_cd, *next_cd; unsigned long flags; int size; int i, j, num_ports; @@ -1795,6 +1796,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; xhci_dbg(xhci, "Freed command ring\n"); + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + } for (i = 1; i < MAX_HC_SLOTS; ++i) xhci_free_virt_device(xhci, i); @@ -2340,6 +2346,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; + INIT_LIST_HEAD(&xhci->cancel_cmd_list); xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); xhci_dbg(xhci, "First segment DMA is 0x%llx\n", (unsigned long long)xhci->cmd_ring->first_seg->dma); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9bfd4ca11..8345d7c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -103,6 +103,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; + xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_ASROCK_P67) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 643c2f3..c6ebb17 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -280,12 +280,123 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, /* Ring the host controller doorbell after placing a command on the ring */ void xhci_ring_cmd_db(struct xhci_hcd *xhci) { + if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) + return; + xhci_dbg(xhci, "// Ding dong!\n"); xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); /* Flush PCI posted writes */ xhci_readl(xhci, &xhci->dba->doorbell[0]); } +static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) +{ + u64 temp_64; + int ret; + + xhci_dbg(xhci, "Abort command ring\n"); + + if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) { + xhci_dbg(xhci, "The command ring isn't running, " + "Have the command ring been stopped?\n"); + return 0; + } + + temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + if (!(temp_64 & CMD_RING_RUNNING)) { + xhci_dbg(xhci, "Command ring had been stopped\n"); + return 0; + } + xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; + xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, + &xhci->op_regs->cmd_ring); + + /* Section 4.6.1.2 of xHCI 1.0 spec says software should + * time the completion od all xHCI commands, including + * the Command Abort operation. If software doesn't see + * CRR negated in a timely manner (e.g. longer than 5 + * seconds), then it should assume that the there are + * larger problems with the xHC and assert HCRST. + */ + ret = handshake(xhci, &xhci->op_regs->cmd_ring, + CMD_RING_RUNNING, 0, 5 * 1000 * 1000); + if (ret < 0) { + xhci_err(xhci, "Stopped the command ring failed, " + "maybe the host is dead\n"); + xhci->xhc_state |= XHCI_STATE_DYING; + xhci_quiesce(xhci); + xhci_halt(xhci); + return -ESHUTDOWN; + } + + return 0; +} + +static int xhci_queue_cd(struct xhci_hcd *xhci, + struct xhci_command *command, + union xhci_trb *cmd_trb) +{ + struct xhci_cd *cd; + cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC); + if (!cd) + return -ENOMEM; + INIT_LIST_HEAD(&cd->cancel_cmd_list); + + cd->command = command; + cd->cmd_trb = cmd_trb; + list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list); + + return 0; +} + +/* + * Cancel the command which has issue. + * + * Some commands may hang due to waiting for acknowledgement from + * usb device. It is outside of the xHC's ability to control and + * will cause the command ring is blocked. When it occurs software + * should intervene to recover the command ring. + * See Section 4.6.1.1 and 4.6.1.2 + */ +int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, + union xhci_trb *cmd_trb) +{ + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&xhci->lock, flags); + + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_warn(xhci, "Abort the command ring," + " but the xHCI is dead.\n"); + retval = -ESHUTDOWN; + goto fail; + } + + /* queue the cmd desriptor to cancel_cmd_list */ + retval = xhci_queue_cd(xhci, command, cmd_trb); + if (retval) { + xhci_warn(xhci, "Queuing command descriptor failed.\n"); + goto fail; + } + + /* abort command ring */ + retval = xhci_abort_cmd_ring(xhci); + if (retval) { + xhci_err(xhci, "Abort command ring failed\n"); + if (unlikely(retval == -ESHUTDOWN)) { + spin_unlock_irqrestore(&xhci->lock, flags); + usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); + xhci_dbg(xhci, "xHCI host controller is dead.\n"); + return retval; + } + } + +fail: + spin_unlock_irqrestore(&xhci->lock, flags); + return retval; +} + void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, @@ -1059,6 +1170,20 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, } } +/* Complete the command and detele it from the devcie's command queue. + */ +static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, + struct xhci_command *command, u32 status) +{ + command->status = status; + list_del(&command->cmd_list); + if (command->completion) + complete(command->completion); + else + xhci_free_command(xhci, command); +} + + /* Check to see if a command in the device's command queue matches this one. * Signal the completion or free the command, and return 1. Return 0 if the * completed command isn't at the head of the command list. @@ -1077,15 +1202,144 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, if (xhci->cmd_ring->dequeue != command->command_trb) return 0; - command->status = GET_COMP_CODE(le32_to_cpu(event->status)); - list_del(&command->cmd_list); - if (command->completion) - complete(command->completion); - else - xhci_free_command(xhci, command); + xhci_complete_cmd_in_cmd_wait_list(xhci, command, + GET_COMP_CODE(le32_to_cpu(event->status))); return 1; } +/* + * Finding the command trb need to be cancelled and modifying it to + * NO OP command. And if the command is in device's command wait + * list, finishing and freeing it. + * + * If we can't find the command trb, we think it had already been + * executed. + */ +static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) +{ + struct xhci_segment *cur_seg; + union xhci_trb *cmd_trb; + u32 cycle_state; + + if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue) + return; + + /* find the current segment of command ring */ + cur_seg = find_trb_seg(xhci->cmd_ring->first_seg, + xhci->cmd_ring->dequeue, &cycle_state); + + /* find the command trb matched by cd from command ring */ + for (cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb != xhci->cmd_ring->enqueue; + next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) { + /* If the trb is link trb, continue */ + if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3])) + continue; + + if (cur_cd->cmd_trb == cmd_trb) { + + /* If the command in device's command list, we should + * finish it and free the command structure. + */ + if (cur_cd->command) + xhci_complete_cmd_in_cmd_wait_list(xhci, + cur_cd->command, COMP_CMD_STOP); + + /* get cycle state from the origin command trb */ + cycle_state = le32_to_cpu(cmd_trb->generic.field[3]) + & TRB_CYCLE; + + /* modify the command trb to NO OP command */ + cmd_trb->generic.field[0] = 0; + cmd_trb->generic.field[1] = 0; + cmd_trb->generic.field[2] = 0; + cmd_trb->generic.field[3] = cpu_to_le32( + TRB_TYPE(TRB_CMD_NOOP) | cycle_state); + break; + } + } +} + +static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci) +{ + struct xhci_cd *cur_cd, *next_cd; + + if (list_empty(&xhci->cancel_cmd_list)) + return; + + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + xhci_cmd_to_noop(xhci, cur_cd); + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + } +} + +/* + * traversing the cancel_cmd_list. If the command descriptor according + * to cmd_trb is found, the function free it and return 1, otherwise + * return 0. + */ +static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci, + union xhci_trb *cmd_trb) +{ + struct xhci_cd *cur_cd, *next_cd; + + if (list_empty(&xhci->cancel_cmd_list)) + return 0; + + list_for_each_entry_safe(cur_cd, next_cd, + &xhci->cancel_cmd_list, cancel_cmd_list) { + if (cur_cd->cmd_trb == cmd_trb) { + if (cur_cd->command) + xhci_complete_cmd_in_cmd_wait_list(xhci, + cur_cd->command, COMP_CMD_STOP); + list_del(&cur_cd->cancel_cmd_list); + kfree(cur_cd); + return 1; + } + } + + return 0; +} + +/* + * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the + * trb pointed by the command ring dequeue pointer is the trb we want to + * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will + * traverse the cancel_cmd_list to trun the all of the commands according + * to command descriptor to NO-OP trb. + */ +static int handle_stopped_cmd_ring(struct xhci_hcd *xhci, + int cmd_trb_comp_code) +{ + int cur_trb_is_good = 0; + + /* Searching the cmd trb pointed by the command ring dequeue + * pointer in command descriptor list. If it is found, free it. + */ + cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci, + xhci->cmd_ring->dequeue); + + if (cmd_trb_comp_code == COMP_CMD_ABORT) + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + else if (cmd_trb_comp_code == COMP_CMD_STOP) { + /* traversing the cancel_cmd_list and canceling + * the command according to command descriptor + */ + xhci_cancel_cmd_in_cd_list(xhci); + + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + /* + * ring command ring doorbell again to restart the + * command ring + */ + if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) + xhci_ring_cmd_db(xhci); + } + return cur_trb_is_good; +} + static void handle_cmd_completion(struct xhci_hcd *xhci, struct xhci_event_cmd *event) { @@ -1111,6 +1365,22 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci->error_bitmask |= 1 << 5; return; } + + if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) || + (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) { + /* If the return value is 0, we think the trb pointed by + * command ring dequeue pointer is a good trb. The good + * trb means we don't want to cancel the trb, but it have + * been stopped by host. So we should handle it normally. + * Otherwise, driver should invoke inc_deq() and return. + */ + if (handle_stopped_cmd_ring(xhci, + GET_COMP_CODE(le32_to_cpu(event->status)))) { + inc_deq(xhci, xhci->cmd_ring); + return; + } + } + switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) & TRB_TYPE_BITMASK) { case TRB_TYPE(TRB_ENABLE_SLOT): @@ -2003,6 +2273,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, */ static int handle_tx_event(struct xhci_hcd *xhci, struct xhci_transfer_event *event) + __releases(&xhci->lock) + __acquires(&xhci->lock) { struct xhci_virt_device *xdev; struct xhci_virt_ep *ep; @@ -2580,7 +2852,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, xhci_err(xhci, "Ring expansion failed\n"); return -ENOMEM; } - }; + } if (enqueue_is_link_trb(ep_ring)) { struct xhci_ring *ring = ep_ring; @@ -3400,7 +3672,9 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; - if (xhci->hci_version == 0x100) { + if (xhci->hci_version == 0x100 && + !(xhci->quirks & + XHCI_AVOID_BEI)) { /* Set BEI bit except for the last td */ if (i < num_tds - 1) field |= TRB_BEI; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6ece0ed..8d7fcbb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -static int handshake(struct xhci_hcd *xhci, void __iomem *ptr, +int handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -105,9 +105,10 @@ int xhci_halt(struct xhci_hcd *xhci) ret = handshake(xhci, &xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); - if (!ret) + if (!ret) { xhci->xhc_state |= XHCI_STATE_HALTED; - else + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + } else xhci_warn(xhci, "Host not halted after %u microseconds.\n", XHCI_MAX_HALT_USEC); return ret; @@ -470,6 +471,8 @@ static bool compliance_mode_recovery_timer_quirk_check(void) dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!dmi_product_name || !dmi_sys_vendor) + return false; if (!(strstr(dmi_sys_vendor, "Hewlett-Packard"))) return false; @@ -581,6 +584,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci) return -ENODEV; } xhci->shared_hcd->state = HC_STATE_RUNNING; + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); @@ -886,7 +890,7 @@ int xhci_suspend(struct xhci_hcd *xhci) command &= ~CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); if (handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, 100*100)) { + STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; @@ -1948,7 +1952,7 @@ static void xhci_finish_resource_reservation(struct xhci_hcd *xhci, xhci->num_active_eps); } -unsigned int xhci_get_block_size(struct usb_device *udev) +static unsigned int xhci_get_block_size(struct usb_device *udev) { switch (udev->speed) { case USB_SPEED_LOW: @@ -1966,7 +1970,8 @@ unsigned int xhci_get_block_size(struct usb_device *udev) } } -unsigned int xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw) +static unsigned int +xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw) { if (interval_bw->overhead[LS_OVERHEAD_TYPE]) return LS_OVERHEAD; @@ -2521,6 +2526,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, struct completion *cmd_completion; u32 *cmd_status; struct xhci_virt_device *virt_dev; + union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); virt_dev = xhci->devs[udev->slot_id]; @@ -2566,6 +2572,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, } init_completion(cmd_completion); + cmd_trb = xhci->cmd_ring->dequeue; if (!ctx_change) ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, udev->slot_id, must_succeed); @@ -2587,14 +2594,17 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, /* Wait for the configure endpoint command to complete */ timeleft = wait_for_completion_interruptible_timeout( cmd_completion, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for %s command\n", timeleft == 0 ? "Timeout" : "Signal", ctx_change == 0 ? "configure endpoint" : "evaluate context"); - /* FIXME cancel the configure endpoint command */ + /* cancel the configure endpoint command */ + ret = xhci_cancel_cmd(xhci, command, cmd_trb); + if (ret < 0) + return ret; return -ETIME; } @@ -3543,8 +3553,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) unsigned long flags; int timeleft; int ret; + union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); + cmd_trb = xhci->cmd_ring->dequeue; ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -3556,12 +3568,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) /* XXX: how much time for xHC slot assignment? */ timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for a slot\n", timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the enable slot request */ - return 0; + /* cancel the enable slot request */ + return xhci_cancel_cmd(xhci, NULL, cmd_trb); } if (!xhci->slot_id) { @@ -3622,6 +3634,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_slot_ctx *slot_ctx; struct xhci_input_control_ctx *ctrl_ctx; u64 temp_64; + union xhci_trb *cmd_trb; if (!udev->slot_id) { xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); @@ -3660,6 +3673,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); spin_lock_irqsave(&xhci->lock, flags); + cmd_trb = xhci->cmd_ring->dequeue; ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret) { @@ -3672,7 +3686,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); + XHCI_CMD_DEFAULT_TIMEOUT); /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. @@ -3680,7 +3694,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for address device command\n", timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the address device command */ + /* cancel the address device command */ + ret = xhci_cancel_cmd(xhci, NULL, cmd_trb); + if (ret < 0) + return ret; return -ETIME; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 1a05908..53df4e7 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1256,6 +1256,16 @@ struct xhci_td { union xhci_trb *last_trb; }; +/* xHCI command default timeout value */ +#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ) + +/* command descriptor */ +struct xhci_cd { + struct list_head cancel_cmd_list; + struct xhci_command *command; + union xhci_trb *cmd_trb; +}; + struct xhci_dequeue_state { struct xhci_segment *new_deq_seg; union xhci_trb *new_deq_ptr; @@ -1421,6 +1431,11 @@ struct xhci_hcd { /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; + unsigned int cmd_ring_state; +#define CMD_RING_STATE_RUNNING (1 << 0) +#define CMD_RING_STATE_ABORTED (1 << 1) +#define CMD_RING_STATE_STOPPED (1 << 2) + struct list_head cancel_cmd_list; unsigned int cmd_ring_reserved_trbs; struct xhci_ring *event_ring; struct xhci_erst erst; @@ -1496,6 +1511,7 @@ struct xhci_hcd { #define XHCI_INTEL_HOST (1 << 12) #define XHCI_SPURIOUS_REBOOT (1 << 13) #define XHCI_COMP_MODE_QUIRK (1 << 14) +#define XHCI_AVOID_BEI (1 << 15) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1704,6 +1720,8 @@ static inline void xhci_unregister_plat(void) /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); +int handshake(struct xhci_hcd *xhci, void __iomem *ptr, + u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_reset(struct xhci_hcd *xhci); @@ -1794,6 +1812,8 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); void xhci_stop_endpoint_command_watchdog(unsigned long arg); +int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, + union xhci_trb *cmd_trb); void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 1bfcd02..a8f0523 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -244,3 +244,8 @@ config USB_YUREX To compile this driver as a module, choose M here: the module will be called yurex. +config USB_EZUSB_FX2 + tristate "Functions for loading firmware on EZUSB chips" + help + Say Y here if you need EZUSB device support. + (Cypress FX/FX2/FX2LP microcontrollers) diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 796ce7eb..3e99a64 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_USB_CYPRESS_CY7C63) += cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o +obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c new file mode 100644 index 0000000..4223d76 --- /dev/null +++ b/drivers/usb/misc/ezusb.c @@ -0,0 +1,160 @@ +/* + * EZ-USB specific functions used by some of the USB to Serial drivers. + * + * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/firmware.h> +#include <linux/ihex.h> + +struct ezusb_fx_type { + /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ + unsigned short cpucs_reg; + unsigned short max_internal_adress; +}; + +struct ezusb_fx_type ezusb_fx1 = { + .cpucs_reg = 0x7F92, + .max_internal_adress = 0x1B3F, +}; + +struct ezusb_fx_type ezusb_fx2 = { + .cpucs_reg = 0xE600, + .max_internal_adress = 0x3FFF, +}; + +/* Commands for writing to memory */ +#define WRITE_INT_RAM 0xA0 +#define WRITE_EXT_RAM 0xA3 + +int ezusb_writememory(struct usb_device *dev, int address, + unsigned char *data, int length, __u8 request) +{ + int result; + unsigned char *transfer_buffer; + + if (!dev) + return -ENODEV; + + transfer_buffer = kmemdup(data, length, GFP_KERNEL); + if (!transfer_buffer) { + dev_err(&dev->dev, "%s - kmalloc(%d) failed.\n", + __func__, length); + return -ENOMEM; + } + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + address, 0, transfer_buffer, length, 3000); + + kfree(transfer_buffer); + return result; +} +EXPORT_SYMBOL_GPL(ezusb_writememory); + +int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, + unsigned char reset_bit) +{ + int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM); + if (response < 0) + dev_err(&dev->dev, "%s-%d failed: %d\n", + __func__, reset_bit, response); + return response; +} + +int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit) +{ + return ezusb_set_reset(dev, ezusb_fx1.cpucs_reg, reset_bit); +} +EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset); + +int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit) +{ + return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); +} +EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); + +static int ezusb_ihex_firmware_download(struct usb_device *dev, + struct ezusb_fx_type fx, + const char *firmware_path) +{ + int ret = -ENOENT; + const struct firmware *firmware = NULL; + const struct ihex_binrec *record; + + if (request_ihex_firmware(&firmware, firmware_path, + &dev->dev)) { + dev_err(&dev->dev, + "%s - request \"%s\" failed\n", + __func__, firmware_path); + goto out; + } + + ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); + if (ret < 0) + goto out; + + record = (const struct ihex_binrec *)firmware->data; + for (; record; record = ihex_next_binrec(record)) { + if (be32_to_cpu(record->addr) > fx.max_internal_adress) { + ret = ezusb_writememory(dev, be32_to_cpu(record->addr), + (unsigned char *)record->data, + be16_to_cpu(record->len), WRITE_EXT_RAM); + if (ret < 0) { + dev_err(&dev->dev, "%s - ezusb_writememory " + "failed writing internal memory " + "(%d %04X %p %d)\n", __func__, ret, + be32_to_cpu(record->addr), record->data, + be16_to_cpu(record->len)); + goto out; + } + } + } + + ret = ezusb_set_reset(dev, fx.cpucs_reg, 1); + if (ret < 0) + goto out; + record = (const struct ihex_binrec *)firmware->data; + for (; record; record = ihex_next_binrec(record)) { + if (be32_to_cpu(record->addr) <= fx.max_internal_adress) { + ret = ezusb_writememory(dev, be32_to_cpu(record->addr), + (unsigned char *)record->data, + be16_to_cpu(record->len), WRITE_INT_RAM); + if (ret < 0) { + dev_err(&dev->dev, "%s - ezusb_writememory " + "failed writing external memory " + "(%d %04X %p %d)\n", __func__, ret, + be32_to_cpu(record->addr), record->data, + be16_to_cpu(record->len)); + goto out; + } + } + } + ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); +out: + release_firmware(firmware); + return ret; +} + +int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, + const char *firmware_path) +{ + return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path); +} +EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download); + +int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, + const char *firmware_path) +{ + return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path); +} +EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download); + diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index a2702cb..8089479 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -868,9 +868,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dbg(2, "%s: enter", __func__); - if (udev == NULL) - dev_info(&interface->dev, "udev is NULL.\n"); - /* allocate memory for our device state and initialize it */ dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 1084124..b9b356a 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -338,7 +338,7 @@ write_rio(struct file *file, const char __user *buffer, thistime -= partial; } else break; - }; + } if (result) { dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n", result); diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 6259f0d..23a0b7f 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -12,7 +12,6 @@ config USB_MUSB_HDRC select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS - select USB_GADGET_DUALSPEED help Say Y here if your system has a dual role high speed USB controller based on the Mentor Graphics silicon IP. Then @@ -20,7 +19,7 @@ config USB_MUSB_HDRC it's being used with, including the USB peripheral role, or the USB host role, or both. - Texas Instruments familiies using this IP include DaVinci + Texas Instruments families using this IP include DaVinci (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010. Analog Devices parts using this IP include Blackfin BF54x, diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 7a95ab8..457f25e 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -33,6 +33,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/usb/nop-usb-xceiv.h> #include <plat/usb.h> @@ -107,9 +108,8 @@ static void am35x_musb_enable(struct musb *musb) musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK); /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - if (is_otg_enabled(musb)) - musb_writel(reg_base, CORE_INTR_SRC_SET_REG, - AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT); + musb_writel(reg_base, CORE_INTR_SRC_SET_REG, + AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT); } /* @@ -173,9 +173,6 @@ static void otg_timer(unsigned long _musb) MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); break; case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); @@ -192,9 +189,6 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) { static unsigned long last_timer; - if (!is_otg_enabled(musb)) - return; - if (timeout == 0) timeout = jiffies + msecs_to_jiffies(3); @@ -271,8 +265,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err; - err = is_host_enabled(musb) && (musb->int_usb & - MUSB_INTR_VBUSERROR); + err = musb->int_usb & MUSB_INTR_VBUSERROR; if (err) { /* * The Mentor core doesn't debounce VBUS as needed @@ -289,7 +282,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); - } else if (is_host_enabled(musb) && drvvbus) { + } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; @@ -326,7 +319,7 @@ eoi: } /* Poll for ID change */ - if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); @@ -369,8 +362,7 @@ static int am35x_musb_init(struct musb *musb) if (IS_ERR_OR_NULL(musb->xceiv)) return -ENODEV; - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); + setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); /* Reset the musb */ if (data->reset) @@ -400,8 +392,7 @@ static int am35x_musb_exit(struct musb *musb) struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); + del_timer_sync(&otg_workaround); /* Shutdown the on-chip PHY and its PLL. */ if (data->set_phy_power) @@ -468,6 +459,7 @@ static int __devinit am35x_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; + int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -475,38 +467,47 @@ static int __devinit am35x_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } phy_clk = clk_get(&pdev->dev, "fck"); if (IS_ERR(phy_clk)) { dev_err(&pdev->dev, "failed to get PHY clock\n"); ret = PTR_ERR(phy_clk); - goto err2; + goto err3; } clk = clk_get(&pdev->dev, "ick"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err3; + goto err4; } ret = clk_enable(phy_clk); if (ret) { dev_err(&pdev->dev, "failed to enable PHY clock\n"); - goto err4; + goto err5; } ret = clk_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err5; + goto err6; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &am35x_dmamask; musb->dev.coherent_dma_mask = am35x_dmamask; @@ -524,38 +525,41 @@ static int __devinit am35x_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err6; + goto err7; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err6; + goto err7; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err6; + goto err7; } return 0; -err6: +err7: clk_disable(clk); -err5: +err6: clk_disable(phy_clk); -err4: +err5: clk_put(clk); -err3: +err4: clk_put(phy_clk); -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -567,6 +571,7 @@ static int __devexit am35x_remove(struct platform_device *pdev) { struct am35x_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); clk_disable(glue->clk); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 428e6aa..e8cff9b 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/prefetch.h> +#include <linux/usb/nop-usb-xceiv.h> #include <asm/cacheflush.h> @@ -184,8 +185,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci) } /* Start sampling ID pin, when plug is removed from MUSB */ - if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE - || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) || + if ((musb->xceiv->state == OTG_STATE_B_IDLE + || musb->xceiv->state == OTG_STATE_A_WAIT_BCON) || (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) { mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); musb->a_wait_bcon = TIMER_DELAY; @@ -228,18 +229,13 @@ static void musb_conn_timer_handler(unsigned long _musb) val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; musb_writeb(musb->mregs, MUSB_INTRUSB, val); - if (is_otg_enabled(musb)) - musb->xceiv->state = OTG_STATE_B_IDLE; - else - musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB); + musb->xceiv->state = OTG_STATE_B_IDLE; } mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); break; case OTG_STATE_B_IDLE: - - if (!is_peripheral_enabled(musb)) - break; - /* Start a new session. It seems that MUSB needs taking + /* + * Start a new session. It seems that MUSB needs taking * some time to recognize the type of the plug inserted? */ val = musb_readw(musb->mregs, MUSB_DEVCTL); @@ -295,10 +291,7 @@ static void musb_conn_timer_handler(unsigned long _musb) static void bfin_musb_enable(struct musb *musb) { - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); - musb->a_wait_bcon = TIMER_DELAY; - } + /* REVISIT is this really correct ? */ } static void bfin_musb_disable(struct musb *musb) @@ -323,12 +316,6 @@ static int bfin_musb_set_power(struct usb_phy *x, unsigned mA) return 0; } -static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); -} - static int bfin_musb_vbus_status(struct musb *musb) { return 0; @@ -424,12 +411,10 @@ static int bfin_musb_init(struct musb *musb) bfin_musb_reg_init(musb); - if (is_host_enabled(musb)) { - setup_timer(&musb_conn_timer, - musb_conn_timer_handler, (unsigned long) musb); - } - if (is_peripheral_enabled(musb)) - musb->xceiv->set_power = bfin_musb_set_power; + setup_timer(&musb_conn_timer, musb_conn_timer_handler, + (unsigned long) musb); + + musb->xceiv->set_power = bfin_musb_set_power; musb->isr = blackfin_interrupt; musb->double_buffer_not_ok = true; @@ -454,7 +439,6 @@ static const struct musb_platform_ops bfin_ops = { .disable = bfin_musb_disable, .set_mode = bfin_musb_set_mode, - .try_idle = bfin_musb_try_idle, .vbus_status = bfin_musb_vbus_status, .set_vbus = bfin_musb_set_vbus, @@ -471,6 +455,7 @@ static int __devinit bfin_probe(struct platform_device *pdev) struct bfin_glue *glue; int ret = -ENOMEM; + int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -478,12 +463,21 @@ static int __devinit bfin_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &bfin_dmamask; musb->dev.coherent_dma_mask = bfin_dmamask; @@ -499,26 +493,29 @@ static int __devinit bfin_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; + goto err3; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; + goto err3; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err2; + goto err3; } return 0; -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -530,6 +527,7 @@ static int __devexit bfin_remove(struct platform_device *pdev) { struct bfin_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); kfree(glue); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 8637c1f..e19da82 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1316,7 +1316,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) } /* Instantiate a software object representing a DMA controller. */ -struct dma_controller *__init +struct dma_controller *__devinit dma_controller_create(struct musb *musb, void __iomem *mregs) { struct cppi *controller; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 0f9fcec..ce11d20 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -33,6 +33,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/usb/nop-usb-xceiv.h> #include <mach/da8xx.h> #include <mach/usb.h> @@ -155,9 +156,8 @@ static void da8xx_musb_enable(struct musb *musb) musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask); /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - if (is_otg_enabled(musb)) - musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, - DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT); + musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, + DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT); } /** @@ -231,9 +231,6 @@ static void otg_timer(unsigned long _musb) MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT); break; case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - /* * There's no ID-changed IRQ, so we have no good way to tell * when to switch to the A-Default state machine (by setting @@ -263,9 +260,6 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) { static unsigned long last_timer; - if (!is_otg_enabled(musb)) - return; - if (timeout == 0) timeout = jiffies + msecs_to_jiffies(3); @@ -333,8 +327,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err; - err = is_host_enabled(musb) && (musb->int_usb & - MUSB_INTR_VBUSERROR); + err = musb->int_usb & USB_INTR_VBUSERROR; if (err) { /* * The Mentor core doesn't debounce VBUS as needed @@ -351,7 +344,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); - } else if (is_host_enabled(musb) && drvvbus) { + } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; @@ -382,7 +375,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); /* Poll for ID change */ - if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); @@ -430,8 +423,7 @@ static int da8xx_musb_init(struct musb *musb) if (IS_ERR_OR_NULL(musb->xceiv)) goto fail; - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); + setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); /* Reset the controller */ musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); @@ -454,8 +446,7 @@ fail: static int da8xx_musb_exit(struct musb *musb) { - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); + del_timer_sync(&otg_workaround); phy_off(); @@ -489,6 +480,7 @@ static int __devinit da8xx_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; + int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -496,25 +488,34 @@ static int __devinit da8xx_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } clk = clk_get(&pdev->dev, "usb20"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err2; + goto err3; } ret = clk_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; + goto err4; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &da8xx_dmamask; musb->dev.coherent_dma_mask = da8xx_dmamask; @@ -531,32 +532,35 @@ static int __devinit da8xx_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; + goto err5; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; + goto err5; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; + goto err5; } return 0; -err4: +err5: clk_disable(clk); -err3: +err4: clk_put(clk); -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -568,6 +572,7 @@ static int __devexit da8xx_remove(struct platform_device *pdev) { struct da8xx_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); clk_disable(glue->clk); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 472c8b4..606bfd0 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -33,6 +33,7 @@ #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/usb/nop-usb-xceiv.h> #include <mach/cputype.h> #include <mach/hardware.h> @@ -115,8 +116,7 @@ static void davinci_musb_enable(struct musb *musb) dma_off = 0; /* force a DRVVBUS irq so we can start polling for ID change */ - if (is_otg_enabled(musb)) - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, + musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT); } @@ -234,10 +234,8 @@ static void otg_timer(unsigned long _musb) MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - - /* There's no ID-changed IRQ, so we have no good way to tell + /* + * There's no ID-changed IRQ, so we have no good way to tell * when to switch to the A-Default state machine (by setting * the DEVCTL.SESSION flag). * @@ -315,8 +313,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err = musb->int_usb & MUSB_INTR_VBUSERROR; - err = is_host_enabled(musb) - && (musb->int_usb & MUSB_INTR_VBUSERROR); + err = musb->int_usb & MUSB_INTR_VBUSERROR; if (err) { /* The Mentor core doesn't debounce VBUS as needed * to cope with device connect current spikes. This @@ -332,7 +329,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); - } else if (is_host_enabled(musb) && drvvbus) { + } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; @@ -365,8 +362,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) musb_writel(tibase, DAVINCI_USB_EOI_REG, 0); /* poll for ID change */ - if (is_otg_enabled(musb) - && musb->xceiv->state == OTG_STATE_B_IDLE) + if (musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); @@ -397,8 +393,7 @@ static int davinci_musb_init(struct musb *musb) if (revision == 0) goto fail; - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); + setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); davinci_musb_source_power(musb, 0, 1); @@ -419,12 +414,7 @@ static int davinci_musb_init(struct musb *musb) if (cpu_is_davinci_dm355()) { u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); - if (is_host_enabled(musb)) { - deepsleep &= ~DRVVBUS_OVERRIDE; - } else { - deepsleep &= ~DRVVBUS_FORCE; - deepsleep |= DRVVBUS_OVERRIDE; - } + deepsleep &= ~DRVVBUS_FORCE; __raw_writel(deepsleep, DM355_DEEPSLEEP); } @@ -453,8 +443,7 @@ unregister: static int davinci_musb_exit(struct musb *musb) { - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); + del_timer_sync(&otg_workaround); /* force VBUS off */ if (cpu_is_davinci_dm355()) { @@ -468,7 +457,7 @@ static int davinci_musb_exit(struct musb *musb) davinci_musb_source_power(musb, 0 /*off*/, 1); /* delay, to avoid problems with module reload */ - if (is_host_enabled(musb) && musb->xceiv->otg->default_a) { + if (musb->xceiv->otg->default_a) { int maxdelay = 30; u8 devctl, warn = 0; @@ -523,6 +512,7 @@ static int __devinit davinci_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; + int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -530,25 +520,34 @@ static int __devinit davinci_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } clk = clk_get(&pdev->dev, "usb"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err2; + goto err3; } ret = clk_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; + goto err4; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &davinci_dmamask; musb->dev.coherent_dma_mask = davinci_dmamask; @@ -565,32 +564,35 @@ static int __devinit davinci_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; + goto err5; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; + goto err5; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; + goto err5; } return 0; -err4: +err5: clk_disable(clk); -err3: +err4: clk_put(clk); -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -602,6 +604,7 @@ static int __devexit davinci_remove(struct platform_device *pdev) { struct davinci_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); clk_disable(glue->clk); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 26f1bef..bb56a0e 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -99,6 +99,8 @@ #include <linux/prefetch.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/idr.h> +#include <linux/dma-mapping.h> #include "musb_core.h" @@ -114,6 +116,7 @@ #define MUSB_DRIVER_NAME "musb-hdrc" const char musb_driver_name[] = MUSB_DRIVER_NAME; +static DEFINE_IDA(musb_ida); MODULE_DESCRIPTION(DRIVER_INFO); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -130,6 +133,35 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ +int musb_get_id(struct device *dev, gfp_t gfp_mask) +{ + int ret; + int id; + + ret = ida_pre_get(&musb_ida, gfp_mask); + if (!ret) { + dev_err(dev, "failed to reserve resource for id\n"); + return -ENOMEM; + } + + ret = ida_get_new(&musb_ida, &id); + if (ret < 0) { + dev_err(dev, "failed to allocate a new id\n"); + return ret; + } + + return id; +} +EXPORT_SYMBOL_GPL(musb_get_id); + +void musb_put_id(struct device *dev, int id) +{ + + dev_dbg(dev, "removing id %d\n", id); + ida_remove(&musb_ida, id); +} +EXPORT_SYMBOL_GPL(musb_put_id); + #ifndef CONFIG_BLACKFIN static int musb_ulpi_read(struct usb_phy *phy, u32 offset) { @@ -234,6 +266,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; + if (unlikely(len == 0)) + return; + prefetch((u8 *)src); dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", @@ -276,6 +311,9 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; + if (unlikely(len == 0)) + return; + dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", 'R', hw_ep->epnum, fifo, len, dst); @@ -348,7 +386,7 @@ void musb_load_testpacket(struct musb *musb) /* * Handles OTG hnp timeouts, such as b_ase0_brst */ -void musb_otg_timer_func(unsigned long data) +static void musb_otg_timer_func(unsigned long data) { struct musb *musb = (struct musb *)data; unsigned long flags; @@ -643,8 +681,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_B_PERIPHERAL: musb_g_suspend(musb); - musb->is_active = is_otg_enabled(musb) - && otg->gadget->b_hnp_enable; + musb->is_active = otg->gadget->b_hnp_enable; if (musb->is_active) { musb->xceiv->state = OTG_STATE_B_WAIT_ACON; dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); @@ -660,8 +697,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && otg->host->b_hnp_enable; + musb->is_active = otg->host->b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -749,7 +785,7 @@ b_host: case OTG_STATE_A_SUSPEND: usb_hcd_resume_root_hub(musb_to_hcd(musb)); musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) + if (musb->a_wait_bcon != 0) musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(musb->a_wait_bcon)); break; @@ -787,7 +823,7 @@ b_host: */ if (int_usb & MUSB_INTR_RESET) { handled = IRQ_HANDLED; - if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) { + if ((devctl & MUSB_DEVCTL_HM) != 0) { /* * Looks like non-HS BABBLE can be ignored, but * HS BABBLE is an error condition. For HS the solution @@ -801,7 +837,7 @@ b_host: ERR("Stopping host session -- babble\n"); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } - } else if (is_peripheral_capable()) { + } else { dev_dbg(musb->controller, "BUS RESET as %s\n", otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { @@ -925,25 +961,16 @@ void musb_start(struct musb *musb) devctl = musb_readb(regs, MUSB_DEVCTL); devctl &= ~MUSB_DEVCTL_SESSION; - if (is_otg_enabled(musb)) { - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; - - } else if (is_host_enabled(musb)) { - /* assume ID pin is hard-wired to ground */ + /* session started after: + * (a) ID-grounded irq, host mode; + * (b) vbus present/connect IRQ, peripheral mode; + * (c) peripheral initiates, using SRP + */ + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + musb->is_active = 1; + else devctl |= MUSB_DEVCTL_SESSION; - } else /* peripheral is enabled */ { - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - } musb_platform_enable(musb); musb_writeb(regs, MUSB_DEVCTL, devctl); } @@ -1007,8 +1034,6 @@ static void musb_shutdown(struct platform_device *pdev) musb_generic_disable(musb); spin_unlock_irqrestore(&musb->lock, flags); - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_platform_exit(musb); @@ -1302,7 +1327,7 @@ done: if (offset < 0) { pr_debug("%s: mem overrun, ep %d\n", musb_driver_name, epn); - return -EINVAL; + return offset; } epn++; musb->nr_endpoints = max(epn, musb->nr_endpoints); @@ -1330,7 +1355,7 @@ static int __devinit ep_config_from_hw(struct musb *musb) { u8 epnum = 0; struct musb_hw_ep *hw_ep; - void *mbase = musb->mregs; + void __iomem *mbase = musb->mregs; int ret = 0; dev_dbg(musb->controller, "<== static silicon ep config\n"); @@ -1571,13 +1596,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, ep_num); + else + musb_g_rx(musb, ep_num); } reg >>= 1; @@ -1592,13 +1614,10 @@ irqreturn_t musb_interrupt(struct musb *musb) /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, ep_num); + else + musb_g_tx(musb, ep_num); } reg >>= 1; ep_num++; @@ -1634,22 +1653,16 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) } else { /* endpoints 1..15 */ if (transmit) { - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_tx(musb, epnum); + else + musb_g_tx(musb, epnum); } else { /* receive */ - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, epnum); - } + if (devctl & MUSB_DEVCTL_HM) + musb_host_rx(musb, epnum); + else + musb_g_rx(musb, epnum); } } } @@ -1785,10 +1798,9 @@ static const struct attribute_group musb_attr_group = { static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work); - static int old_state; - if (musb->xceiv->state != old_state) { - old_state = musb->xceiv->state; + if (musb->xceiv->state != musb->xceiv_old_state) { + musb->xceiv_old_state = musb->xceiv->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } } @@ -1862,15 +1874,15 @@ static void musb_free(struct musb *musb) dma_controller_destroy(c); } - kfree(musb); + usb_put_hcd(musb_to_hcd(musb)); } /* * Perform generic per-controller initialization. * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, + * @dev: the controller (already clocked, etc) + * @nIrq: IRQ number + * @ctrl: virtual address of controller registers, * not yet corrected for platform-specific offsets */ static int __devinit @@ -1879,6 +1891,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) int status; struct musb *musb; struct musb_hdrc_platform_data *plat = dev->platform_data; + struct usb_hcd *hcd; /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. @@ -1901,7 +1914,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_enable(musb->controller); spin_lock_init(&musb->lock); - musb->board_mode = plat->mode; musb->board_set_power = plat->set_power; musb->min_power = plat->min_power; musb->ops = plat->platform_ops; @@ -1972,7 +1984,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail3; } musb->nIrq = nIrq; -/* FIXME this handles wakeup irqs wrong */ + /* FIXME this handles wakeup irqs wrong */ if (enable_irq_wake(nIrq) == 0) { musb->irq_wake = 1; device_init_wakeup(dev, 1); @@ -1981,58 +1993,25 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) } /* host side needs more setup */ - if (is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - otg_set_host(musb->xceiv->otg, &hcd->self); - - if (is_otg_enabled(musb)) - hcd->self.otg_port = 1; - musb->xceiv->otg->host = &hcd->self; - hcd->power_budget = 2 * (plat->power ? : 250); - - /* program PHY to use external vBus if required */ - if (plat->extvbus) { - u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); - busctl |= MUSB_ULPI_USE_EXTVBUS; - musb_write_ulpi_buscontrol(musb->mregs, busctl); - } + hcd = musb_to_hcd(musb); + otg_set_host(musb->xceiv->otg, &hcd->self); + hcd->self.otg_port = 1; + musb->xceiv->otg->host = &hcd->self; + hcd->power_budget = 2 * (plat->power ? : 250); + + /* program PHY to use external vBus if required */ + if (plat->extvbus) { + u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); + busctl |= MUSB_ULPI_USE_EXTVBUS; + musb_write_ulpi_buscontrol(musb->mregs, busctl); } - /* For the host-only role, we can activate right away. - * (We expect the ID pin to be forcibly grounded!!) - * Otherwise, wait till the gadget driver hooks up. - */ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - MUSB_HST_MODE(musb); - musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_IDLE; - - status = usb_add_hcd(musb_to_hcd(musb), 0, 0); - - hcd->self.uses_pio_for_control = 1; - dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n", - "HOST", status, - musb_readb(musb->mregs, MUSB_DEVCTL), - (musb_readb(musb->mregs, MUSB_DEVCTL) - & MUSB_DEVCTL_BDEVICE - ? 'B' : 'A')); - - } else /* peripheral is enabled */ { - MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - - status = musb_gadget_setup(musb); + MUSB_DEV_MODE(musb); + musb->xceiv->otg->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; - dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n", - is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", - status, - musb_readb(musb->mregs, MUSB_DEVCTL)); + status = musb_gadget_setup(musb); - } if (status < 0) goto fail3; @@ -2048,28 +2027,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_put(musb->controller); - dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", - ({char *s; - switch (musb->board_mode) { - case MUSB_HOST: s = "Host"; break; - case MUSB_PERIPHERAL: s = "Peripheral"; break; - default: s = "OTG"; break; - }; s; }), - ctrl, - (is_dma_capable() && musb->dma_controller) - ? "DMA" : "PIO", - musb->nIrq); - return 0; fail5: musb_exit_debugfs(musb); fail4: - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); - else - musb_gadget_cleanup(musb); + musb_gadget_cleanup(musb); fail3: pm_runtime_put_sync(musb->controller); @@ -2096,11 +2060,6 @@ fail0: /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just * bridge to a platform device; this driver then suffices. */ - -#ifndef CONFIG_MUSB_PIO_ONLY -static u64 *orig_dma_mask; -#endif - static int __devinit musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2119,10 +2078,6 @@ static int __devinit musb_probe(struct platform_device *pdev) return -ENOMEM; } -#ifndef CONFIG_MUSB_PIO_ONLY - /* clobbered by use_dma=n */ - orig_dma_mask = dev->dma_mask; -#endif status = musb_init_controller(dev, irq, base); if (status < 0) iounmap(base); @@ -2132,7 +2087,8 @@ static int __devinit musb_probe(struct platform_device *pdev) static int __devexit musb_remove(struct platform_device *pdev) { - struct musb *musb = dev_to_musb(&pdev->dev); + struct device *dev = &pdev->dev; + struct musb *musb = dev_to_musb(dev); void __iomem *ctrl_base = musb->ctrl_base; /* this gets called on rmmod. @@ -2145,9 +2101,9 @@ static int __devexit musb_remove(struct platform_device *pdev) musb_free(musb); iounmap(ctrl_base); - device_init_wakeup(&pdev->dev, 0); + device_init_wakeup(dev, 0); #ifndef CONFIG_MUSB_PIO_ONLY - pdev->dev.dma_mask = orig_dma_mask; + dma_set_mask(dev, *dev->parent->dma_mask); #endif return 0; } @@ -2160,11 +2116,9 @@ static void musb_save_context(struct musb *musb) void __iomem *musb_base = musb->mregs; void __iomem *epio; - if (is_host_enabled(musb)) { - musb->context.frame = musb_readw(musb_base, MUSB_FRAME); - musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); - musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); - } + musb->context.frame = musb_readw(musb_base, MUSB_FRAME); + musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); musb->context.power = musb_readb(musb_base, MUSB_POWER); musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); @@ -2203,30 +2157,29 @@ static void musb_save_context(struct musb *musb) musb->context.index_regs[i].rxfifosz = musb_read_rxfifosz(musb_base); } - if (is_host_enabled(musb)) { - musb->context.index_regs[i].txtype = - musb_readb(epio, MUSB_TXTYPE); - musb->context.index_regs[i].txinterval = - musb_readb(epio, MUSB_TXINTERVAL); - musb->context.index_regs[i].rxtype = - musb_readb(epio, MUSB_RXTYPE); - musb->context.index_regs[i].rxinterval = - musb_readb(epio, MUSB_RXINTERVAL); - - musb->context.index_regs[i].txfunaddr = - musb_read_txfunaddr(musb_base, i); - musb->context.index_regs[i].txhubaddr = - musb_read_txhubaddr(musb_base, i); - musb->context.index_regs[i].txhubport = - musb_read_txhubport(musb_base, i); - - musb->context.index_regs[i].rxfunaddr = - musb_read_rxfunaddr(musb_base, i); - musb->context.index_regs[i].rxhubaddr = - musb_read_rxhubaddr(musb_base, i); - musb->context.index_regs[i].rxhubport = - musb_read_rxhubport(musb_base, i); - } + + musb->context.index_regs[i].txtype = + musb_readb(epio, MUSB_TXTYPE); + musb->context.index_regs[i].txinterval = + musb_readb(epio, MUSB_TXINTERVAL); + musb->context.index_regs[i].rxtype = + musb_readb(epio, MUSB_RXTYPE); + musb->context.index_regs[i].rxinterval = + musb_readb(epio, MUSB_RXINTERVAL); + + musb->context.index_regs[i].txfunaddr = + musb_read_txfunaddr(musb_base, i); + musb->context.index_regs[i].txhubaddr = + musb_read_txhubaddr(musb_base, i); + musb->context.index_regs[i].txhubport = + musb_read_txhubport(musb_base, i); + + musb->context.index_regs[i].rxfunaddr = + musb_read_rxfunaddr(musb_base, i); + musb->context.index_regs[i].rxhubaddr = + musb_read_rxhubaddr(musb_base, i); + musb->context.index_regs[i].rxhubport = + musb_read_rxhubport(musb_base, i); } } @@ -2237,11 +2190,9 @@ static void musb_restore_context(struct musb *musb) void __iomem *ep_target_regs; void __iomem *epio; - if (is_host_enabled(musb)) { - musb_writew(musb_base, MUSB_FRAME, musb->context.frame); - musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); - musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - } + musb_writew(musb_base, MUSB_FRAME, musb->context.frame); + musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); + musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); musb_writeb(musb_base, MUSB_POWER, musb->context.power); musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); @@ -2280,33 +2231,31 @@ static void musb_restore_context(struct musb *musb) musb->context.index_regs[i].rxfifoadd); } - if (is_host_enabled(musb)) { - musb_writeb(epio, MUSB_TXTYPE, + musb_writeb(epio, MUSB_TXTYPE, musb->context.index_regs[i].txtype); - musb_writeb(epio, MUSB_TXINTERVAL, + musb_writeb(epio, MUSB_TXINTERVAL, musb->context.index_regs[i].txinterval); - musb_writeb(epio, MUSB_RXTYPE, + musb_writeb(epio, MUSB_RXTYPE, musb->context.index_regs[i].rxtype); - musb_writeb(epio, MUSB_RXINTERVAL, + musb_writeb(epio, MUSB_RXINTERVAL, - musb->context.index_regs[i].rxinterval); - musb_write_txfunaddr(musb_base, i, + musb->context.index_regs[i].rxinterval); + musb_write_txfunaddr(musb_base, i, musb->context.index_regs[i].txfunaddr); - musb_write_txhubaddr(musb_base, i, + musb_write_txhubaddr(musb_base, i, musb->context.index_regs[i].txhubaddr); - musb_write_txhubport(musb_base, i, + musb_write_txhubport(musb_base, i, musb->context.index_regs[i].txhubport); - ep_target_regs = - musb_read_target_reg_base(i, musb_base); + ep_target_regs = + musb_read_target_reg_base(i, musb_base); - musb_write_rxfunaddr(ep_target_regs, + musb_write_rxfunaddr(ep_target_regs, musb->context.index_regs[i].rxfunaddr); - musb_write_rxhubaddr(ep_target_regs, + musb_write_rxhubaddr(ep_target_regs, musb->context.index_regs[i].rxhubaddr); - musb_write_rxhubport(ep_target_regs, + musb_write_rxhubport(ep_target_regs, musb->context.index_regs[i].rxhubport); - } } musb_writeb(musb_base, MUSB_INDEX, musb->context.index); } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 586105b..c158aac 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -71,10 +71,6 @@ struct musb_ep; #include <linux/usb/hcd.h> #include "musb_host.h" -#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST) -#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL) -#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG) - /* NOTE: otg and peripheral-only state machines start at B_IDLE. * OTG or host-only go to A_IDLE when ID is sensed. */ @@ -88,8 +84,6 @@ struct musb_ep; /****************************** PERIPHERAL ROLE *****************************/ -#define is_peripheral_capable() (1) - extern irqreturn_t musb_g_ep0_irq(struct musb *); extern void musb_g_tx(struct musb *, u8); extern void musb_g_rx(struct musb *, u8); @@ -101,8 +95,6 @@ extern void musb_g_disconnect(struct musb *); /****************************** HOST ROLE ***********************************/ -#define is_host_capable() (1) - extern irqreturn_t musb_h_ep0_irq(struct musb *); extern void musb_host_tx(struct musb *, u8); extern void musb_host_rx(struct musb *, u8); @@ -376,7 +368,6 @@ struct musb { u16 epmask; u8 nr_endpoints; - u8 board_mode; /* enum musb_mode */ int (*board_set_power)(int state); u8 min_power; /* vbus for periph, in mA/2 */ @@ -446,6 +437,10 @@ struct musb { #ifdef MUSB_CONFIG_PROC_FS struct proc_dir_entry *proc_entry; #endif + int xceiv_old_state; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif }; static inline struct musb *gadget_to_musb(struct usb_gadget *g) @@ -484,7 +479,7 @@ static inline void musb_configure_ep0(struct musb *musb) static inline int musb_read_fifosize(struct musb *musb, struct musb_hw_ep *hw_ep, u8 epnum) { - void *mbase = musb->mregs; + void __iomem *mbase = musb->mregs; u8 reg = 0; /* read from core using indexed model */ @@ -526,6 +521,8 @@ extern const char musb_driver_name[]; extern void musb_start(struct musb *musb); extern void musb_stop(struct musb *musb); +extern int musb_get_id(struct device *dev, gfp_t gfp_mask); +extern void musb_put_id(struct device *dev, int id); extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src); extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 40a37c9..1d6e8af 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -103,8 +103,6 @@ static const struct musb_register_map musb_regmap[] = { { } /* Terminating Entry */ }; -static struct dentry *musb_debugfs_root; - static int musb_regdump_show(struct seq_file *s, void *unused) { struct musb *musb = s->private; @@ -241,7 +239,7 @@ int __devinit musb_init_debugfs(struct musb *musb) struct dentry *file; int ret; - root = debugfs_create_dir("musb", NULL); + root = debugfs_create_dir(dev_name(musb->controller), NULL); if (!root) { ret = -ENOMEM; goto err0; @@ -261,7 +259,7 @@ int __devinit musb_init_debugfs(struct musb *musb) goto err1; } - musb_debugfs_root = root; + musb->debugfs_root = root; return 0; @@ -274,5 +272,5 @@ err0: void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb) { - debugfs_remove_recursive(musb_debugfs_root); + debugfs_remove_recursive(musb->debugfs_root); } diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 3a97c4e..24d3921 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -178,7 +178,7 @@ struct dma_controller { extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); -extern struct dma_controller *__init +extern struct dma_controller *__devinit dma_controller_create(struct musb *, void __iomem *); extern void dma_controller_destroy(struct dma_controller *); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 494772f..444346e 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -31,11 +31,13 @@ #include <linux/init.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/module.h> +#include <linux/usb/nop-usb-xceiv.h> #include <linux/of.h> #include <linux/of_device.h> @@ -45,6 +47,10 @@ #include "musb_core.h" +#ifdef CONFIG_OF +static const struct of_device_id musb_dsps_of_match[]; +#endif + /** * avoid using musb_readx()/musb_writex() as glue layer should not be * dependent on musb core layer symbols. @@ -105,6 +111,8 @@ struct dsps_musb_wrapper { /* miscellaneous stuff */ u32 musb_core_offset; u8 poll_seconds; + /* number of musb instances */ + u8 instances; }; /** @@ -112,9 +120,10 @@ struct dsps_musb_wrapper { */ struct dsps_glue { struct device *dev; - struct platform_device *musb; /* child musb pdev */ + struct platform_device *musb[2]; /* child musb pdev */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ - struct timer_list timer; /* otg_workaround timer */ + struct timer_list timer[2]; /* otg_workaround timer */ + unsigned long last_timer[2]; /* last timer data for each instance */ }; /** @@ -137,9 +146,8 @@ static void dsps_musb_enable(struct musb *musb) dsps_writel(reg_base, wrp->epintr_set, epmask); dsps_writel(reg_base, wrp->coreintr_set, coremask); /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - if (is_otg_enabled(musb)) - dsps_writel(reg_base, wrp->coreintr_set, - (1 << wrp->drvvbus) << wrp->usb_shift); + dsps_writel(reg_base, wrp->coreintr_set, + (1 << wrp->drvvbus) << wrp->usb_shift); } /** @@ -165,8 +173,8 @@ static void otg_timer(unsigned long _musb) struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; unsigned long flags; @@ -200,12 +208,9 @@ static void otg_timer(unsigned long _musb) MUSB_INTR_VBUSERROR << wrp->usb_shift); break; case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - devctl = dsps_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&glue->timer, + mod_timer(&glue->timer[pdev->id], jiffies + wrp->poll_seconds * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; @@ -219,12 +224,8 @@ static void otg_timer(unsigned long _musb) static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - static unsigned long last_timer; - - if (!is_otg_enabled(musb)) - return; + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); if (timeout == 0) timeout = jiffies + msecs_to_jiffies(3); @@ -234,22 +235,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer); - last_timer = jiffies; + del_timer(&glue->timer[pdev->id]); + glue->last_timer[pdev->id] = jiffies; return; } - if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) { + if (time_after(glue->last_timer[pdev->id], timeout) && + timer_pending(&glue->timer[pdev->id])) { dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); return; } - last_timer = timeout; + glue->last_timer[pdev->id] = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer, timeout); + mod_timer(&glue->timer[pdev->id], timeout); } static irqreturn_t dsps_interrupt(int irq, void *hci) @@ -257,8 +259,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; irqreturn_t ret = IRQ_NONE; @@ -293,7 +295,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb)) + if (usbintr & MUSB_INTR_BABBLE) pr_info("CAUTION: musb: Babble Interrupt Occured\n"); if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { @@ -302,8 +304,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); int err; - err = is_host_enabled(musb) && (musb->int_usb & - MUSB_INTR_VBUSERROR); + err = musb->int_usb & MUSB_INTR_VBUSERROR; if (err) { /* * The Mentor core doesn't debounce VBUS as needed @@ -318,15 +319,15 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer, + mod_timer(&glue->timer[pdev->id], jiffies + wrp->poll_seconds * HZ); WARNING("VBUS error workaround (delay coming)\n"); - } else if (is_host_enabled(musb) && drvvbus) { + } else if (drvvbus) { musb->is_active = 1; MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - del_timer(&glue->timer); + del_timer(&glue->timer[pdev->id]); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -352,8 +353,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) dsps_writel(reg_base, wrp->eoi, 1); /* Poll for ID change */ - if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + if (musb->xceiv->state == OTG_STATE_B_IDLE) + mod_timer(&glue->timer[pdev->id], + jiffies + wrp->poll_seconds * HZ); spin_unlock_irqrestore(&musb->lock, flags); @@ -364,8 +366,8 @@ static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; struct omap_musb_board_data *data = plat->board_data; void __iomem *reg_base = musb->ctrl_base; @@ -375,8 +377,7 @@ static int dsps_musb_init(struct musb *musb) /* mentor core register starts at offset of 0x400 from musb base */ musb->mregs += wrp->musb_core_offset; - /* NOP driver needs change if supporting dual instance */ - usb_nop_xceiv_register(); + /* Get the NOP PHY */ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -ENODEV; @@ -388,8 +389,7 @@ static int dsps_musb_init(struct musb *musb) goto err0; } - if (is_host_enabled(musb)) - setup_timer(&glue->timer, otg_timer, (unsigned long) musb); + setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb); /* Reset the musb */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); @@ -420,11 +420,10 @@ static int dsps_musb_exit(struct musb *musb) struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); - if (is_host_enabled(musb)) - del_timer_sync(&glue->timer); + del_timer_sync(&glue->timer[pdev->id]); /* Shutdown the on-chip PHY and its PLL. */ if (data->set_phy_power) @@ -454,11 +453,13 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) struct device *dev = glue->dev; struct platform_device *pdev = to_platform_device(dev); struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct device_node *np = pdev->dev.of_node; + struct musb_hdrc_config *config; struct platform_device *musb; struct resource *res; struct resource resources[2]; char res_name[10]; - int ret; + int ret, musbid; /* get memory resource */ sprintf(res_name, "musb%d", id); @@ -483,62 +484,107 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) resources[1] = *res; resources[1].name = "mc"; + /* get the musb id */ + musbid = musb_get_id(dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err0; + } /* allocate the child platform device */ - musb = platform_device_alloc("musb-hdrc", -1); + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); ret = -ENOMEM; - goto err0; + goto err1; } + musb->id = musbid; musb->dev.parent = dev; musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; - glue->musb = musb; - - pdata->platform_ops = &dsps_ops; + glue->musb[id] = musb; ret = platform_device_add_resources(musb, resources, 2); if (ret) { dev_err(dev, "failed to add resources\n"); - goto err1; + goto err2; } + if (np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, + "failed to allocate musb platfrom data\n"); + ret = -ENOMEM; + goto err2; + } + + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(&pdev->dev, + "failed to allocate musb hdrc config\n"); + goto err2; + } + + of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); + sprintf(res_name, "port%d-mode", id); + of_property_read_u32(np, res_name, (u32 *)&pdata->mode); + of_property_read_u32(np, "power", (u32 *)&pdata->power); + config->multipoint = of_property_read_bool(np, "multipoint"); + + pdata->config = config; + } + + pdata->platform_ops = &dsps_ops; + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(dev, "failed to add platform_data\n"); - goto err1; + goto err2; } ret = platform_device_add(musb); if (ret) { dev_err(dev, "failed to register musb device\n"); - goto err1; + goto err2; } return 0; -err1: +err2: platform_device_put(musb); +err1: + musb_put_id(dev, musbid); err0: return ret; } -static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) +static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id) { - platform_device_del(glue->musb); - platform_device_put(glue->musb); + musb_put_id(glue->dev, glue->musb[id]->id); + platform_device_del(glue->musb[id]); + platform_device_put(glue->musb[id]); } static int __devinit dsps_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); - const struct dsps_musb_wrapper *wrp = - (struct dsps_musb_wrapper *)id->driver_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; struct resource *iomem; - int ret; + int ret, i; + + match = of_match_node(musb_dsps_of_match, np); + if (!match) { + dev_err(&pdev->dev, "fail to get matching of_match struct\n"); + ret = -EINVAL; + goto err0; + } + wrp = match->data; /* allocate glue */ glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -575,11 +621,16 @@ static int __devinit dsps_probe(struct platform_device *pdev) goto err2; } - /* create the child platform device for first instances of musb */ - ret = dsps_create_musb_pdev(glue, 0); - if (ret != 0) { - dev_err(&pdev->dev, "failed to create child pdev\n"); - goto err3; + /* create the child platform device for all instances of musb */ + for (i = 0; i < wrp->instances ; i++) { + ret = dsps_create_musb_pdev(glue, i); + if (ret != 0) { + dev_err(&pdev->dev, "failed to create child pdev\n"); + /* release resources of previously created instances */ + for (i--; i >= 0 ; i--) + dsps_delete_musb_pdev(glue, i); + goto err3; + } } return 0; @@ -597,9 +648,12 @@ err0: static int __devexit dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; /* delete the child platform device */ - dsps_delete_musb_pdev(glue); + for (i = 0; i < wrp->instances ; i++) + dsps_delete_musb_pdev(glue, i); /* disable usbss clocks */ pm_runtime_put(&pdev->dev); @@ -665,6 +719,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { .rxep_bitmap = (0xfffe << 16), .musb_core_offset = 0x400, .poll_seconds = 2, + .instances = 2, }; static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { @@ -676,13 +731,14 @@ static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { }; MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); +#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[] __devinitconst = { - { .compatible = "musb-ti81xx", }, - { .compatible = "ti,ti81xx-musb", }, - { .compatible = "ti,am335x-musb", }, + { .compatible = "ti,musb-am33xx", + .data = (void *) &ti81xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); +#endif static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, @@ -690,7 +746,7 @@ static struct platform_driver dsps_usbss_driver = { .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, - .of_match_table = musb_dsps_of_match, + .of_match_table = of_match_ptr(musb_dsps_of_match), }, .id_table = musb_dsps_id_table, }; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f7194cf..d0b87e7 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -373,7 +373,7 @@ static void txstate(struct musb *musb, struct musb_request *req) request_size = min_t(size_t, request->length - request->actual, musb_ep->dma->max_len); - use_dma = (request->dma != DMA_ADDR_INVALID); + use_dma = (request->dma != DMA_ADDR_INVALID && request_size); /* MUSB_TXCSR_P_ISO is still set correctly */ @@ -644,8 +644,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) struct usb_request *request = &req->request; struct musb_ep *musb_ep; void __iomem *epio = musb->endpoints[epnum].regs; - unsigned fifo_count = 0; - u16 len; + unsigned len = 0; + u16 fifo_count; u16 csr = musb_readw(epio, MUSB_RXCSR); struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; u8 use_mode_1; @@ -655,7 +655,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) else musb_ep = &hw_ep->ep_out; - len = musb_ep->packet_sz; + fifo_count = musb_ep->packet_sz; /* Check if EP is disabled */ if (!musb_ep->desc) { @@ -704,15 +704,14 @@ static void rxstate(struct musb *musb, struct musb_request *req) } if (csr & MUSB_RXCSR_RXPKTRDY) { - len = musb_readw(epio, MUSB_RXCOUNT); + fifo_count = musb_readw(epio, MUSB_RXCOUNT); /* - * Enable Mode 1 on RX transfers only when short_not_ok flag - * is set. Currently short_not_ok flag is set only from - * file_storage and f_mass_storage drivers + * use mode 1 only if we expect data of at least ep packet_sz + * and have not yet received a short packet */ - - if (request->short_not_ok && len == musb_ep->packet_sz) + if ((request->length - request->actual >= musb_ep->packet_sz) && + (fifo_count >= musb_ep->packet_sz)) use_mode_1 = 1; else use_mode_1 = 0; @@ -723,31 +722,11 @@ static void rxstate(struct musb *musb, struct musb_request *req) struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; + int transfer_size; c = musb->dma_controller; channel = musb_ep->dma; - /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in - * mode 0 only. So we do not get endpoint interrupts due to DMA - * completion. We only get interrupts from DMA controller. - * - * We could operate in DMA mode 1 if we knew the size of the tranfer - * in advance. For mass storage class, request->length = what the host - * sends, so that'd work. But for pretty much everything else, - * request->length is routinely more than what the host sends. For - * most these gadgets, end of is signified either by a short packet, - * or filling the last byte of the buffer. (Sending extra data in - * that last pckate should trigger an overflow fault.) But in mode 1, - * we don't get DMA completion interrupt for short packets. - * - * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), - * to get endpoint interrupt on every DMA req, but that didn't seem - * to work reliably. - * - * REVISIT an updated g_file_storage can set req->short_not_ok, which - * then becomes usable as a runtime "use mode 1" hint... - */ - /* Experimental: Mode1 works with mass storage use cases */ if (use_mode_1) { csr |= MUSB_RXCSR_AUTOCLEAR; @@ -764,35 +743,30 @@ static void rxstate(struct musb *musb, struct musb_request *req) csr | MUSB_RXCSR_DMAMODE); musb_writew(epio, MUSB_RXCSR, csr); + transfer_size = min(request->length - request->actual, + channel->max_len); + musb_ep->dma->desired_mode = 1; + } else { if (!musb_ep->hb_mult && musb_ep->hw_ep->rx_double_buffered) csr |= MUSB_RXCSR_AUTOCLEAR; csr |= MUSB_RXCSR_DMAENAB; musb_writew(epio, MUSB_RXCSR, csr); - } - if (request->actual < request->length) { - int transfer_size = 0; - if (use_mode_1) { - transfer_size = min(request->length - request->actual, - channel->max_len); - musb_ep->dma->desired_mode = 1; - } else { - transfer_size = min(request->length - request->actual, - (unsigned)len); - musb_ep->dma->desired_mode = 0; - } - - use_dma = c->channel_program( - channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size); + transfer_size = min(request->length - request->actual, + (unsigned)fifo_count); + musb_ep->dma->desired_mode = 0; } + use_dma = c->channel_program( + channel, + musb_ep->packet_sz, + channel->desired_mode, + request->dma + + request->actual, + transfer_size); + if (use_dma) return; } @@ -808,8 +782,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) channel = musb_ep->dma; /* In case first packet is short */ - if (len < musb_ep->packet_sz) - transfer_size = len; + if (fifo_count < musb_ep->packet_sz) + transfer_size = fifo_count; else if (request->short_not_ok) transfer_size = min(request->length - request->actual, @@ -817,7 +791,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) else transfer_size = min(request->length - request->actual, - (unsigned)len); + (unsigned)fifo_count); csr &= ~MUSB_RXCSR_DMAMODE; csr |= (MUSB_RXCSR_DMAENAB | @@ -845,10 +819,10 @@ static void rxstate(struct musb *musb, struct musb_request *req) } #endif /* Mentor's DMA */ - fifo_count = request->length - request->actual; + len = request->length - request->actual; dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", musb_ep->end_point.name, - len, fifo_count, + fifo_count, len, musb_ep->packet_sz); fifo_count = min_t(unsigned, len, fifo_count); @@ -901,7 +875,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) } /* reach the end or short packet detected */ - if (request->actual == request->length || len < musb_ep->packet_sz) + if (request->actual == request->length || + fifo_count < musb_ep->packet_sz) musb_g_giveback(musb_ep, request, 0); } @@ -1885,8 +1860,7 @@ int __devinit musb_gadget_setup(struct musb *musb) musb->g.dev.release = musb_gadget_release; musb->g.name = musb_driver_name; - if (is_otg_enabled(musb)) - musb->g.is_otg = 1; + musb->g.is_otg = 1; musb_g_init_endpoints(musb); @@ -1932,11 +1906,14 @@ static int musb_gadget_start(struct usb_gadget *g, { struct musb *musb = gadget_to_musb(g); struct usb_otg *otg = musb->xceiv->otg; + struct usb_hcd *hcd = musb_to_hcd(musb); unsigned long flags; - int retval = -EINVAL; + int retval = 0; - if (driver->max_speed < USB_SPEED_HIGH) - goto err0; + if (driver->max_speed < USB_SPEED_HIGH) { + retval = -EINVAL; + goto err; + } pm_runtime_get_sync(musb->controller); @@ -1950,49 +1927,30 @@ static int musb_gadget_start(struct usb_gadget *g, otg_set_peripheral(otg, &musb->g); musb->xceiv->state = OTG_STATE_B_IDLE; - - /* - * FIXME this ignores the softconnect flag. Drivers are - * allowed hold the peripheral inactive until for example - * userspace hooks up printer hardware or DSP codecs, so - * hosts only see fully functional devices. - */ - - if (!is_otg_enabled(musb)) - musb_start(musb); - spin_unlock_irqrestore(&musb->lock, flags); - if (is_otg_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - dev_dbg(musb->controller, "OTG startup...\n"); + /* REVISIT: funcall to other code, which also + * handles power budgeting ... this way also + * ensures HdrcStart is indirectly called. + */ + retval = usb_add_hcd(hcd, 0, 0); + if (retval < 0) { + dev_dbg(musb->controller, "add_hcd failed, %d\n", retval); + goto err; + } - /* REVISIT: funcall to other code, which also - * handles power budgeting ... this way also - * ensures HdrcStart is indirectly called. - */ - retval = usb_add_hcd(musb_to_hcd(musb), 0, 0); - if (retval < 0) { - dev_dbg(musb->controller, "add_hcd failed, %d\n", retval); - goto err2; - } + if ((musb->xceiv->last_event == USB_EVENT_ID) + && otg->set_vbus) + otg_set_vbus(otg, 1); - if ((musb->xceiv->last_event == USB_EVENT_ID) - && otg->set_vbus) - otg_set_vbus(otg, 1); + hcd->self.uses_pio_for_control = 1; - hcd->self.uses_pio_for_control = 1; - } if (musb->xceiv->last_event == USB_EVENT_NONE) pm_runtime_put(musb->controller); return 0; -err2: - if (!is_otg_enabled(musb)) - musb_stop(musb); -err0: +err: return retval; } @@ -2070,16 +2028,12 @@ static int musb_gadget_stop(struct usb_gadget *g, musb_platform_try_idle(musb, 0); spin_unlock_irqrestore(&musb->lock, flags); - if (is_otg_enabled(musb)) { - usb_remove_hcd(musb_to_hcd(musb)); - /* FIXME we need to be able to register another - * gadget driver here and have everything work; - * that currently misbehaves. - */ - } - - if (!is_otg_enabled(musb)) - musb_stop(musb); + usb_remove_hcd(musb_to_hcd(musb)); + /* + * FIXME we need to be able to register another + * gadget driver here and have everything work; + * that currently misbehaves. + */ pm_runtime_put(musb->controller); @@ -2241,13 +2195,11 @@ __acquires(musb->lock) if (devctl & MUSB_DEVCTL_BDEVICE) { musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->g.is_a_peripheral = 0; - } else if (is_otg_enabled(musb)) { + } else { musb->xceiv->state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; - } else - WARN_ON(1); + } /* start with default limits on VBUS power draw */ - (void) musb_gadget_vbus_draw(&musb->g, - is_otg_enabled(musb) ? 8 : 100); + (void) musb_gadget_vbus_draw(&musb->g, 8); } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 1ae378d..3df6a76 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -693,6 +693,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, void __iomem *epio = hw_ep->regs; struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out); u16 packet_sz = qh->maxpacket; + u8 use_dma = 1; + u16 csr; dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s " "h_addr%02x h_port%02x bytes %d\n", @@ -704,9 +706,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum, musb_ep_select(mbase, epnum); + if (is_out && !len) { + use_dma = 0; + csr = musb_readw(epio, MUSB_TXCSR); + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); + hw_ep->tx_channel = NULL; + } + /* candidate for DMA? */ dma_controller = musb->dma_controller; - if (is_dma_capable() && epnum && dma_controller) { + if (use_dma && is_dma_capable() && epnum && dma_controller) { dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; if (!dma_channel) { dma_channel = dma_controller->channel_alloc( @@ -813,9 +823,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum, if (load_count) { /* PIO to load FIFO */ qh->segsize = load_count; - musb_write_fifo(hw_ep, load_count, buf); + if (!buf) { + sg_miter_start(&qh->sg_miter, urb->sg, 1, + SG_MITER_ATOMIC + | SG_MITER_FROM_SG); + if (!sg_miter_next(&qh->sg_miter)) { + dev_err(musb->controller, + "error: sg" + "list empty\n"); + sg_miter_stop(&qh->sg_miter); + goto finish; + } + buf = qh->sg_miter.addr + urb->sg->offset + + urb->actual_length; + load_count = min_t(u32, load_count, + qh->sg_miter.length); + musb_write_fifo(hw_ep, load_count, buf); + qh->sg_miter.consumed = load_count; + sg_miter_stop(&qh->sg_miter); + } else + musb_write_fifo(hw_ep, load_count, buf); } - +finish: /* re-enable interrupt */ musb_writew(mbase, MUSB_INTRTXE, int_txe); @@ -882,6 +911,73 @@ static void musb_ep_program(struct musb *musb, u8 epnum, } } +/* Schedule next QH from musb->in_bulk/out_bulk and move the current qh to + * the end; avoids starvation for other endpoints. + */ +static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, + int is_in) +{ + struct dma_channel *dma; + struct urb *urb; + void __iomem *mbase = musb->mregs; + void __iomem *epio = ep->regs; + struct musb_qh *cur_qh, *next_qh; + u16 rx_csr, tx_csr; + + musb_ep_select(mbase, ep->epnum); + if (is_in) { + dma = is_dma_capable() ? ep->rx_channel : NULL; + + /* clear nak timeout bit */ + rx_csr = musb_readw(epio, MUSB_RXCSR); + rx_csr |= MUSB_RXCSR_H_WZC_BITS; + rx_csr &= ~MUSB_RXCSR_DATAERROR; + musb_writew(epio, MUSB_RXCSR, rx_csr); + + cur_qh = first_qh(&musb->in_bulk); + } else { + dma = is_dma_capable() ? ep->tx_channel : NULL; + + /* clear nak timeout bit */ + tx_csr = musb_readw(epio, MUSB_TXCSR); + tx_csr |= MUSB_TXCSR_H_WZC_BITS; + tx_csr &= ~MUSB_TXCSR_H_NAKTIMEOUT; + musb_writew(epio, MUSB_TXCSR, tx_csr); + + cur_qh = first_qh(&musb->out_bulk); + } + if (cur_qh) { + urb = next_urb(cur_qh); + if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { + dma->status = MUSB_DMA_STATUS_CORE_ABORT; + musb->dma_controller->channel_abort(dma); + urb->actual_length += dma->actual_len; + dma->actual_len = 0L; + } + musb_save_toggle(cur_qh, is_in, urb); + + if (is_in) { + /* move cur_qh to end of queue */ + list_move_tail(&cur_qh->ring, &musb->in_bulk); + + /* get the next qh from musb->in_bulk */ + next_qh = first_qh(&musb->in_bulk); + + /* set rx_reinit and schedule the next qh */ + ep->rx_reinit = 1; + } else { + /* move cur_qh to end of queue */ + list_move_tail(&cur_qh->ring, &musb->out_bulk); + + /* get the next qh from musb->out_bulk */ + next_qh = first_qh(&musb->out_bulk); + + /* set tx_reinit and schedule the next qh */ + ep->tx_reinit = 1; + } + musb_start_urb(musb, is_in, next_qh); + } +} /* * Service the default endpoint (ep0) as host. @@ -1116,6 +1212,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) void __iomem *mbase = musb->mregs; struct dma_channel *dma; bool transfer_pending = false; + static bool use_sg; musb_ep_select(mbase, epnum); tx_csr = musb_readw(epio, MUSB_TXCSR); @@ -1146,23 +1243,31 @@ void musb_host_tx(struct musb *musb, u8 epnum) status = -ETIMEDOUT; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { - dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); - - /* NOTE: this code path would be a good place to PAUSE a - * transfer, if there's some other (nonperiodic) tx urb - * that could use this fifo. (dma complicates it...) - * That's already done for bulk RX transfers. - * - * if (bulk && qh->ring.next != &musb->out_bulk), then - * we have a candidate... NAKing is *NOT* an error - */ - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_H_WZC_BITS - | MUSB_TXCSR_TXPKTRDY); - return; + if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1 + && !list_is_singular(&musb->out_bulk)) { + dev_dbg(musb->controller, + "NAK timeout on TX%d ep\n", epnum); + musb_bulk_nak_timeout(musb, hw_ep, 0); + } else { + dev_dbg(musb->controller, + "TX end=%d device not responding\n", epnum); + /* NOTE: this code path would be a good place to PAUSE a + * transfer, if there's some other (nonperiodic) tx urb + * that could use this fifo. (dma complicates it...) + * That's already done for bulk RX transfers. + * + * if (bulk && qh->ring.next != &musb->out_bulk), then + * we have a candidate... NAKing is *NOT* an error + */ + musb_ep_select(mbase, epnum); + musb_writew(epio, MUSB_TXCSR, + MUSB_TXCSR_H_WZC_BITS + | MUSB_TXCSR_TXPKTRDY); + } + return; } +done: if (status) { if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { dma->status = MUSB_DMA_STATUS_CORE_ABORT; @@ -1332,9 +1437,38 @@ void musb_host_tx(struct musb *musb, u8 epnum) length = qh->maxpacket; /* Unmap the buffer so that CPU can use it */ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); - musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); + + /* + * We need to map sg if the transfer_buffer is + * NULL. + */ + if (!urb->transfer_buffer) + use_sg = true; + + if (use_sg) { + /* sg_miter_start is already done in musb_ep_program */ + if (!sg_miter_next(&qh->sg_miter)) { + dev_err(musb->controller, "error: sg list empty\n"); + sg_miter_stop(&qh->sg_miter); + status = -EINVAL; + goto done; + } + urb->transfer_buffer = qh->sg_miter.addr; + length = min_t(u32, length, qh->sg_miter.length); + musb_write_fifo(hw_ep, length, urb->transfer_buffer); + qh->sg_miter.consumed = length; + sg_miter_stop(&qh->sg_miter); + } else { + musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); + } + qh->segsize = length; + if (use_sg) { + if (offset + length >= urb->transfer_buffer_length) + use_sg = false; + } + musb_ep_select(mbase, epnum); musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); @@ -1380,50 +1514,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) #endif -/* Schedule next QH from musb->in_bulk and move the current qh to - * the end; avoids starvation for other endpoints. - */ -static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep) -{ - struct dma_channel *dma; - struct urb *urb; - void __iomem *mbase = musb->mregs; - void __iomem *epio = ep->regs; - struct musb_qh *cur_qh, *next_qh; - u16 rx_csr; - - musb_ep_select(mbase, ep->epnum); - dma = is_dma_capable() ? ep->rx_channel : NULL; - - /* clear nak timeout bit */ - rx_csr = musb_readw(epio, MUSB_RXCSR); - rx_csr |= MUSB_RXCSR_H_WZC_BITS; - rx_csr &= ~MUSB_RXCSR_DATAERROR; - musb_writew(epio, MUSB_RXCSR, rx_csr); - - cur_qh = first_qh(&musb->in_bulk); - if (cur_qh) { - urb = next_urb(cur_qh); - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - urb->actual_length += dma->actual_len; - dma->actual_len = 0L; - } - musb_save_toggle(cur_qh, 1, urb); - - /* move cur_qh to end of queue */ - list_move_tail(&cur_qh->ring, &musb->in_bulk); - - /* get the next qh from musb->in_bulk */ - next_qh = first_qh(&musb->in_bulk); - - /* set rx_reinit and schedule the next qh */ - ep->rx_reinit = 1; - musb_start_urb(musb, 1, next_qh); - } -} - /* * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso, * and high-bandwidth IN transfer cases. @@ -1442,6 +1532,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) bool done = false; u32 status; struct dma_channel *dma; + static bool use_sg; + unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; musb_ep_select(mbase, epnum); @@ -1500,7 +1592,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) if (usb_pipebulk(urb->pipe) && qh->mux == 1 && !list_is_singular(&musb->in_bulk)) { - musb_bulk_rx_nak_timeout(musb, hw_ep); + musb_bulk_nak_timeout(musb, hw_ep, 1); return; } musb_ep_select(mbase, epnum); @@ -1756,10 +1848,43 @@ void musb_host_rx(struct musb *musb, u8 epnum) #endif /* Mentor DMA */ if (!dma) { + unsigned int received_len; + /* Unmap the buffer so that CPU can use it */ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); - done = musb_host_packet_rx(musb, urb, - epnum, iso_err); + + /* + * We need to map sg if the transfer_buffer is + * NULL. + */ + if (!urb->transfer_buffer) { + use_sg = true; + sg_miter_start(&qh->sg_miter, urb->sg, 1, + sg_flags); + } + + if (use_sg) { + if (!sg_miter_next(&qh->sg_miter)) { + dev_err(musb->controller, "error: sg list empty\n"); + sg_miter_stop(&qh->sg_miter); + status = -EINVAL; + done = true; + goto finish; + } + urb->transfer_buffer = qh->sg_miter.addr; + received_len = urb->actual_length; + qh->offset = 0x0; + done = musb_host_packet_rx(musb, urb, epnum, + iso_err); + /* Calculate the number of bytes received */ + received_len = urb->actual_length - + received_len; + qh->sg_miter.consumed = received_len; + sg_miter_stop(&qh->sg_miter); + } else { + done = musb_host_packet_rx(musb, urb, + epnum, iso_err); + } dev_dbg(musb->controller, "read %spacket\n", done ? "last " : ""); } } @@ -1768,6 +1893,9 @@ finish: urb->actual_length += xfer_len; qh->offset += xfer_len; if (done) { + if (use_sg) + use_sg = false; + if (urb->status == -EINPROGRESS) urb->status = status; musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN); @@ -1863,14 +1991,14 @@ static int musb_schedule( else head = &musb->out_bulk; - /* Enable bulk RX NAK timeout scheme when bulk requests are + /* Enable bulk RX/TX NAK timeout scheme when bulk requests are * multiplexed. This scheme doen't work in high speed to full * speed scenario as NAK interrupts are not coming from a * full speed device connected to a high speed device. * NAK timeout interval is 8 (128 uframe or 16ms) for HS and * 4 (8 frame or 8ms) for FS device. */ - if (is_in && qh->dev) + if (qh->dev) qh->intv_reg = (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4; goto success; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 622d09f..5a9c8fe 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -35,6 +35,8 @@ #ifndef _MUSB_HOST_H #define _MUSB_HOST_H +#include <linux/scatterlist.h> + static inline struct usb_hcd *musb_to_hcd(struct musb *musb) { return container_of((void *) musb, struct usb_hcd, hcd_priv); @@ -71,6 +73,7 @@ struct musb_qh { u16 maxpacket; u16 frame; /* for periodic schedule */ unsigned iso_idx; /* in urb->iso_frame_desc[] */ + struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ }; /* map from control or bulk queue head to the first qh on that ring */ diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 22ec3e3..f705791 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -81,8 +81,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend) switch (musb->xceiv->state) { case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && otg->host->b_hnp_enable; + musb->is_active = otg->host->b_hnp_enable; if (musb->is_active) mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( @@ -91,8 +90,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend) break; case OTG_STATE_B_HOST: musb->xceiv->state = OTG_STATE_B_WAIT_ACON; - musb->is_active = is_otg_enabled(musb) - && otg->host->b_hnp_enable; + musb->is_active = otg->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; default: @@ -190,8 +188,7 @@ void musb_root_disconnect(struct musb *musb) switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: - if (is_otg_enabled(musb) - && otg->host->b_hnp_enable) { + if (otg->host->b_hnp_enable) { musb->xceiv->state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; break; @@ -273,7 +270,7 @@ int musb_hub_control( musb_port_suspend(musb, false); break; case USB_PORT_FEAT_POWER: - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) + if (!hcd->self.is_b_host) musb_platform_set_vbus(musb, 0); break; case USB_PORT_FEAT_C_CONNECTION: @@ -369,7 +366,7 @@ int musb_hub_control( * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up. */ - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) + if (!hcd->self.is_b_host) musb_start(musb); break; case USB_PORT_FEAT_RESET: diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index c1be687..0fc6ca6 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -380,7 +380,7 @@ void dma_controller_destroy(struct dma_controller *c) kfree(controller); } -struct dma_controller *__init +struct dma_controller *__devinit dma_controller_create(struct musb *musb, void __iomem *base) { struct musb_dma_controller *controller; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 5fdb9da..a538fe1 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -30,10 +30,12 @@ #include <linux/init.h> #include <linux/list.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/err.h> +#include <linux/delay.h> #include <linux/usb/musb-omap.h> #include "musb_core.h" @@ -44,6 +46,7 @@ struct omap2430_glue { struct platform_device *musb; enum omap_musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; + u32 __iomem *control_otghs; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -51,6 +54,26 @@ struct omap2430_glue *_glue; static struct timer_list musb_idle_timer; +/** + * omap4_usb_phy_mailbox - write to usb otg mailbox + * @glue: struct omap2430_glue * + * @val: the value to be written to the mailbox + * + * On detection of a device (ID pin is grounded), this API should be called + * to set AVALID, VBUSVALID and ID pin is grounded. + * + * When OMAP is connected to a host (OMAP in device mode), this API + * is called to set AVALID, VBUSVALID and ID pin in high impedance. + * + * XXX: This function will be removed once we have a seperate driver for + * control module + */ +static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val) +{ + if (glue->control_otghs) + writel(val, glue->control_otghs); +} + static void musb_do_idle(unsigned long _musb) { struct musb *musb = (void *)_musb; @@ -140,7 +163,6 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) struct usb_otg *otg = musb->xceiv->otg; u8 devctl; unsigned long timeout = jiffies + msecs_to_jiffies(1000); - int ret = 1; /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. @@ -150,6 +172,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) if (is_on) { if (musb->xceiv->state == OTG_STATE_A_IDLE) { + int loops = 100; /* start the session */ devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); @@ -159,17 +182,18 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) */ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + mdelay(5); cpu_relax(); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout) + || loops-- <= 0) { dev_err(musb->controller, "configured as A device timeout"); - ret = -EINVAL; break; } } - if (ret && otg->set_vbus) + if (otg->set_vbus) otg_set_vbus(otg, 1); } else { musb->is_active = 1; @@ -245,6 +269,7 @@ EXPORT_SYMBOL_GPL(omap_musb_mailbox); static void omap_musb_set_mailbox(struct omap2430_glue *glue) { + u32 val; struct musb *musb = glue_to_musb(glue); struct device *dev = musb->controller; struct musb_hdrc_platform_data *pdata = dev->platform_data; @@ -258,9 +283,10 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) otg->default_a = true; musb->xceiv->state = OTG_STATE_A_IDLE; musb->xceiv->last_event = USB_EVENT_ID; - if (!is_otg_enabled(musb) || musb->gadget_driver) { + if (musb->gadget_driver) { pm_runtime_get_sync(dev); - usb_phy_init(musb->xceiv); + val = AVALID | VBUSVALID; + omap4_usb_phy_mailbox(glue, val); omap2430_musb_set_vbus(musb, 1); } break; @@ -273,7 +299,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) musb->xceiv->last_event = USB_EVENT_VBUS; if (musb->gadget_driver) pm_runtime_get_sync(dev); - usb_phy_init(musb->xceiv); + val = IDDIG | AVALID | VBUSVALID; + omap4_usb_phy_mailbox(glue, val); break; case OMAP_MUSB_ID_FLOAT: @@ -281,17 +308,17 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) dev_dbg(dev, "VBUS Disconnect\n"); musb->xceiv->last_event = USB_EVENT_NONE; - if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) - if (musb->gadget_driver) { - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - } + if (musb->gadget_driver) { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } if (data->interface_type == MUSB_INTERFACE_UTMI) { if (musb->xceiv->otg->set_vbus) otg_set_vbus(musb->xceiv->otg, 0); } - usb_phy_shutdown(musb->xceiv); + val = SESSEND | IDDIG; + omap4_usb_phy_mailbox(glue, val); break; default: dev_dbg(dev, "ID float\n"); @@ -366,6 +393,7 @@ err1: static void omap2430_musb_enable(struct musb *musb) { u8 devctl; + u32 val; unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); @@ -375,7 +403,8 @@ static void omap2430_musb_enable(struct musb *musb) switch (glue->status) { case OMAP_MUSB_ID_GROUND: - usb_phy_init(musb->xceiv); + val = AVALID | VBUSVALID; + omap4_usb_phy_mailbox(glue, val); if (data->interface_type != MUSB_INTERFACE_UTMI) break; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); @@ -394,7 +423,8 @@ static void omap2430_musb_enable(struct musb *musb) break; case OMAP_MUSB_VBUS_VALID: - usb_phy_init(musb->xceiv); + val = IDDIG | AVALID | VBUSVALID; + omap4_usb_phy_mailbox(glue, val); break; default: @@ -404,11 +434,14 @@ static void omap2430_musb_enable(struct musb *musb) static void omap2430_musb_disable(struct musb *musb) { + u32 val; struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - if (glue->status != OMAP_MUSB_UNKNOWN) - usb_phy_shutdown(musb->xceiv); + if (glue->status != OMAP_MUSB_UNKNOWN) { + val = SESSEND | IDDIG; + omap4_usb_phy_mailbox(glue, val); + } } static int omap2430_musb_exit(struct musb *musb) @@ -438,9 +471,14 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int __devinit omap2430_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct omap_musb_board_data *data; struct platform_device *musb; struct omap2430_glue *glue; + struct device_node *np = pdev->dev.of_node; + struct musb_hdrc_config *config; + struct resource *res; int ret = -ENOMEM; + int musbid; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -448,12 +486,21 @@ static int __devinit omap2430_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err0; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err0; + goto err1; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &omap2430_dmamask; musb->dev.coherent_dma_mask = omap2430_dmamask; @@ -462,6 +509,48 @@ static int __devinit omap2430_probe(struct platform_device *pdev) glue->musb = musb; glue->status = OMAP_MUSB_UNKNOWN; + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res); + if (glue->control_otghs == NULL) + dev_dbg(&pdev->dev, "Failed to obtain control memory\n"); + + if (np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, + "failed to allocate musb platfrom data\n"); + ret = -ENOMEM; + goto err1; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, + "failed to allocate musb board data\n"); + ret = -ENOMEM; + goto err1; + } + + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, + "failed to allocate musb hdrc config\n"); + goto err1; + } + + of_property_read_u32(np, "mode", (u32 *)&pdata->mode); + of_property_read_u32(np, "interface_type", + (u32 *)&data->interface_type); + of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); + of_property_read_u32(np, "power", (u32 *)&pdata->power); + config->multipoint = of_property_read_bool(np, "multipoint"); + + pdata->board_data = data; + pdata->config = config; + } + pdata->platform_ops = &omap2430_ops; platform_set_drvdata(pdev, glue); @@ -478,13 +567,13 @@ static int __devinit omap2430_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err1; + goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err1; + goto err2; } pm_runtime_enable(&pdev->dev); @@ -492,14 +581,17 @@ static int __devinit omap2430_probe(struct platform_device *pdev) ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err1; + goto err2; } return 0; -err1: +err2: platform_device_put(musb); +err1: + musb_put_id(&pdev->dev, musbid); + err0: return ret; } @@ -509,8 +601,8 @@ static int __devexit omap2430_remove(struct platform_device *pdev) struct omap2430_glue *glue = platform_get_drvdata(pdev); cancel_work_sync(&glue->omap_musb_mailbox_work); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + musb_put_id(&pdev->dev, glue->musb->id); + platform_device_unregister(glue->musb); return 0; } @@ -559,12 +651,26 @@ static struct dev_pm_ops omap2430_pm_ops = { #define DEV_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id omap2430_id_table[] = { + { + .compatible = "ti,omap4-musb" + }, + { + .compatible = "ti,omap3-musb" + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap2430_id_table); +#endif + static struct platform_driver omap2430_driver = { .probe = omap2430_probe, .remove = __devexit_p(omap2430_remove), .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap2430_id_table), }, }; diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index 40b3c02..b85f397 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -49,4 +49,13 @@ #define OTG_FORCESTDBY 0x414 # define ENABLEFORCE (1 << 0) +/* + * Control Module bit definitions + * XXX: Will be removed once we have a driver for control module. + */ +#define AVALID BIT(0) +#define BVALID BIT(1) +#define VBUSVALID BIT(2) +#define SESSEND BIT(3) +#define IDDIG BIT(4) #endif /* __MUSB_OMAP243X_H__ */ diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 3416254..dc4d75e 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -24,6 +24,7 @@ #include <linux/irq.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/usb/nop-usb-xceiv.h> #include "musb_core.h" @@ -153,7 +154,7 @@ tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len) } static inline void tusb_fifo_read_unaligned(void __iomem *fifo, - void __iomem *buf, u16 len) + void *buf, u16 len) { u32 val; int i; @@ -437,14 +438,13 @@ static void musb_do_idle(unsigned long _musb) if (is_host_active(musb) && (musb->port1_status >> 16)) goto done; - if (is_peripheral_enabled(musb) && !musb->gadget_driver) { + if (!musb->gadget_driver) { wakeups = 0; } else { wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS | TUSB_PRCM_WVBUS; - if (is_otg_enabled(musb)) - wakeups |= TUSB_PRCM_WID; + wakeups |= TUSB_PRCM_WID; } tusb_allow_idle(musb, wakeups); } @@ -582,21 +582,12 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) * * Note that if a mini-A cable is plugged in the ID line will stay down as * the weak ID pull-up is not able to pull the ID up. - * - * REVISIT: It would be possible to add support for changing between host - * and peripheral modes in non-OTG configurations by reconfiguring hardware - * and then setting musb->board_mode. For now, only support OTG mode. */ static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode) { void __iomem *tbase = musb->ctrl_base; u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf; - if (musb->board_mode != MUSB_OTG) { - ERR("Changing mode currently only supported in OTG mode\n"); - return -EINVAL; - } - otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL); phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); @@ -652,10 +643,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) { int default_a; - if (is_otg_enabled(musb)) - default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS); - else - default_a = is_host_enabled(musb); + default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS); dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B'); otg->default_a = default_a; tusb_musb_set_vbus(musb, default_a); @@ -669,8 +657,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { /* B-dev state machine: no vbus ~= disconnect */ - if ((is_otg_enabled(musb) && !otg->default_a) - || !is_host_enabled(musb)) { + if (!otg->default_a) { /* ? musb_root_disconnect(musb); */ musb->port1_status &= ~(USB_PORT_STAT_CONNECTION @@ -1119,10 +1106,8 @@ static int tusb_musb_init(struct musb *musb) } musb->isr = tusb_musb_interrupt; - if (is_peripheral_enabled(musb)) { - musb->xceiv->set_power = tusb_draw_power; - the_musb = musb; - } + musb->xceiv->set_power = tusb_draw_power; + the_musb = musb; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); @@ -1175,6 +1160,7 @@ static int __devinit tusb_probe(struct platform_device *pdev) struct tusb6010_glue *glue; int ret = -ENOMEM; + int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -1182,12 +1168,21 @@ static int __devinit tusb_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &tusb_dmamask; musb->dev.coherent_dma_mask = tusb_dmamask; @@ -1203,26 +1198,29 @@ static int __devinit tusb_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; + goto err3; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; + goto err3; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err2; + goto err3; } return 0; -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -1234,6 +1232,7 @@ static int __devexit tusb_remove(struct platform_device *pdev) { struct tusb6010_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); kfree(glue); diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index b67b4bc..53e2596 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -662,7 +662,7 @@ void dma_controller_destroy(struct dma_controller *c) kfree(tusb_dma); } -struct dma_controller *__init +struct dma_controller *__devinit dma_controller_create(struct musb *musb, void __iomem *base) { void __iomem *tbase = musb->ctrl_base; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index a8c0fad..d62a91f 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -74,25 +74,34 @@ static int __devinit ux500_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", -1); + /* get the musb id */ + musbid = musb_get_id(&pdev->dev, GFP_KERNEL); + if (musbid < 0) { + dev_err(&pdev->dev, "failed to allocate musb id\n"); + ret = -ENOMEM; + goto err1; + } + + musb = platform_device_alloc("musb-hdrc", musbid); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err2; } clk = clk_get(&pdev->dev, "usb"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); ret = PTR_ERR(clk); - goto err2; + goto err3; } ret = clk_enable(clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; + goto err4; } + musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = pdev->dev.dma_mask; musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; @@ -109,32 +118,35 @@ static int __devinit ux500_probe(struct platform_device *pdev) pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; + goto err5; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; + goto err5; } ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; + goto err5; } return 0; -err4: +err5: clk_disable(clk); -err3: +err4: clk_put(clk); -err2: +err3: platform_device_put(musb); +err2: + musb_put_id(&pdev->dev, musbid); + err1: kfree(glue); @@ -146,6 +158,7 @@ static int __devexit ux500_remove(struct platform_device *pdev) { struct ux500_glue *glue = platform_get_drvdata(pdev); + musb_put_id(&pdev->dev, glue->musb->id); platform_device_del(glue->musb); platform_device_put(glue->musb); clk_disable(glue->clk); diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index d05c7fb..639d58e 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -364,7 +364,7 @@ void dma_controller_destroy(struct dma_controller *c) kfree(controller); } -struct dma_controller *__init +struct dma_controller *__devinit dma_controller_create(struct musb *musb, void __iomem *base) { struct ux500_dma_controller *controller; diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 13fd1ddf..d8c8a42 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -68,7 +68,7 @@ config TWL4030_USB config TWL6030_USB tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE + depends on TWL4030_CORE && OMAP_USB2 select USB_OTG_UTILS help Enable this to support the USB OTG transceiver on TWL6030 diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index 23c798c..c19d1d7 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -544,9 +544,13 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) */ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) { - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); + struct fsl_otg *otg_dev; + + if (!otg) + return -ENODEV; - if (!otg || otg_dev != fsl_otg_dev) + otg_dev = container_of(otg->phy, struct fsl_otg, phy); + if (otg_dev != fsl_otg_dev) return -ENODEV; otg->host = host; @@ -590,12 +594,15 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) static int fsl_otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); + struct fsl_otg *otg_dev; + if (!otg) + return -ENODEV; + + otg_dev = container_of(otg->phy, struct fsl_otg, phy); VDBG("otg_dev 0x%x\n", (int)otg_dev); VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev); - - if (!otg || otg_dev != fsl_otg_dev) + if (otg_dev != fsl_otg_dev) return -ENODEV; if (!gadget) { @@ -660,10 +667,13 @@ static void fsl_otg_event(struct work_struct *work) /* B-device start SRP */ static int fsl_otg_start_srp(struct usb_otg *otg) { - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); + struct fsl_otg *otg_dev; + + if (!otg || otg->phy->state != OTG_STATE_B_IDLE) + return -ENODEV; - if (!otg || otg_dev != fsl_otg_dev - || otg->phy->state != OTG_STATE_B_IDLE) + otg_dev = container_of(otg->phy, struct fsl_otg, phy); + if (otg_dev != fsl_otg_dev) return -ENODEV; otg_dev->fsm.b_bus_req = 1; @@ -675,9 +685,13 @@ static int fsl_otg_start_srp(struct usb_otg *otg) /* A_host suspend will call this function to start hnp */ static int fsl_otg_start_hnp(struct usb_otg *otg) { - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); + struct fsl_otg *otg_dev; + + if (!otg) + return -ENODEV; - if (!otg || otg_dev != fsl_otg_dev) + otg_dev = container_of(otg->phy, struct fsl_otg, phy); + if (otg_dev != fsl_otg_dev) return -ENODEV; DBG("start_hnp...n"); diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c index c1a67cb..88db976 100644 --- a/drivers/usb/otg/mxs-phy.c +++ b/drivers/usb/otg/mxs-phy.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/workqueue.h> #define DRIVER_NAME "mxs_phy" @@ -34,9 +35,16 @@ #define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14) #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1) +/* + * Amount of delay in miliseconds to safely enable ENHOSTDISCONDETECT bit + * so that connection and reset processing can be completed for the root hub. + */ +#define MXY_PHY_ENHOSTDISCONDETECT_DELAY 250 + struct mxs_phy { struct usb_phy phy; struct clk *clk; + struct delayed_work enhostdiscondetect_work; }; #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) @@ -62,6 +70,7 @@ static int mxs_phy_init(struct usb_phy *phy) clk_prepare_enable(mxs_phy->clk); mxs_phy_hw_init(mxs_phy); + INIT_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, NULL); return 0; } @@ -76,13 +85,34 @@ static void mxs_phy_shutdown(struct usb_phy *phy) clk_disable_unprepare(mxs_phy->clk); } +static void mxs_phy_enhostdiscondetect_delay(struct work_struct *ws) +{ + struct mxs_phy *mxs_phy = container_of(ws, struct mxs_phy, + enhostdiscondetect_work.work); + + /* Enable HOSTDISCONDETECT after delay. */ + dev_dbg(mxs_phy->phy.dev, "Setting ENHOSTDISCONDETECT\n"); + writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET); +} + static int mxs_phy_on_connect(struct usb_phy *phy, int port) { + struct mxs_phy *mxs_phy = to_mxs_phy(phy); + dev_dbg(phy->dev, "Connect on port %d\n", port); - mxs_phy_hw_init(to_mxs_phy(phy)); - writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, - phy->io_priv + HW_USBPHY_CTRL_SET); + mxs_phy_hw_init(mxs_phy); + + /* + * Delay enabling ENHOSTDISCONDETECT so that connection and + * reset processing can be completed for the root hub. + */ + dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n"); + PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, + mxs_phy_enhostdiscondetect_delay); + schedule_delayed_work(&mxs_phy->enhostdiscondetect_work, + msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY)); return 0; } @@ -91,6 +121,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy, int port) { dev_dbg(phy->dev, "Disconnect on port %d\n", port); + /* No need to delay before clearing ENHOSTDISCONDETECT. */ + dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n"); writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, phy->io_priv + HW_USBPHY_CTRL_CLR); diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index 803f958..e52e35e 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/usb/otg.h> +#include <linux/usb/nop-usb-xceiv.h> #include <linux/slab.h> struct nop_usb_xceiv { @@ -94,7 +95,9 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) { + struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; struct nop_usb_xceiv *nop; + enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; nop = kzalloc(sizeof *nop, GFP_KERNEL); @@ -107,6 +110,9 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) return -ENOMEM; } + if (pdata) + type = pdata->type; + nop->dev = &pdev->dev; nop->phy.dev = nop->dev; nop->phy.label = "nop-xceiv"; @@ -117,7 +123,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) nop->phy.otg->set_host = nop_set_host; nop->phy.otg->set_peripheral = nop_set_peripheral; - err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2); + err = usb_add_phy(&nop->phy, type); if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", err); diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index 1bf60a2..a30c041 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -159,7 +159,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) unsigned long flags; struct usb_phy *phy; - if (x && x->type != USB_PHY_TYPE_UNDEFINED) { + if (x->type != USB_PHY_TYPE_UNDEFINED) { dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); return -EINVAL; } diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 523cad5..f0d2e75 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -585,23 +585,28 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb *twl; int status, err; struct usb_otg *otg; - - if (!pdata) { - dev_dbg(&pdev->dev, "platform_data not available\n"); - return -EINVAL; - } + struct device_node *np = pdev->dev.of_node; twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL); if (!twl) return -ENOMEM; + if (np) + of_property_read_u32(np, "usb_mode", + (enum twl4030_usb_mode *)&twl->usb_mode); + else if (pdata) + twl->usb_mode = pdata->usb_mode; + else { + dev_err(&pdev->dev, "twl4030 initialized without pdata\n"); + return -EINVAL; + } + otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL); if (!otg) return -ENOMEM; twl->dev = &pdev->dev; twl->irq = platform_get_irq(pdev, 0); - twl->usb_mode = pdata->usb_mode; twl->vbus_supplied = false; twl->asleep = 1; twl->linkstat = OMAP_MUSB_UNKNOWN; @@ -690,12 +695,21 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl4030_usb_id_table[] = { + { .compatible = "ti,twl4030-usb" }, + {} +}; +MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); +#endif + static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, .remove = __exit_p(twl4030_usb_remove), .driver = { .name = "twl4030_usb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl4030_usb_id_table), }, }; diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index 6907d8d..fcadef7 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c @@ -25,8 +25,9 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/usb/otg.h> #include <linux/usb/musb-omap.h> +#include <linux/usb/phy_companion.h> +#include <linux/usb/omap_usb.h> #include <linux/i2c/twl.h> #include <linux/regulator/consumer.h> #include <linux/err.h> @@ -87,7 +88,7 @@ #define VBUS_DET BIT(2) struct twl6030_usb { - struct usb_phy phy; + struct phy_companion comparator; struct device *dev; /* for vbus reporting with irqs disabled */ @@ -104,10 +105,10 @@ struct twl6030_usb { u8 asleep; bool irq_enabled; bool vbus_enable; - unsigned long features; + const char *regulator; }; -#define phy_to_twl(x) container_of((x), struct twl6030_usb, phy) +#define comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator) /*-------------------------------------------------------------------------*/ @@ -137,50 +138,9 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address) return ret; } -static int twl6030_phy_init(struct usb_phy *x) +static int twl6030_start_srp(struct phy_companion *comparator) { - struct twl6030_usb *twl; - struct device *dev; - struct twl4030_usb_data *pdata; - - twl = phy_to_twl(x); - dev = twl->dev; - pdata = dev->platform_data; - - if (twl->linkstat == OMAP_MUSB_ID_GROUND) - pdata->phy_power(twl->dev, 1, 1); - else - pdata->phy_power(twl->dev, 0, 1); - - return 0; -} - -static void twl6030_phy_shutdown(struct usb_phy *x) -{ - struct twl6030_usb *twl; - struct device *dev; - struct twl4030_usb_data *pdata; - - twl = phy_to_twl(x); - dev = twl->dev; - pdata = dev->platform_data; - pdata->phy_power(twl->dev, 0, 0); -} - -static int twl6030_phy_suspend(struct usb_phy *x, int suspend) -{ - struct twl6030_usb *twl = phy_to_twl(x); - struct device *dev = twl->dev; - struct twl4030_usb_data *pdata = dev->platform_data; - - pdata->phy_suspend(dev, suspend); - - return 0; -} - -static int twl6030_start_srp(struct usb_otg *otg) -{ - struct twl6030_usb *twl = phy_to_twl(otg->phy); + struct twl6030_usb *twl = comparator_to_twl(comparator); twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET); twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET); @@ -193,13 +153,6 @@ static int twl6030_start_srp(struct usb_otg *otg) static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { - char *regulator_name; - - if (twl->features & TWL6025_SUBCLASS) - regulator_name = "ldousb"; - else - regulator_name = "vusb"; - /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); @@ -209,7 +162,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl) /* Program MISC2 register and set bit VUSB_IN_VBAT */ twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); - twl->usb3v3 = regulator_get(twl->dev, regulator_name); + twl->usb3v3 = regulator_get(twl->dev, twl->regulator); if (IS_ERR(twl->usb3v3)) return -ENODEV; @@ -313,23 +266,8 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) return IRQ_HANDLED; } -static int twl6030_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - if (!otg) - return -ENODEV; - - otg->gadget = gadget; - if (!gadget) - otg->phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int twl6030_enable_irq(struct usb_phy *x) +static int twl6030_enable_irq(struct twl6030_usb *twl) { - struct twl6030_usb *twl = phy_to_twl(x); - twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C); @@ -362,9 +300,9 @@ static void otg_set_vbus_work(struct work_struct *data) CHARGERUSB_CTRL1); } -static int twl6030_set_vbus(struct usb_otg *otg, bool enabled) +static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled) { - struct twl6030_usb *twl = phy_to_twl(otg->phy); + struct twl6030_usb *twl = comparator_to_twl(comparator); twl->vbus_enable = enabled; schedule_work(&twl->set_vbus_work); @@ -372,52 +310,44 @@ static int twl6030_set_vbus(struct usb_otg *otg, bool enabled) return 0; } -static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - otg->host = host; - if (!host) - otg->phy->state = OTG_STATE_UNDEFINED; - return 0; -} - static int __devinit twl6030_usb_probe(struct platform_device *pdev) { + u32 ret; struct twl6030_usb *twl; int status, err; - struct twl4030_usb_data *pdata; - struct usb_otg *otg; - struct device *dev = &pdev->dev; - pdata = dev->platform_data; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct twl4030_usb_data *pdata = dev->platform_data; twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL); if (!twl) return -ENOMEM; - otg = devm_kzalloc(dev, sizeof *otg, GFP_KERNEL); - if (!otg) - return -ENOMEM; - twl->dev = &pdev->dev; twl->irq1 = platform_get_irq(pdev, 0); twl->irq2 = platform_get_irq(pdev, 1); - twl->features = pdata->features; twl->linkstat = OMAP_MUSB_UNKNOWN; - twl->phy.dev = twl->dev; - twl->phy.label = "twl6030"; - twl->phy.otg = otg; - twl->phy.init = twl6030_phy_init; - twl->phy.shutdown = twl6030_phy_shutdown; - twl->phy.set_suspend = twl6030_phy_suspend; + twl->comparator.set_vbus = twl6030_set_vbus; + twl->comparator.start_srp = twl6030_start_srp; + + ret = omap_usb2_set_comparator(&twl->comparator); + if (ret == -ENODEV) { + dev_info(&pdev->dev, "phy not ready, deferring probe"); + return -EPROBE_DEFER; + } - otg->phy = &twl->phy; - otg->set_host = twl6030_set_host; - otg->set_peripheral = twl6030_set_peripheral; - otg->set_vbus = twl6030_set_vbus; - otg->start_srp = twl6030_start_srp; + if (np) { + twl->regulator = "usb"; + } else if (pdata) { + if (pdata->features & TWL6025_SUBCLASS) + twl->regulator = "ldousb"; + else + twl->regulator = "vusb"; + } else { + dev_err(&pdev->dev, "twl6030 initialized without pdata\n"); + return -EINVAL; + } /* init spinlock for workqueue */ spin_lock_init(&twl->lock); @@ -427,7 +357,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ldo init failed\n"); return err; } - usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); platform_set_drvdata(pdev, twl); if (device_create_file(&pdev->dev, &dev_attr_vbus)) @@ -458,9 +387,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) } twl->asleep = 0; - pdata->phy_init(dev); - twl6030_phy_suspend(&twl->phy, 0); - twl6030_enable_irq(&twl->phy); + twl6030_enable_irq(twl); dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); return 0; @@ -470,10 +397,6 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - struct twl4030_usb_data *pdata; - struct device *dev = &pdev->dev; - pdata = dev->platform_data; - twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, @@ -481,19 +404,27 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev) free_irq(twl->irq1, twl); free_irq(twl->irq2, twl); regulator_put(twl->usb3v3); - pdata->phy_exit(twl->dev); device_remove_file(twl->dev, &dev_attr_vbus); cancel_work_sync(&twl->set_vbus_work); return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl6030_usb_id_table[] = { + { .compatible = "ti,twl6030-usb" }, + {} +}; +MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); +#endif + static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, .remove = __exit_p(twl6030_usb_remove), .driver = { .name = "twl6030_usb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl6030_usb_id_table), }, }; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index e7cf84f..63c339b 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -4,6 +4,15 @@ comment "USB Physical Layer drivers" depends on USB || USB_GADGET +config OMAP_USB2 + tristate "OMAP USB2 PHY Driver" + select USB_OTG_UTILS + help + Enable this to support the transceiver that is part of SOC. This + driver takes care of all the PHY functionality apart from comparator. + The USB OTG controller communicates with the comparator using this + driver. + config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET @@ -15,3 +24,11 @@ config USB_ISP1301 To compile this driver as a module, choose M here: the module will be called isp1301. + +config MV_U3D_PHY + bool "Marvell USB 3.0 PHY controller Driver" + depends on USB_MV_U3D + select USB_OTG_UTILS + help + Enable this to support Marvell USB 3.0 phy controller for Marvell + SoC. diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index eca095b..b069f29 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -4,4 +4,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG +obj-$(CONFIG_OMAP_USB2) += omap-usb2.o obj-$(CONFIG_USB_ISP1301) += isp1301.o +obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o +obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c index b19f493..18dbf7e 100644 --- a/drivers/usb/phy/isp1301.c +++ b/drivers/usb/phy/isp1301.c @@ -15,12 +15,6 @@ #define DRV_NAME "isp1301" -#define ISP1301_I2C_ADDR 0x2C - -static const unsigned short normal_i2c[] = { - ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END -}; - static const struct i2c_device_id isp1301_id[] = { { "isp1301", 0 }, { } diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c new file mode 100644 index 0000000..9f1c5d3 --- /dev/null +++ b/drivers/usb/phy/mv_u3d_phy.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/usb/otg.h> +#include <linux/platform_data/mv_usb.h> + +#include "mv_u3d_phy.h" + +/* + * struct mv_u3d_phy - transceiver driver state + * @phy: transceiver structure + * @dev: The parent device supplied to the probe function + * @clk: usb phy clock + * @base: usb phy register memory base + */ +struct mv_u3d_phy { + struct usb_phy phy; + struct mv_usb_platform_data *plat; + struct device *dev; + struct clk *clk; + void __iomem *base; +}; + +static u32 mv_u3d_phy_read(void __iomem *base, u32 reg) +{ + void __iomem *addr, *data; + + addr = base; + data = base + 0x4; + + writel_relaxed(reg, addr); + return readl_relaxed(data); +} + +static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) +{ + void __iomem *addr, *data; + u32 tmp; + + addr = base; + data = base + 0x4; + + writel_relaxed(reg, addr); + tmp = readl_relaxed(data); + tmp |= value; + writel_relaxed(tmp, data); +} + +static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) +{ + void __iomem *addr, *data; + u32 tmp; + + addr = base; + data = base + 0x4; + + writel_relaxed(reg, addr); + tmp = readl_relaxed(data); + tmp &= ~value; + writel_relaxed(tmp, data); +} + +static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) +{ + void __iomem *addr, *data; + + addr = base; + data = base + 0x4; + + writel_relaxed(reg, addr); + writel_relaxed(value, data); +} + +void mv_u3d_phy_shutdown(struct usb_phy *phy) +{ + struct mv_u3d_phy *mv_u3d_phy; + void __iomem *base; + u32 val; + + mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); + base = mv_u3d_phy->base; + + /* Power down Reference Analog current, bit 15 + * Power down PLL, bit 14 + * Power down Receiver, bit 13 + * Power down Transmitter, bit 12 + * of USB3_POWER_PLL_CONTROL register + */ + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); + val &= ~(USB3_POWER_PLL_CONTROL_PU); + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); + + if (mv_u3d_phy->clk) + clk_disable(mv_u3d_phy->clk); +} + +static int mv_u3d_phy_init(struct usb_phy *phy) +{ + struct mv_u3d_phy *mv_u3d_phy; + void __iomem *base; + u32 val, count; + + /* enable usb3 phy */ + mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); + + if (mv_u3d_phy->clk) + clk_enable(mv_u3d_phy->clk); + + base = mv_u3d_phy->base; + + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); + val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK); + val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT; + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); + udelay(100); + + mv_u3d_phy_write(base, USB3_RESET_CONTROL, + USB3_RESET_CONTROL_RESET_PIPE); + udelay(100); + + mv_u3d_phy_write(base, USB3_RESET_CONTROL, + USB3_RESET_CONTROL_RESET_PIPE + | USB3_RESET_CONTROL_RESET_PHY); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); + val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK + | USB3_POWER_PLL_CONTROL_PHY_MODE_MASK); + val |= (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT) + | (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT); + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); + udelay(100); + + mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL, + USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE); + val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK + | USB3_SQUELCH_FFE_FFE_RES_SEL_MASK + | USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK); + val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT) + | (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT) + | (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT)); + mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_GEN1_SET0); + val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK; + val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT; + mv_u3d_phy_write(base, USB3_GEN1_SET0, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_GEN2_SET0); + val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK + | USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK + | USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK); + val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT) + | (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT) + | (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT) + | (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT)); + mv_u3d_phy_write(base, USB3_GEN2_SET0, val); + udelay(100); + + mv_u3d_phy_read(base, USB3_TX_EMPPH); + val &= ~(USB3_TX_EMPPH_AMP_MASK + | USB3_TX_EMPPH_EN_MASK + | USB3_TX_EMPPH_AMP_FORCE_MASK + | USB3_TX_EMPPH_PAR1_MASK + | USB3_TX_EMPPH_PAR2_MASK); + val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT) + | (1 << USB3_TX_EMPPH_EN_SHIFT) + | (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT) + | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT) + | (1 << USB3_TX_EMPPH_PAR2_SHIFT)); + + mv_u3d_phy_write(base, USB3_TX_EMPPH, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_GEN2_SET1); + val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK + | USB3_GEN2_SET1_G2_RX_SELMUPF_MASK + | USB3_GEN2_SET1_G2_RX_SELMUFI_MASK + | USB3_GEN2_SET1_G2_RX_SELMUFF_MASK); + val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT) + | (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT) + | (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT) + | (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT)); + mv_u3d_phy_write(base, USB3_GEN2_SET1, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN); + val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK; + val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT; + mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC); + val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK; + val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT; + mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL); + val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK; + val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT; + mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE); + val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK + | USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK + | USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK); + val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT) + | (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT)); + mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val); + udelay(100); + + val = mv_u3d_phy_read(base, USB3_TXDETRX); + val &= ~(USB3_TXDETRX_VTHSEL_MASK); + val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT; + mv_u3d_phy_write(base, USB3_TXDETRX, val); + udelay(100); + + dev_dbg(mv_u3d_phy->dev, "start calibration\n"); + +calstart: + /* Perform Manual Calibration */ + mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL, + 1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT); + + mdelay(1); + + count = 0; + while (1) { + val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL); + if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT)) + break; + else if (count > 50) { + dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n"); + goto calstart; + } + count++; + mdelay(1); + } + + /* active PIPE interface */ + mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL, + 1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE); + + return 0; +} + +static int __devinit mv_u3d_phy_probe(struct platform_device *pdev) +{ + struct mv_u3d_phy *mv_u3d_phy; + struct mv_usb_platform_data *pdata; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *phy_base; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing mem resource\n"); + return -ENODEV; + } + + phy_base = devm_request_and_ioremap(dev, res); + if (!phy_base) { + dev_err(dev, "%s: register mapping failed\n", __func__); + return -ENXIO; + } + + mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL); + if (!mv_u3d_phy) + return -ENOMEM; + + mv_u3d_phy->dev = &pdev->dev; + mv_u3d_phy->plat = pdata; + mv_u3d_phy->base = phy_base; + mv_u3d_phy->phy.dev = mv_u3d_phy->dev; + mv_u3d_phy->phy.label = "mv-u3d-phy"; + mv_u3d_phy->phy.init = mv_u3d_phy_init; + mv_u3d_phy->phy.shutdown = mv_u3d_phy_shutdown; + + ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3); + if (ret) + goto err; + + if (!mv_u3d_phy->clk) + mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy"); + + platform_set_drvdata(pdev, mv_u3d_phy); + + dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n"); +err: + return ret; +} + +static int __exit mv_u3d_phy_remove(struct platform_device *pdev) +{ + struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&mv_u3d_phy->phy); + + if (mv_u3d_phy->clk) { + clk_put(mv_u3d_phy->clk); + mv_u3d_phy->clk = NULL; + } + + return 0; +} + +static struct platform_driver mv_u3d_phy_driver = { + .probe = mv_u3d_phy_probe, + .remove = __devexit_p(mv_u3d_phy_remove), + .driver = { + .name = "mv-u3d-phy", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(mv_u3d_phy_driver); +MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller"); +MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mv-u3d-phy"); diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/mv_u3d_phy.h new file mode 100644 index 0000000..2a658cb --- /dev/null +++ b/drivers/usb/phy/mv_u3d_phy.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef __MV_U3D_PHY_H +#define __MV_U3D_PHY_H + +#define USB3_POWER_PLL_CONTROL 0x1 +#define USB3_KVCO_CALI_CONTROL 0x2 +#define USB3_IMPEDANCE_CALI_CTRL 0x3 +#define USB3_IMPEDANCE_TX_SSC 0x4 +#define USB3_SQUELCH_FFE 0x6 +#define USB3_GEN1_SET0 0xD +#define USB3_GEN2_SET0 0xF +#define USB3_GEN2_SET1 0x10 +#define USB3_DIGITAL_LOOPBACK_EN 0x23 +#define USB3_PHY_ISOLATION_MODE 0x26 +#define USB3_TXDETRX 0x48 +#define USB3_TX_EMPPH 0x5E +#define USB3_RESET_CONTROL 0x90 +#define USB3_PIPE_SM_CTRL 0x91 + +#define USB3_RESET_CONTROL_RESET_PIPE 0x1 +#define USB3_RESET_CONTROL_RESET_PHY 0x2 + +#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK (0x1F << 0) +#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT 0 +#define USB3_PLL_25MHZ 0x2 +#define USB3_PLL_26MHZ 0x5 +#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK (0x7 << 5) +#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT 5 +#define USB3_POWER_PLL_CONTROL_PU_MASK (0xF << 12) +#define USB3_POWER_PLL_CONTROL_PU_SHIFT 12 +#define USB3_POWER_PLL_CONTROL_PU (0xF << 12) + +#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK (0x1 << 12) +#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT 12 +#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT 14 +#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT 15 + +#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK 0xF +#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT 0 +#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK (0x7 << 4) +#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT 4 +#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK (0x1F << 8) +#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT 8 + +#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK (0x1 << 15) +#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT 11 + +#define USB3_GEN2_SET0_G2_TX_AMP_MASK (0x1F << 1) +#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT 1 +#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT 6 +#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK (0xF << 7) +#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT 7 +#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK (0x1 << 11) +#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT 11 +#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK (0x1 << 15) +#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT 15 + +#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK (0x7 << 0) +#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT 0 +#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK (0x7 << 3) +#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT 3 +#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK (0x3 << 6) +#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT 6 +#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK (0x3 << 8) +#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT 8 + +#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK (0x3 << 10) +#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT 10 + +#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK (0x7 << 12) +#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT 12 + +#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK (0x3F << 0) +#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT 0 + +#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK 0xF +#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT 0 +#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK (0xF << 4) +#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT 4 +#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK (0x1 << 8) + +#define USB3_TXDETRX_VTHSEL_MASK (0x3 << 4) +#define USB3_TXDETRX_VTHSEL_SHIFT 4 + +#define USB3_TX_EMPPH_AMP_MASK (0xF << 0) +#define USB3_TX_EMPPH_AMP_SHIFT 0 +#define USB3_TX_EMPPH_EN_MASK (0x1 << 6) +#define USB3_TX_EMPPH_EN_SHIFT 6 +#define USB3_TX_EMPPH_AMP_FORCE_MASK (0x1 << 7) +#define USB3_TX_EMPPH_AMP_FORCE_SHIFT 7 +#define USB3_TX_EMPPH_PAR1_MASK (0x1F << 8) +#define USB3_TX_EMPPH_PAR1_SHIFT 8 +#define USB3_TX_EMPPH_PAR2_MASK (0x1 << 13) +#define USB3_TX_EMPPH_PAR2_SHIFT 13 + +#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE 15 + +#endif /* __MV_U3D_PHY_H */ diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c new file mode 100644 index 0000000..15ab3d6 --- /dev/null +++ b/drivers/usb/phy/omap-usb2.c @@ -0,0 +1,271 @@ +/* + * omap-usb2.c - USB PHY, talking to musb controller in OMAP. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I <kishon@ti.com> + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/io.h> +#include <linux/usb/omap_usb.h> +#include <linux/usb/phy_companion.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> +#include <linux/delay.h> + +/** + * omap_usb2_set_comparator - links the comparator present in the sytem with + * this phy + * @comparator - the companion phy(comparator) for this phy + * + * The phy companion driver should call this API passing the phy_companion + * filled with set_vbus and start_srp to be used by usb phy. + * + * For use by phy companion driver + */ +int omap_usb2_set_comparator(struct phy_companion *comparator) +{ + struct omap_usb *phy; + struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2); + + if (IS_ERR(x)) + return -ENODEV; + + phy = phy_to_omapusb(x); + phy->comparator = comparator; + return 0; +} +EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); + +/** + * omap_usb_phy_power - power on/off the phy using control module reg + * @phy: struct omap_usb * + * @on: 0 or 1, based on powering on or off the PHY + * + * XXX: Remove this function once control module driver gets merged + */ +static void omap_usb_phy_power(struct omap_usb *phy, int on) +{ + u32 val; + + if (on) { + val = readl(phy->control_dev); + if (val & PHY_PD) { + writel(~PHY_PD, phy->control_dev); + /* XXX: add proper documentation for this delay */ + mdelay(200); + } + } else { + writel(PHY_PD, phy->control_dev); + } +} + +static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->set_vbus(phy->comparator, enabled); +} + +static int omap_usb_start_srp(struct usb_otg *otg) +{ + struct omap_usb *phy = phy_to_omapusb(otg->phy); + + if (!phy->comparator) + return -ENODEV; + + return phy->comparator->start_srp(phy->comparator); +} + +static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + struct usb_phy *phy = otg->phy; + + otg->host = host; + if (!host) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + struct usb_phy *phy = otg->phy; + + otg->gadget = gadget; + if (!gadget) + phy->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int omap_usb2_suspend(struct usb_phy *x, int suspend) +{ + u32 ret; + struct omap_usb *phy = phy_to_omapusb(x); + + if (suspend && !phy->is_suspended) { + omap_usb_phy_power(phy, 0); + pm_runtime_put_sync(phy->dev); + phy->is_suspended = 1; + } else if (!suspend && phy->is_suspended) { + ret = pm_runtime_get_sync(phy->dev); + if (ret < 0) { + dev_err(phy->dev, "get_sync failed with err %d\n", + ret); + return ret; + } + omap_usb_phy_power(phy, 1); + phy->is_suspended = 0; + } + + return 0; +} + +static int __devinit omap_usb2_probe(struct platform_device *pdev) +{ + struct omap_usb *phy; + struct usb_otg *otg; + struct resource *res; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); + return -ENOMEM; + } + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) { + dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); + return -ENOMEM; + } + + phy->dev = &pdev->dev; + + phy->phy.dev = phy->dev; + phy->phy.label = "omap-usb2"; + phy->phy.set_suspend = omap_usb2_suspend; + phy->phy.otg = otg; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + phy->control_dev = devm_request_and_ioremap(&pdev->dev, res); + if (phy->control_dev == NULL) { + dev_err(&pdev->dev, "Failed to obtain io memory\n"); + return -ENXIO; + } + + phy->is_suspended = 1; + omap_usb_phy_power(phy, 0); + + otg->set_host = omap_usb_set_host; + otg->set_peripheral = omap_usb_set_peripheral; + otg->set_vbus = omap_usb_set_vbus; + otg->start_srp = omap_usb_start_srp; + otg->phy = &phy->phy; + + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); + return PTR_ERR(phy->wkupclk); + } + clk_prepare(phy->wkupclk); + + usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2); + + platform_set_drvdata(pdev, phy); + + pm_runtime_enable(phy->dev); + + return 0; +} + +static int __devexit omap_usb2_remove(struct platform_device *pdev) +{ + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_unprepare(phy->wkupclk); + usb_remove_phy(&phy->phy); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int omap_usb2_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_disable(phy->wkupclk); + + return 0; +} + +static int omap_usb2_runtime_resume(struct device *dev) +{ + u32 ret = 0; + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + ret = clk_enable(phy->wkupclk); + if (ret < 0) + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops omap_usb2_pm_ops = { + SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&omap_usb2_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id omap_usb2_id_table[] = { + { .compatible = "ti,omap-usb2" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_usb2_id_table); +#endif + +static struct platform_driver omap_usb2_driver = { + .probe = omap_usb2_probe, + .remove = __devexit_p(omap_usb2_remove), + .driver = { + .name = "omap-usb2", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap_usb2_id_table), + }, +}; + +module_platform_driver(omap_usb2_driver); + +MODULE_ALIAS("platform: omap_usb2"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP USB2 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-tegra/usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 022b33a..4739903 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -1,6 +1,4 @@ /* - * arch/arm/mach-tegra/usb_phy.c - * * Copyright (C) 2010 Google, Inc. * * Author: @@ -31,7 +29,7 @@ #include <linux/usb/ulpi.h> #include <asm/mach-types.h> #include <mach/gpio-tegra.h> -#include <mach/usb_phy.h> +#include <linux/usb/tegra_usb_phy.h> #include <mach/iomap.h> #define ULPI_VIEWPORT 0x170 @@ -482,7 +480,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) return 0; } -static void utmi_phy_power_off(struct tegra_usb_phy *phy) +static int utmi_phy_power_off(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; @@ -514,7 +512,7 @@ static void utmi_phy_power_off(struct tegra_usb_phy *phy) UTMIP_FORCE_PDDR_POWERDOWN; writel(val, base + UTMIP_XCVR_CFG1); - utmip_pad_power_off(phy); + return utmip_pad_power_off(phy); } static void utmi_phy_preresume(struct tegra_usb_phy *phy) @@ -638,7 +636,7 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) return 0; } -static void ulpi_phy_power_off(struct tegra_usb_phy *phy) +static int ulpi_phy_power_off(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; @@ -651,15 +649,92 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy) val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); writel(val, base + USB_PORTSC1); - gpio_direction_output(config->reset_gpio, 0); clk_disable(phy->clk); + return gpio_direction_output(config->reset_gpio, 0); +} + +static int tegra_phy_init(struct usb_phy *x) +{ + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + struct tegra_ulpi_config *ulpi_config; + int err; + + if (phy_is_ulpi(phy)) { + ulpi_config = phy->config; + phy->clk = clk_get_sys(NULL, ulpi_config->clk); + if (IS_ERR(phy->clk)) { + pr_err("%s: can't get ulpi clock\n", __func__); + err = -ENXIO; + goto err1; + } + if (!gpio_is_valid(ulpi_config->reset_gpio)) + ulpi_config->reset_gpio = + of_get_named_gpio(phy->dev->of_node, + "nvidia,phy-reset-gpio", 0); + if (!gpio_is_valid(ulpi_config->reset_gpio)) { + pr_err("%s: invalid reset gpio: %d\n", __func__, + ulpi_config->reset_gpio); + err = -EINVAL; + goto err1; + } + gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b"); + gpio_direction_output(ulpi_config->reset_gpio, 0); + phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); + phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT; + } else { + err = utmip_pad_open(phy); + if (err < 0) + goto err1; + } + return 0; +err1: + clk_disable_unprepare(phy->pll_u); + clk_put(phy->pll_u); + return err; +} + +static void tegra_usb_phy_close(struct usb_phy *x) +{ + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + + if (phy_is_ulpi(phy)) + clk_put(phy->clk); + else + utmip_pad_close(phy); + clk_disable_unprepare(phy->pll_u); + clk_put(phy->pll_u); + kfree(phy); +} + +static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) +{ + if (phy_is_ulpi(phy)) + return ulpi_phy_power_on(phy); + else + return utmi_phy_power_on(phy); +} + +static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) +{ + if (phy_is_ulpi(phy)) + return ulpi_phy_power_off(phy); + else + return utmi_phy_power_off(phy); +} + +static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend) +{ + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (suspend) + return tegra_usb_phy_power_off(phy); + else + return tegra_usb_phy_power_on(phy); } struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode) { struct tegra_usb_phy *phy; - struct tegra_ulpi_config *ulpi_config; unsigned long parent_rate; int i; int err; @@ -672,6 +747,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, phy->regs = regs; phy->config = config; phy->mode = phy_mode; + phy->dev = dev; if (!phy->config) { if (phy_is_ulpi(phy)) { @@ -704,33 +780,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, goto err1; } - if (phy_is_ulpi(phy)) { - ulpi_config = config; - phy->clk = clk_get_sys(NULL, ulpi_config->clk); - if (IS_ERR(phy->clk)) { - pr_err("%s: can't get ulpi clock\n", __func__); - err = -ENXIO; - goto err1; - } - if (!gpio_is_valid(ulpi_config->reset_gpio)) - ulpi_config->reset_gpio = - of_get_named_gpio(dev->of_node, - "nvidia,phy-reset-gpio", 0); - if (!gpio_is_valid(ulpi_config->reset_gpio)) { - pr_err("%s: invalid reset gpio: %d\n", __func__, - ulpi_config->reset_gpio); - err = -EINVAL; - goto err1; - } - gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b"); - gpio_direction_output(ulpi_config->reset_gpio, 0); - phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); - phy->ulpi->io_priv = regs + ULPI_VIEWPORT; - } else { - err = utmip_pad_open(phy); - if (err < 0) - goto err1; - } + phy->u_phy.init = tegra_phy_init; + phy->u_phy.shutdown = tegra_usb_phy_close; + phy->u_phy.set_suspend = tegra_usb_phy_suspend; return phy; @@ -743,24 +795,6 @@ err0: } EXPORT_SYMBOL_GPL(tegra_usb_phy_open); -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) -{ - if (phy_is_ulpi(phy)) - return ulpi_phy_power_on(phy); - else - return utmi_phy_power_on(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on); - -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy) -{ - if (phy_is_ulpi(phy)) - ulpi_phy_power_off(phy); - else - utmi_phy_power_off(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off); - void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) { if (!phy_is_ulpi(phy)) @@ -803,15 +837,3 @@ void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); } EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable); - -void tegra_usb_phy_close(struct tegra_usb_phy *phy) -{ - if (phy_is_ulpi(phy)) - clk_put(phy->clk); - else - utmip_pad_close(phy); - clk_disable_unprepare(phy->pll_u); - clk_put(phy->pll_u); - kfree(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_close); diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 681da06..072edc1 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -432,17 +432,16 @@ static int usbhs_probe(struct platform_device *pdev) } /* usb private data */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "Could not allocate priv\n"); return -ENOMEM; } - priv->base = ioremap_nocache(res->start, resource_size(res)); + priv->base = devm_request_and_ioremap(&pdev->dev, res); if (!priv->base) { dev_err(&pdev->dev, "ioremap error.\n"); - ret = -ENOMEM; - goto probe_end_kfree; + return -ENOMEM; } /* @@ -485,7 +484,7 @@ static int usbhs_probe(struct platform_device *pdev) /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) - goto probe_end_iounmap; + return ret; ret = usbhs_fifo_probe(priv); if (ret < 0) @@ -546,10 +545,6 @@ probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); -probe_end_iounmap: - iounmap(priv->base); -probe_end_kfree: - kfree(priv); dev_info(&pdev->dev, "probe failed\n"); @@ -576,8 +571,6 @@ static int __devexit usbhs_remove(struct platform_device *pdev) usbhs_mod_remove(priv); usbhs_fifo_remove(priv); usbhs_pipe_remove(priv); - iounmap(priv->base); - kfree(priv); return 0; } diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 82a628f..35c5208 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -209,14 +209,18 @@ int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state) return (int)irq_state->intsts0 & CTSQ_MASK; } -static void usbhs_status_get_each_irq(struct usbhs_priv *priv, - struct usbhs_irq_state *state) +static int usbhs_status_get_each_irq(struct usbhs_priv *priv, + struct usbhs_irq_state *state) { struct usbhs_mod *mod = usbhs_mod_get_current(priv); + u16 intenb0, intenb1; state->intsts0 = usbhs_read(priv, INTSTS0); state->intsts1 = usbhs_read(priv, INTSTS1); + intenb0 = usbhs_read(priv, INTENB0); + intenb1 = usbhs_read(priv, INTENB1); + /* mask */ if (mod) { state->brdysts = usbhs_read(priv, BRDYSTS); @@ -226,6 +230,20 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv, state->bempsts &= mod->irq_bempsts; state->brdysts &= mod->irq_brdysts; } + + /* + * Check whether the irq enable registers and the irq status are set + * when IRQF_SHARED is set. + */ + if (priv->irqflags & IRQF_SHARED) { + if (!(intenb0 & state->intsts0) && + !(intenb1 & state->intsts1) && + !(state->bempsts) && + !(state->brdysts)) + return -EIO; + } + + return 0; } /* @@ -238,7 +256,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) struct usbhs_priv *priv = data; struct usbhs_irq_state irq_state; - usbhs_status_get_each_irq(priv, &irq_state); + if (usbhs_status_get_each_irq(priv, &irq_state) < 0) + return IRQ_NONE; /* * clear interrupt diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 325d291..76f4622 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -42,11 +42,6 @@ config USB_SERIAL_CONSOLE If unsure, say N. -config USB_EZUSB - bool "Functions for loading firmware on EZUSB chips" - help - Say Y here if you need EZUSB device support. - config USB_SERIAL_GENERIC bool "USB Generic Serial Driver" help @@ -94,7 +89,7 @@ config USB_SERIAL_CH341 config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a ConnectTech WhiteHEAT 4 port USB to serial converter device. @@ -281,7 +276,7 @@ config USB_SERIAL_IUU config USB_SERIAL_KEYSPAN_PDA tristate "USB Keyspan PDA Single Port Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a Keyspan PDA single port USB to serial converter device. This driver makes use of firmware @@ -292,7 +287,7 @@ config USB_SERIAL_KEYSPAN_PDA config USB_SERIAL_KEYSPAN tristate "USB Keyspan USA-xxx Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 ---help--- Say Y here if you want to use Keyspan USB to serial converter devices. This driver makes use of Keyspan's official firmware @@ -596,7 +591,7 @@ config USB_SERIAL_CYBERJACK config USB_SERIAL_XIRCOM tristate "USB Xircom / Entregra Single Port Serial Driver" - select USB_EZUSB + select USB_EZUSB_FX2 help Say Y here if you want to use a Xircom or Entregra single port USB to serial converter device. This driver makes use of firmware @@ -660,6 +655,14 @@ config USB_SERIAL_ZIO To compile this driver as a module, choose M here: the module will be called zio. +config USB_SERIAL_ZTE + tristate "ZTE USB serial driver" + help + Say Y here if you want to use a ZTE USB to serial device. + + To compile this driver as a module, choose M here: the + module will be called zte. + config USB_SERIAL_SSU100 tristate "USB Quatech SSU-100 Single Port Serial Driver" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 1dc483a..3b3e730 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_USB_SERIAL) += usbserial.o usbserial-y := usb-serial.o generic.o bus.o usbserial-$(CONFIG_USB_SERIAL_CONSOLE) += console.o -usbserial-$(CONFIG_USB_EZUSB) += ezusb.o obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o @@ -63,3 +62,4 @@ obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o +obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index d634e66..54e1bb6 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -52,8 +52,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static bool debug; - /* Vendor and Product ID */ #define AIRCABLE_VID 0x16CA #define AIRCABLE_USB_PID 0x1502 @@ -196,6 +194,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 3b98fb7..cf2522c 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -37,7 +37,6 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -static bool debug; /* * Version information */ @@ -650,8 +649,7 @@ static void ark3116_read_int_callback(struct urb *urb) /* * Not sure what this data meant... */ - usb_serial_debug_data(debug, &port->dev, - __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); break; @@ -750,9 +748,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug"); - /* * The following describes what I learned from studying the old * ark3116.c driver, disassembling the windows driver, and some lucky diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index a46df73..9944942 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -37,8 +37,6 @@ #include <linux/usb/serial.h> #include "belkin_sa.h" -static bool debug; - /* * Version Information */ @@ -206,8 +204,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); /* Handle known interrupt data */ /* ignore data[0] and data[1] */ @@ -515,6 +512,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index cabd1b1..e9c7046 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -70,8 +70,6 @@ #define CH341_NBREAK_BITS_REG2 0x40 -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x4348, 0x5523) }, { USB_DEVICE(0x1a86, 0x7523) }, @@ -93,8 +91,9 @@ static int ch341_control_out(struct usb_device *dev, u8 request, u16 value, u16 index) { int r; - dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, - (int)request, (int)value, (int)index); + + dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n", + USB_DIR_OUT|0x40, (int)request, (int)value, (int)index); r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, @@ -108,8 +107,10 @@ static int ch341_control_in(struct usb_device *dev, char *buf, unsigned bufsize) { int r; - dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, - (int)request, (int)value, (int)index, buf, (int)bufsize); + + dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n", + USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf, + (int)bufsize); r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, @@ -320,7 +321,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) if (r) goto out; - dbg("%s - submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__); r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (r) { dev_err(&port->dev, "%s - failed submitting interrupt urb," @@ -390,19 +391,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) __func__, r); goto out; } - dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); + dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n", + __func__, break_reg[0], break_reg[1]); if (break_state != 0) { - dbg("%s - Enter break state requested", __func__); + dev_dbg(&port->dev, "%s - Enter break state requested\n", __func__); break_reg[0] &= ~CH341_NBREAK_BITS_REG1; break_reg[1] &= ~CH341_NBREAK_BITS_REG2; } else { - dbg("%s - Leave break state requested", __func__); + dev_dbg(&port->dev, "%s - Leave break state requested\n", __func__); break_reg[0] |= CH341_NBREAK_BITS_REG1; break_reg[1] |= CH341_NBREAK_BITS_REG2; } - dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); + dev_dbg(&port->dev, "%s - New ch341 break register contents - reg1: %x, reg2: %x\n", + __func__, break_reg[0], break_reg[1]); reg_contents = get_unaligned_le16(break_reg); r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, ch341_break_reg, reg_contents); @@ -451,16 +452,16 @@ static void ch341_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", + __func__, urb->status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); if (actual_length >= 4) { @@ -536,15 +537,16 @@ static int ch341_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd); switch (cmd) { case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number); return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); break; } @@ -572,7 +574,7 @@ static int ch341_tiocmget(struct tty_struct *tty) | ((status & CH341_BIT_RI) ? TIOCM_RI : 0) | ((status & CH341_BIT_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } @@ -617,6 +619,3 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 9a56428..5f3bcd3 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> @@ -20,8 +22,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; - struct usbcons_info { int magic; int break_flag; @@ -68,8 +68,6 @@ static int usb_console_setup(struct console *co, char *options) struct tty_struct *tty = NULL; struct ktermios dummy; - dbg("%s", __func__); - if (options) { baud = simple_strtoul(options, NULL, 10); s = options; @@ -113,8 +111,7 @@ static int usb_console_setup(struct console *co, char *options) serial = usb_serial_get_by_index(co->index); if (serial == NULL) { /* no device is connected yet, sorry :( */ - printk(KERN_ERR "No USB device connected to ttyUSB%i\n", - co->index); + pr_err("No USB device connected to ttyUSB%i\n", co->index); return -ENODEV; } @@ -213,10 +210,10 @@ static void usb_console_write(struct console *co, if (count == 0) return; - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); + pr_debug("%s - port %d, %d byte(s)\n", __func__, port->number, count); if (!port->port.console) { - dbg("%s - port not opened", __func__); + pr_debug("%s - port not opened\n", __func__); return; } @@ -237,7 +234,7 @@ static void usb_console_write(struct console *co, retval = serial->type->write(NULL, port, buf, i); else retval = usb_serial_generic_write(NULL, port, buf, i); - dbg("%s - return value : %d", __func__, retval); + pr_debug("%s - return value : %d\n", __func__, retval); if (lf) { /* append CR after LF */ unsigned char cr = 13; @@ -247,7 +244,7 @@ static void usb_console_write(struct console *co, else retval = usb_serial_generic_write(NULL, port, &cr, 1); - dbg("%s - return value : %d", __func__, retval); + pr_debug("%s - return value : %d\n", __func__, retval); } buf += i; count -= i; @@ -284,10 +281,8 @@ void usb_serial_console_disconnect(struct usb_serial *serial) } } -void usb_serial_console_init(int serial_debug, int minor) +void usb_serial_console_init(int minor) { - debug = serial_debug; - if (minor == 0) { /* * Call register_console() if this is the first device plugged @@ -302,7 +297,7 @@ void usb_serial_console_init(int serial_debug, int minor) * register_console). console_write() is called immediately * from register_console iff CON_PRINTBUFFER is set in flags. */ - dbg("registering the USB serial console."); + pr_debug("registering the USB serial console.\n"); register_console(&usbcons); } } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index ba5e07e1..28af5ac 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -52,8 +52,6 @@ static int cp210x_startup(struct usb_serial *); static void cp210x_release(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ @@ -304,9 +302,8 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, kfree(buf); if (result != size) { - dbg("%s - Unable to send config request, " - "request=0x%x size=%d result=%d", - __func__, request, size, result); + dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n", + __func__, request, size, result); if (result > 0) result = -EPROTO; @@ -361,9 +358,8 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, kfree(buf); if ((size > 2 && result != size) || result < 0) { - dbg("%s - Unable to send request, " - "request=0x%x size=%d result=%d", - __func__, request, size, result); + dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n", + __func__, request, size, result); if (result > 0) result = -EPROTO; @@ -487,13 +483,14 @@ static void cp210x_get_termios(struct tty_struct *tty, static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp) { + struct device *dev = &port->dev; unsigned int cflag, modem_ctl[4]; unsigned int baud; unsigned int bits; cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud); *baudp = baud; cflag = *cflagp; @@ -502,31 +499,30 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cflag &= ~CSIZE; switch (bits & BITS_DATA_MASK) { case BITS_DATA_5: - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); cflag |= CS5; break; case BITS_DATA_6: - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); cflag |= CS6; break; case BITS_DATA_7: - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); cflag |= CS7; break; case BITS_DATA_8: - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); cflag |= CS8; break; case BITS_DATA_9: - dbg("%s - data bits = 9 (not supported, using 8 data bits)", - __func__); + dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__); cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; default: - dbg("%s - Unknown number of data bits, using 8", __func__); + dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__); cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; @@ -536,29 +532,29 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, switch (bits & BITS_PARITY_MASK) { case BITS_PARITY_NONE: - dbg("%s - parity = NONE", __func__); + dev_dbg(dev, "%s - parity = NONE\n", __func__); cflag &= ~PARENB; break; case BITS_PARITY_ODD: - dbg("%s - parity = ODD", __func__); + dev_dbg(dev, "%s - parity = ODD\n", __func__); cflag |= (PARENB|PARODD); break; case BITS_PARITY_EVEN: - dbg("%s - parity = EVEN", __func__); + dev_dbg(dev, "%s - parity = EVEN\n", __func__); cflag &= ~PARODD; cflag |= PARENB; break; case BITS_PARITY_MARK: - dbg("%s - parity = MARK", __func__); + dev_dbg(dev, "%s - parity = MARK\n", __func__); cflag |= (PARENB|PARODD|CMSPAR); break; case BITS_PARITY_SPACE: - dbg("%s - parity = SPACE", __func__); + dev_dbg(dev, "%s - parity = SPACE\n", __func__); cflag &= ~PARODD; cflag |= (PARENB|CMSPAR); break; default: - dbg("%s - Unknown parity mode, disabling parity", __func__); + dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__); cflag &= ~PARENB; bits &= ~BITS_PARITY_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); @@ -568,21 +564,19 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cflag &= ~CSTOPB; switch (bits & BITS_STOP_MASK) { case BITS_STOP_1: - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); break; case BITS_STOP_1_5: - dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", - __func__); + dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__); bits &= ~BITS_STOP_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; case BITS_STOP_2: - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); cflag |= CSTOPB; break; default: - dbg("%s - Unknown number of stop bits, using 1 stop bit", - __func__); + dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__); bits &= ~BITS_STOP_MASK; cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; @@ -590,10 +584,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); if (modem_ctl[0] & 0x0008) { - dbg("%s - flow control = CRTSCTS", __func__); + dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); cflag |= CRTSCTS; } else { - dbg("%s - flow control = NONE", __func__); + dev_dbg(dev, "%s - flow control = NONE\n", __func__); cflag &= ~CRTSCTS; } @@ -640,7 +634,7 @@ static void cp210x_change_speed(struct tty_struct *tty, */ baud = cp210x_quantise_baudrate(baud); - dbg("%s - setting baud rate to %u", __func__, baud); + dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, sizeof(baud))) { dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); @@ -656,11 +650,12 @@ static void cp210x_change_speed(struct tty_struct *tty, static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct device *dev = &port->dev; unsigned int cflag, old_cflag; unsigned int bits; unsigned int modem_ctl[4]; - dbg("%s - port %d", __func__, port->number); + dev_dbg(dev, "%s - port %d\n", __func__, port->number); if (!tty) return; @@ -678,34 +673,31 @@ static void cp210x_set_termios(struct tty_struct *tty, switch (cflag & CSIZE) { case CS5: bits |= BITS_DATA_5; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: bits |= BITS_DATA_6; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: bits |= BITS_DATA_7; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; case CS8: bits |= BITS_DATA_8; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; /*case CS9: bits |= BITS_DATA_9; - dbg("%s - data bits = 9", __func__); + dev_dbg(dev, "%s - data bits = 9\n", __func__); break;*/ default: - dbg("cp210x driver does not " - "support the number of bits requested," - " using 8 bit mode"); + dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n"); bits |= BITS_DATA_8; break; } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of data bits requested " - "not supported by device"); + dev_dbg(dev, "Number of data bits requested not supported by device\n"); } if ((cflag & (PARENB|PARODD|CMSPAR)) != @@ -714,25 +706,25 @@ static void cp210x_set_termios(struct tty_struct *tty, bits &= ~BITS_PARITY_MASK; if (cflag & PARENB) { if (cflag & CMSPAR) { - if (cflag & PARODD) { - bits |= BITS_PARITY_MARK; - dbg("%s - parity = MARK", __func__); - } else { - bits |= BITS_PARITY_SPACE; - dbg("%s - parity = SPACE", __func__); - } + if (cflag & PARODD) { + bits |= BITS_PARITY_MARK; + dev_dbg(dev, "%s - parity = MARK\n", __func__); + } else { + bits |= BITS_PARITY_SPACE; + dev_dbg(dev, "%s - parity = SPACE\n", __func__); + } } else { - if (cflag & PARODD) { - bits |= BITS_PARITY_ODD; - dbg("%s - parity = ODD", __func__); - } else { - bits |= BITS_PARITY_EVEN; - dbg("%s - parity = EVEN", __func__); - } + if (cflag & PARODD) { + bits |= BITS_PARITY_ODD; + dev_dbg(dev, "%s - parity = ODD\n", __func__); + } else { + bits |= BITS_PARITY_EVEN; + dev_dbg(dev, "%s - parity = EVEN\n", __func__); + } } } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Parity mode not supported by device"); + dev_dbg(dev, "Parity mode not supported by device\n"); } if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { @@ -740,37 +732,36 @@ static void cp210x_set_termios(struct tty_struct *tty, bits &= ~BITS_STOP_MASK; if (cflag & CSTOPB) { bits |= BITS_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { bits |= BITS_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of stop bits requested " - "not supported by device"); + dev_dbg(dev, "Number of stop bits requested not supported by device\n"); } if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); - dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); + dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", + __func__, modem_ctl[0], modem_ctl[1], + modem_ctl[2], modem_ctl[3]); if (cflag & CRTSCTS) { modem_ctl[0] &= ~0x7B; modem_ctl[0] |= 0x09; modem_ctl[1] = 0x80; - dbg("%s - flow control = CRTSCTS", __func__); + dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); } else { modem_ctl[0] &= ~0x7B; modem_ctl[0] |= 0x01; modem_ctl[1] |= 0x40; - dbg("%s - flow control = NONE", __func__); + dev_dbg(dev, "%s - flow control = NONE\n", __func__); } - dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); + dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", + __func__, modem_ctl[0], modem_ctl[1], + modem_ctl[2], modem_ctl[3]); cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16); } @@ -805,7 +796,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, control |= CONTROL_WRITE_DTR; } - dbg("%s - control = 0x%.4x", __func__, control); + dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control); return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); } @@ -833,7 +824,7 @@ static int cp210x_tiocmget (struct tty_struct *tty) |((control & CONTROL_RING)? TIOCM_RI : 0) |((control & CONTROL_DCD) ? TIOCM_CD : 0); - dbg("%s - control = 0x%.2x", __func__, control); + dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control); return result; } @@ -847,8 +838,8 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __func__, - state == BREAK_OFF ? "off" : "on"); + dev_dbg(&port->dev, "%s - turning break %s\n", __func__, + state == BREAK_OFF ? "off" : "on"); cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); } @@ -865,7 +856,6 @@ static int cp210x_startup(struct usb_serial *serial) if (!port_priv) return -ENOMEM; - memset(port_priv, 0x00, sizeof(*port_priv)); port_priv->bInterfaceNumber = serial->interface->cur_altsetting->desc.bInterfaceNumber; @@ -892,6 +882,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 3aa0b53..2a7aecc 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -43,8 +43,6 @@ #define CYBERJACK_LOCAL_BUF_SIZE 32 -static bool debug; - /* * Version Information */ @@ -136,7 +134,8 @@ static int cyberjack_startup(struct usb_serial *serial) if (result) dev_err(&serial->dev->dev, "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); + dev_dbg(&serial->dev->dev, "%s - usb_submit_urb(int urb)\n", + __func__); } return 0; @@ -167,7 +166,7 @@ static int cyberjack_open(struct tty_struct *tty, unsigned long flags; int result = 0; - dbg("%s - usb_clear_halt", __func__); + dev_dbg(&port->dev, "%s - usb_clear_halt\n", __func__); usb_clear_halt(port->serial->dev, port->write_urb->pipe); priv = usb_get_serial_port_data(port); @@ -192,18 +191,19 @@ static void cyberjack_close(struct usb_serial_port *port) static int cyberjack_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { + struct device *dev = &port->dev; struct cyberjack_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result; int wrexpected; if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(dev, "%s - write request of 0 bytes\n", __func__); return 0; } if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dbg("%s - already writing", __func__); + dev_dbg(dev, "%s - already writing\n", __func__); return 0; } @@ -220,13 +220,12 @@ static int cyberjack_write(struct tty_struct *tty, /* Copy data */ memcpy(priv->wrbuf + priv->wrfilled, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->wrbuf + priv->wrfilled); + usb_serial_debug_data(dev, __func__, count, priv->wrbuf + priv->wrfilled); priv->wrfilled += count; if (priv->wrfilled >= 3) { wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; - dbg("%s - expected data: %d", __func__, wrexpected); + dev_dbg(dev, "%s - expected data: %d\n", __func__, wrexpected); } else wrexpected = sizeof(priv->wrbuf); @@ -234,7 +233,7 @@ static int cyberjack_write(struct tty_struct *tty, /* We have enough data to begin transmission */ int length; - dbg("%s - transmitting data (frame 1)", __func__); + dev_dbg(dev, "%s - transmitting data (frame 1)\n", __func__); length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected; @@ -258,11 +257,11 @@ static int cyberjack_write(struct tty_struct *tty, return 0; } - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); + dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); + dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); if (priv->wrsent >= priv->wrfilled) { - dbg("%s - buffer cleaned", __func__); + dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; @@ -284,6 +283,7 @@ static void cyberjack_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned char *data = urb->transfer_buffer; int status = urb->status; int result; @@ -292,8 +292,7 @@ static void cyberjack_read_int_callback(struct urb *urb) if (status) return; - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(dev, __func__, urb->actual_length, data); /* React only to interrupts signaling a bulk_in transfer */ if (urb->actual_length == 4 && data[0] == 0x01) { @@ -307,7 +306,7 @@ static void cyberjack_read_int_callback(struct urb *urb) old_rdtodo = priv->rdtodo; if (old_rdtodo + size < old_rdtodo) { - dbg("To many bulk_in urbs to do."); + dev_dbg(dev, "To many bulk_in urbs to do.\n"); spin_unlock(&priv->lock); goto resubmit; } @@ -315,17 +314,16 @@ static void cyberjack_read_int_callback(struct urb *urb) /* "+=" is probably more fault tollerant than "=" */ priv->rdtodo += size; - dbg("%s - rdtodo: %d", __func__, priv->rdtodo); + dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); spin_unlock(&priv->lock); if (!old_rdtodo) { result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dev_err(&port->dev, "%s - failed resubmitting " - "read urb, error %d\n", + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); + dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } } @@ -333,30 +331,30 @@ resubmit: result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); + dev_dbg(dev, "%s - usb_submit_urb(int urb)\n", __func__); } static void cyberjack_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; short todo; int result; int status = urb->status; - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dev_dbg(dev, "%s - nonzero read bulk status received: %d\n", + __func__, status); return; } tty = tty_port_tty_get(&port->port); if (!tty) { - dbg("%s - ignoring since device not open", __func__); + dev_dbg(dev, "%s - ignoring since device not open\n", __func__); return; } if (urb->actual_length) { @@ -376,15 +374,15 @@ static void cyberjack_read_bulk_callback(struct urb *urb) spin_unlock(&priv->lock); - dbg("%s - rdtodo: %d", __func__, todo); + dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); /* Continue to read if we have still urbs to do. */ if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - dev_err(&port->dev, "%s - failed resubmitting read " - "urb, error %d\n", __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", + __func__, result); + dev_dbg(dev, "%s - usb_submit_urb(read urb)\n", __func__); } } @@ -392,12 +390,13 @@ static void cyberjack_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; int status = urb->status; set_bit(0, &port->write_urbs_free); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } @@ -407,7 +406,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) if (priv->wrfilled) { int length, blksize, result; - dbg("%s - transmitting data (frame n)", __func__); + dev_dbg(dev, "%s - transmitting data (frame n)\n", __func__); length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? port->bulk_out_size : (priv->wrfilled - priv->wrsent); @@ -422,8 +421,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", + dev_err(dev, "%s - failed submitting write urb, error %d\n", __func__, result); /* Throw away data. No better idea what to do with it. */ priv->wrfilled = 0; @@ -431,14 +429,14 @@ static void cyberjack_write_bulk_callback(struct urb *urb) goto exit; } - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); + dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent); + dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled); blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; if (priv->wrsent >= priv->wrfilled || priv->wrsent >= blksize) { - dbg("%s - buffer cleaned", __func__); + dev_dbg(dev, "%s - buffer cleaned\n", __func__); memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); priv->wrfilled = 0; priv->wrsent = 0; @@ -456,6 +454,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index be34f15..1befce2 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -46,7 +46,6 @@ #include "cypress_m8.h" -static bool debug; static bool stats; static int interval; static bool unstable_bauds; @@ -263,8 +262,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) * safest speed for a part like that. */ if (new_rate > 4800) { - dbg("%s - failed setting baud rate, device incapable " - "speed %d", __func__, new_rate); + dev_dbg(&port->dev, + "%s - failed setting baud rate, device incapable speed %d\n", + __func__, new_rate); return -1; } } @@ -274,8 +274,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) /* 300 and 600 baud rates are supported under * the generic firmware, but are not used with * NMEA and SiRF protocols */ - dbg("%s - failed setting baud rate, unsupported speed " - "of %d on Earthmate GPS", __func__, new_rate); + dev_dbg(&port->dev, + "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS", + __func__, new_rate); return -1; } break; @@ -294,6 +295,7 @@ static int cypress_serial_control(struct tty_struct *tty, { int new_baudrate = 0, retval = 0, tries = 0; struct cypress_private *priv; + struct device *dev = &port->dev; u8 *feature_buffer; const unsigned int feature_len = 5; unsigned long flags; @@ -312,16 +314,16 @@ static int cypress_serial_control(struct tty_struct *tty, /* 0 means 'Hang up' so doesn't change the true bit rate */ new_baudrate = priv->baud_rate; if (baud_rate && baud_rate != priv->baud_rate) { - dbg("%s - baud rate is changing", __func__); + dev_dbg(dev, "%s - baud rate is changing\n", __func__); retval = analyze_baud_rate(port, baud_rate); if (retval >= 0) { new_baudrate = retval; - dbg("%s - New baud rate set to %d", - __func__, new_baudrate); + dev_dbg(dev, "%s - New baud rate set to %d\n", + __func__, new_baudrate); } } - dbg("%s - baud rate is being sent as %d", - __func__, new_baudrate); + dev_dbg(dev, "%s - baud rate is being sent as %d\n", __func__, + new_baudrate); /* fill the feature_buffer with new configuration */ put_unaligned_le32(new_baudrate, feature_buffer); @@ -333,9 +335,8 @@ static int cypress_serial_control(struct tty_struct *tty, /* 1 bit gap */ feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */ - dbg("%s - device is being sent this feature report:", - __func__); - dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, + dev_dbg(dev, "%s - device is being sent this feature report:\n", __func__); + dev_dbg(dev, "%s - %02X - %02X - %02X - %02X - %02X\n", __func__, feature_buffer[0], feature_buffer[1], feature_buffer[2], feature_buffer[3], feature_buffer[4]); @@ -355,8 +356,8 @@ static int cypress_serial_control(struct tty_struct *tty, retval != -ENODEV); if (retval != feature_len) { - dev_err(&port->dev, "%s - failed sending serial " - "line settings - %d\n", __func__, retval); + dev_err(dev, "%s - failed sending serial line settings - %d\n", + __func__, retval); cypress_set_dead(port); } else { spin_lock_irqsave(&priv->lock, flags); @@ -377,7 +378,7 @@ static int cypress_serial_control(struct tty_struct *tty, retval = -ENOTTY; goto out; } - dbg("%s - retreiving serial line settings", __func__); + dev_dbg(dev, "%s - retreiving serial line settings\n", __func__); do { retval = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), @@ -392,8 +393,8 @@ static int cypress_serial_control(struct tty_struct *tty, && retval != -ENODEV); if (retval != feature_len) { - dev_err(&port->dev, "%s - failed to retrieve serial " - "line settings - %d\n", __func__, retval); + dev_err(dev, "%s - failed to retrieve serial line settings - %d\n", + __func__, retval); cypress_set_dead(port); goto out; } else { @@ -474,14 +475,14 @@ static int generic_startup(struct usb_serial *serial) if (interval > 0) { priv->write_urb_interval = interval; priv->read_urb_interval = interval; - dbg("%s - port %d read & write intervals forced to %d", - __func__, port->number, interval); + dev_dbg(&port->dev, "%s - read & write intervals forced to %d\n", + __func__, interval); } else { priv->write_urb_interval = port->interrupt_out_urb->interval; priv->read_urb_interval = port->interrupt_in_urb->interval; - dbg("%s - port %d intervals: read=%d write=%d", - __func__, port->number, - priv->read_urb_interval, priv->write_urb_interval); + dev_dbg(&port->dev, "%s - intervals: read=%d write=%d\n", + __func__, priv->read_urb_interval, + priv->write_urb_interval); } usb_set_serial_port_data(port, priv); @@ -495,8 +496,7 @@ static int cypress_earthmate_startup(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - port->number); + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); return 1; } @@ -511,8 +511,9 @@ static int cypress_earthmate_startup(struct usb_serial *serial) handle GET_CONFIG requests; everything they've produced since that time crashes if this command is attempted :-( */ - dbg("%s - Marking this device as unsafe for GET_CONFIG " - "commands", __func__); + dev_dbg(&port->dev, + "%s - Marking this device as unsafe for GET_CONFIG commands\n", + __func__); priv->get_cfg_unsafe = !0; } @@ -523,14 +524,14 @@ static int cypress_earthmate_startup(struct usb_serial *serial) static int cypress_hidcom_startup(struct usb_serial *serial) { struct cypress_private *priv; + struct usb_serial_port *port = serial->port[0]; if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); return 1; } - priv = usb_get_serial_port_data(serial->port[0]); + priv = usb_get_serial_port_data(port); priv->chiptype = CT_CYPHIDCOM; return 0; @@ -540,14 +541,14 @@ static int cypress_hidcom_startup(struct usb_serial *serial) static int cypress_ca42v2_startup(struct usb_serial *serial) { struct cypress_private *priv; + struct usb_serial_port *port = serial->port[0]; if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); + dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); return 1; } - priv = usb_get_serial_port_data(serial->port[0]); + priv = usb_get_serial_port_data(port); priv->chiptype = CT_CA42V2; return 0; @@ -649,7 +650,7 @@ static void cypress_close(struct usb_serial_port *port) kfifo_reset_out(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - stopping urbs", __func__); + dev_dbg(&port->dev, "%s - stopping urbs\n", __func__); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); @@ -665,7 +666,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, { struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d, %d bytes", __func__, port->number, count); + dev_dbg(&port->dev, "%s - port %d, %d bytes\n", __func__, port->number, count); /* line control commands, which need to be executed immediately, are not put into the buffer for obvious reasons. @@ -691,17 +692,18 @@ static void cypress_send(struct usb_serial_port *port) { int count = 0, result, offset, actual_size; struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned long flags; if (!priv->comm_is_ok) return; - dbg("%s - interrupt out size is %d", __func__, - port->interrupt_out_size); + dev_dbg(dev, "%s - interrupt out size is %d\n", __func__, + port->interrupt_out_size); spin_lock_irqsave(&priv->lock, flags); if (priv->write_urb_in_use) { - dbg("%s - can't write, urb in use", __func__); + dev_dbg(dev, "%s - can't write, urb in use\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); return; } @@ -731,7 +733,7 @@ static void cypress_send(struct usb_serial_port *port) if (priv->cmd_ctrl) { priv->cmd_count++; - dbg("%s - line control command being issued", __func__); + dev_dbg(dev, "%s - line control command being issued\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto send; } else @@ -753,7 +755,7 @@ static void cypress_send(struct usb_serial_port *port) port->interrupt_out_buffer[0] |= count; } - dbg("%s - count is %d", __func__, count); + dev_dbg(dev, "%s - count is %d\n", __func__, count); send: spin_lock_irqsave(&priv->lock, flags); @@ -766,9 +768,8 @@ send: actual_size = count + (priv->pkt_fmt == packet_format_1 ? 2 : 1); - usb_serial_debug_data(debug, &port->dev, __func__, - port->interrupt_out_size, - port->interrupt_out_urb->transfer_buffer); + usb_serial_debug_data(dev, __func__, port->interrupt_out_size, + port->interrupt_out_urb->transfer_buffer); usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), @@ -807,7 +808,7 @@ static int cypress_write_room(struct tty_struct *tty) room = kfifo_avail(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -832,7 +833,7 @@ static int cypress_tiocmget(struct tty_struct *tty) | ((status & UART_RI) ? TIOCM_RI : 0) | ((status & UART_CD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } @@ -867,7 +868,7 @@ static int cypress_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd); switch (cmd) { /* This code comes from drivers/char/serial.c and ftdi_sio.c */ @@ -902,7 +903,7 @@ static int cypress_ioctl(struct tty_struct *tty, default: break; } - dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd); + dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd); return -ENOIOCTLCMD; } /* cypress_ioctl */ @@ -911,6 +912,7 @@ static void cypress_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; int data_bits, stop_bits, parity_type, parity_enable; unsigned cflag, iflag; unsigned long flags; @@ -984,23 +986,21 @@ static void cypress_set_termios(struct tty_struct *tty, data_bits = 3; break; default: - dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n", - __func__); + dev_err(dev, "%s - CSIZE was set, but not CS5-CS8\n", __func__); data_bits = 3; } spin_lock_irqsave(&priv->lock, flags); oldlines = priv->line_control; if ((cflag & CBAUD) == B0) { /* drop dtr and rts */ - dbg("%s - dropping the lines, baud rate 0bps", __func__); + dev_dbg(dev, "%s - dropping the lines, baud rate 0bps\n", __func__); priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); } else priv->line_control = (CONTROL_DTR | CONTROL_RTS); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " - "%d data_bits (+5)", __func__, stop_bits, - parity_enable, parity_type, data_bits); + dev_dbg(dev, "%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)\n", + __func__, stop_bits, parity_enable, parity_type, data_bits); cypress_serial_control(tty, port, tty_get_baud_rate(tty), data_bits, stop_bits, @@ -1017,8 +1017,7 @@ static void cypress_set_termios(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) { - dbg("Using custom termios settings for a baud rate of " - "4800bps."); + dev_dbg(dev, "Using custom termios settings for a baud rate of 4800bps.\n"); /* define custom termios settings for NMEA protocol */ tty->termios.c_iflag /* input modes - */ @@ -1067,7 +1066,7 @@ static int cypress_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1112,6 +1111,7 @@ static void cypress_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &urb->dev->dev; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; @@ -1135,16 +1135,15 @@ static void cypress_read_int_callback(struct urb *urb) /* FALLS THROUGH */ default: /* something ugly is going on... */ - dev_err(&urb->dev->dev, - "%s - unexpected nonzero read status received: %d\n", - __func__, status); + dev_err(dev, "%s - unexpected nonzero read status received: %d\n", + __func__, status); cypress_set_dead(port); return; } spin_lock_irqsave(&priv->lock, flags); if (priv->rx_flags & THROTTLED) { - dbg("%s - now throttling", __func__); + dev_dbg(dev, "%s - now throttling\n", __func__); priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock_irqrestore(&priv->lock, flags); return; @@ -1153,7 +1152,7 @@ static void cypress_read_int_callback(struct urb *urb) tty = tty_port_tty_get(&port->port); if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); + dev_dbg(dev, "%s - bad tty pointer - exiting\n", __func__); return; } @@ -1180,13 +1179,13 @@ static void cypress_read_int_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); if (result < bytes) { - dbg("%s - wrong packet size - received %d bytes but packet " - "said %d bytes", __func__, result, bytes); + dev_dbg(dev, + "%s - wrong packet size - received %d bytes but packet said %d bytes\n", + __func__, result, bytes); goto continue_read; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); spin_lock_irqsave(&priv->lock, flags); /* check to see if status has changed */ @@ -1202,7 +1201,7 @@ static void cypress_read_int_callback(struct urb *urb) * though */ if (tty && !(tty->termios.c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) { - dbg("%s - calling hangup", __func__); + dev_dbg(dev, "%s - calling hangup\n", __func__); tty_hangup(tty); goto continue_read; } @@ -1215,7 +1214,7 @@ static void cypress_read_int_callback(struct urb *urb) if (priv->current_status & CYP_ERROR) { spin_unlock_irqrestore(&priv->lock, flags); tty_flag = TTY_PARITY; - dbg("%s - Parity Error detected", __func__); + dev_dbg(dev, "%s - Parity Error detected\n", __func__); } else spin_unlock_irqrestore(&priv->lock, flags); @@ -1246,9 +1245,8 @@ continue_read: priv->read_urb_interval); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result && result != -EPERM) { - dev_err(&urb->dev->dev, "%s - failed resubmitting " - "read urb, error %d\n", __func__, - result); + dev_err(dev, "%s - failed resubmitting read urb, error %d\n", + __func__, result); cypress_set_dead(port); } } @@ -1259,6 +1257,7 @@ static void cypress_write_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); + struct device *dev = &urb->dev->dev; int result; int status = urb->status; @@ -1270,8 +1269,8 @@ static void cypress_write_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", + __func__, status); priv->write_urb_in_use = 0; return; case -EPIPE: /* no break needed; clear halt and resubmit */ @@ -1279,21 +1278,19 @@ static void cypress_write_int_callback(struct urb *urb) break; usb_clear_halt(port->serial->dev, 0x02); /* error in the urb, so we have to resubmit it */ - dbg("%s - nonzero write bulk status received: %d", + dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", __func__, status); port->interrupt_out_urb->transfer_buffer_length = 1; result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (!result) return; - dev_err(&urb->dev->dev, - "%s - failed resubmitting write urb, error %d\n", - __func__, result); + dev_err(dev, "%s - failed resubmitting write urb, error %d\n", + __func__, result); cypress_set_dead(port); break; default: - dev_err(&urb->dev->dev, - "%s - unexpected nonzero write status received: %d\n", - __func__, status); + dev_err(dev, "%s - unexpected nonzero write status received: %d\n", + __func__, status); cypress_set_dead(port); break; } @@ -1310,8 +1307,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(stats, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(stats, "Enable statistics or not"); module_param(interval, int, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index afd9d2e..c86f68c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -249,10 +249,6 @@ static int digi_read_inb_callback(struct urb *urb); static int digi_read_oob_callback(struct urb *urb); -/* Statics */ - -static bool debug; - static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, @@ -404,14 +400,15 @@ static void digi_wakeup_write(struct usb_serial_port *port) static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible) { - int ret = 0; int len; struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); unsigned long flags = 0; - dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count); + dev_dbg(&port->dev, + "digi_write_oob_command: TOP: port=%d, count=%d\n", + oob_priv->dp_port_num, count); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); while (count > 0) { @@ -467,7 +464,7 @@ static int digi_write_inb_command(struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write_inb_command: TOP: port=%d, count=%d", + dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n", priv->dp_port_num, count); if (timeout) @@ -549,7 +546,8 @@ static int digi_set_modem_signals(struct usb_serial_port *port, unsigned long flags = 0; - dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", + dev_dbg(&port->dev, + "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n", port_priv->dp_port_num, modem_signals); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); @@ -687,6 +685,7 @@ static void digi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct digi_port *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned int iflag = tty->termios.c_iflag; unsigned int cflag = tty->termios.c_cflag; unsigned int old_iflag = old_termios->c_iflag; @@ -697,7 +696,9 @@ static void digi_set_termios(struct tty_struct *tty, int i = 0; speed_t baud; - dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); + dev_dbg(dev, + "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x\n", + priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); /* set baud rate */ baud = tty_get_baud_rate(tty); @@ -773,7 +774,8 @@ static void digi_set_termios(struct tty_struct *tty, case CS7: arg = DIGI_WORD_SIZE_7; break; case CS8: arg = DIGI_WORD_SIZE_8; break; default: - dbg("digi_set_termios: can't handle word size %d", + dev_dbg(dev, + "digi_set_termios: can't handle word size %d\n", (cflag&CSIZE)); break; } @@ -866,7 +868,7 @@ static void digi_set_termios(struct tty_struct *tty, } ret = digi_write_oob_command(port, buf, i, 1); if (ret != 0) - dbg("digi_set_termios: write oob failed, ret=%d", ret); + dev_dbg(dev, "digi_set_termios: write oob failed, ret=%d\n", ret); tty_encode_baud_rate(tty, baud, baud); } @@ -922,7 +924,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld", + dev_dbg(&port->dev, + "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n", priv->dp_port_num, count, in_interrupt()); /* copy user data (which can sleep) before getting spin lock */ @@ -981,7 +984,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, dev_err_console(port, "%s: usb_submit_urb failed, ret=%d, port=%d\n", __func__, ret, priv->dp_port_num); - dbg("digi_write: returning %d", ret); + dev_dbg(&port->dev, "digi_write: returning %d\n", ret); return ret; } @@ -1012,7 +1015,7 @@ static void digi_write_bulk_callback(struct urb *urb) /* handle oob callback */ if (priv->dp_port_num == serial_priv->ds_oob_port_num) { - dbg("digi_write_bulk_callback: oob callback"); + dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); spin_lock(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; wake_up_interruptible(&port->write_wait); @@ -1066,7 +1069,7 @@ static int digi_write_room(struct tty_struct *tty) room = port->bulk_out_size - 2 - priv->dp_out_buf_len; spin_unlock_irqrestore(&priv->dp_port_lock, flags); - dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room); + dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room); return room; } @@ -1077,12 +1080,12 @@ static int digi_chars_in_buffer(struct tty_struct *tty) struct digi_port *priv = usb_get_serial_port_data(port); if (priv->dp_write_urb_in_use) { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, port->bulk_out_size - 2); /* return(port->bulk_out_size - 2); */ return 256; } else { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, priv->dp_out_buf_len); return priv->dp_out_buf_len; } @@ -1120,7 +1123,7 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) ret = digi_write_oob_command(port, buf, 8, 1); if (ret != 0) - dbg("digi_open: write oob failed, ret=%d", ret); + dev_dbg(&port->dev, "digi_open: write oob failed, ret=%d\n", ret); /* set termios settings */ if (tty) { @@ -1180,7 +1183,7 @@ static void digi_close(struct usb_serial_port *port) ret = digi_write_oob_command(port, buf, 20, 0); if (ret != 0) - dbg("digi_close: write oob failed, ret=%d", ret); + dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret); /* wait for final commands on oob port to complete */ prepare_to_wait(&priv->dp_flush_wait, &wait, @@ -1448,9 +1451,9 @@ static int digi_read_inb_callback(struct urb *urb) tty_kref_put(tty); if (opcode == DIGI_CMD_RECEIVE_DISABLE) - dbg("%s: got RECEIVE_DISABLE", __func__); + dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__); else if (opcode != DIGI_CMD_RECEIVE_DATA) - dbg("%s: unknown opcode: %d", __func__, opcode); + dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode); return throttled ? 1 : 0; @@ -1484,7 +1487,7 @@ static int digi_read_oob_callback(struct urb *urb) status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; - dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", + dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); if (status != 0 || line >= serial->type->num_ports) @@ -1552,6 +1555,3 @@ module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 34e8638..43ede4a 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -28,8 +28,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static bool debug; - /* * Version Information */ @@ -134,6 +132,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c deleted file mode 100644 index 800e8eb..0000000 --- a/drivers/usb/serial/ezusb.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * EZ-USB specific functions used by some of the USB to Serial drivers. - * - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define CPUCS_REG 0x7F92 - -int ezusb_writememory(struct usb_serial *serial, int address, - unsigned char *data, int length, __u8 request) -{ - int result; - unsigned char *transfer_buffer; - - if (!serial->dev) { - printk(KERN_ERR "ezusb: %s - no physical device present, " - "failing.\n", __func__); - return -ENODEV; - } - - transfer_buffer = kmemdup(data, length, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, length); - return -ENOMEM; - } - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, 0x40, address, 0, transfer_buffer, length, 3000); - kfree(transfer_buffer); - return result; -} -EXPORT_SYMBOL_GPL(ezusb_writememory); - -int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit) -{ - int response; - - response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) - dev_err(&serial->dev->dev, "%s- %d failed\n", - __func__, reset_bit); - return response; -} -EXPORT_SYMBOL_GPL(ezusb_set_reset); - diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 79451ee..2444771 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -25,8 +25,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1934, 0x0706) }, { } /* Terminating entry */ @@ -85,7 +83,7 @@ static void f81232_read_int_callback(struct urb *urb) goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); f81232_update_line_status(port, data, actual_length); @@ -389,7 +387,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org"); MODULE_LICENSE("GPL v2"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0c8d1c2..be84587 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -48,14 +48,9 @@ #include "ftdi_sio.h" #include "ftdi_sio_ids.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.6.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" -static bool debug; static __u16 vendor = FTDI_VID; static __u16 product; @@ -584,6 +579,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, /* * ELV devices: */ @@ -1063,11 +1060,12 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear) { struct ftdi_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned urb_value; int rv; if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); + dev_dbg(dev, "%s - DTR|RTS not being set|cleared\n", __func__); return 0; /* no change */ } @@ -1088,18 +1086,14 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, urb_value, priv->interface, NULL, 0, WDR_TIMEOUT); if (rv < 0) { - dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", - __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n", + __func__, + (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); } else { - dbg("%s - DTR %s, RTS %s", __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, + (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", + (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); /* FIXME: locking on last_dtr_rts */ priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set; } @@ -1111,6 +1105,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; __u32 div_value = 0; int div_okay = 1; int baud; @@ -1146,7 +1141,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, alt_speed hack */ baud = tty_get_baud_rate(tty); - dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud); + dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud); /* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */ @@ -1155,8 +1150,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && (priv->custom_divisor)) { baud = priv->baud_base / priv->custom_divisor; - dbg("%s - custom divisor %d sets baud rate to %d", - __func__, priv->custom_divisor, baud); + dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n", + __func__, priv->custom_divisor, baud); } /* 3. Convert baudrate to device-specific divisor */ @@ -1178,8 +1173,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, case 115200: div_value = ftdi_sio_b115200; break; } /* baud */ if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", - __func__, baud); + dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", + __func__, baud); div_value = ftdi_sio_b9600; baud = 9600; div_okay = 0; @@ -1189,7 +1184,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, if (baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); baud = 9600; div_value = ftdi_232am_baud_to_divisor(9600); div_okay = 0; @@ -1212,7 +1207,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, } div_value = ftdi_232bm_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); div_value = ftdi_232bm_baud_to_divisor(9600); div_okay = 0; baud = 9600; @@ -1226,7 +1221,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, } else if (baud < 1200) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { - dbg("%s - Baud rate too high!", __func__); + dev_dbg(dev, "%s - Baud rate too high!\n", __func__); div_value = ftdi_232bm_baud_to_divisor(9600); div_okay = 0; baud = 9600; @@ -1235,7 +1230,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, } /* priv->chip_type */ if (div_okay) { - dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s", + dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n", __func__, baud, (unsigned long)div_value, ftdi_chip_name[priv->chip_type]); } @@ -1281,7 +1276,7 @@ static int write_latency_timer(struct usb_serial_port *port) if (priv->flags & ASYNC_LOW_LATENCY) l = 1; - dbg("%s: setting latency timer = %i", __func__, l); + dev_dbg(&port->dev, "%s: setting latency timer = %i\n", __func__, l); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1436,8 +1431,8 @@ static void ftdi_determine_type(struct usb_serial_port *port) version = le16_to_cpu(udev->descriptor.bcdDevice); interfaces = udev->actconfig->desc.bNumInterfaces; - dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__, - version, interfaces); + dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__, + version, interfaces); if (interfaces > 1) { int inter; @@ -1467,8 +1462,9 @@ static void ftdi_determine_type(struct usb_serial_port *port) /* BM-type devices have a bug where bcdDevice gets set * to 0x200 when iSerialNumber is 0. */ if (version < 0x500) { - dbg("%s: something fishy - bcdDevice too low for multi-interface device", - __func__); + dev_dbg(&port->dev, + "%s: something fishy - bcdDevice too low for multi-interface device\n", + __func__); } } else if (version < 0x200) { /* Old device. Assume it's the original SIO. */ @@ -1582,7 +1578,7 @@ static ssize_t store_event_char(struct device *dev, int v = simple_strtoul(valbuf, NULL, 10); int rv; - dbg("%s: setting event char = %i", __func__, v); + dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1591,7 +1587,7 @@ static ssize_t store_event_char(struct device *dev, v, priv->interface, NULL, 0, WDR_TIMEOUT); if (rv < 0) { - dbg("Unable to write event character: %i", rv); + dev_dbg(&port->dev, "Unable to write event character: %i\n", rv); return -EIO; } @@ -1610,7 +1606,7 @@ static int create_sysfs_attrs(struct usb_serial_port *port) /* XXX I've no idea if the original SIO supports the event_char * sysfs parameter, so I'm playing it safe. */ if (priv->chip_type != SIO) { - dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]); + dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]); retval = device_create_file(&port->dev, &dev_attr_event_char); if ((!retval) && (priv->chip_type == FT232BM || @@ -1750,8 +1746,8 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial) if (latency > 99) latency = 99; - dbg("%s setting NDI device latency to %d", __func__, latency); - dev_info(&udev->dev, "NDI device with a latency value of %d", latency); + dev_dbg(&udev->dev, "%s setting NDI device latency to %d\n", __func__, latency); + dev_info(&udev->dev, "NDI device with a latency value of %d\n", latency); /* FIXME: errors are not returned */ usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -1969,7 +1965,7 @@ static int ftdi_process_packet(struct tty_struct *tty, char *ch; if (len < 2) { - dbg("malformed packet"); + dev_dbg(&port->dev, "malformed packet\n"); return 0; } @@ -2084,12 +2080,12 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to enable/disable break state " - "(state was %d)\n", __func__, break_state); + dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n", + __func__, break_state); } - dbg("%s break state is %d - urb is %d", __func__, - break_state, urb_value); + dev_dbg(&port->dev, "%s break state is %d - urb is %d\n", __func__, + break_state, urb_value); } @@ -2101,6 +2097,7 @@ static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; + struct device *ddev = &port->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; @@ -2114,20 +2111,20 @@ static void ftdi_set_termios(struct tty_struct *tty, /* Force baud rate if this device requires it, unless it is set to B0. */ if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) { - dbg("%s: forcing baud rate for this device", __func__); + dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__); tty_encode_baud_rate(tty, priv->force_baud, priv->force_baud); } /* Force RTS-CTS if this device requires it. */ if (priv->force_rtscts) { - dbg("%s: forcing rtscts for this device", __func__); + dev_dbg(ddev, "%s: forcing rtscts for this device\n", __func__); termios->c_cflag |= CRTSCTS; } cflag = termios->c_cflag; - if (old_termios == 0) + if (!old_termios) goto no_skip; if (old_termios->c_cflag == termios->c_cflag @@ -2163,10 +2160,16 @@ no_skip: } if (cflag & CSIZE) { switch (cflag & CSIZE) { - case CS7: urb_value |= 7; dbg("Setting CS7"); break; - case CS8: urb_value |= 8; dbg("Setting CS8"); break; + case CS7: + urb_value |= 7; + dev_dbg(ddev, "Setting CS7\n"); + break; + case CS8: + urb_value |= 8; + dev_dbg(ddev, "Setting CS8\n"); + break; default: - dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n"); + dev_err(ddev, "CSIZE was set but not CS7-CS8\n"); } } @@ -2179,8 +2182,8 @@ no_skip: FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, NULL, 0, WDR_SHORT_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to set " - "databits/stopbits/parity\n", __func__); + dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n", + __func__); } /* Now do the baudrate */ @@ -2192,8 +2195,7 @@ no_data_parity_stop_changes: FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "%s error from disable flowcontrol urb\n", + dev_err(ddev, "%s error from disable flowcontrol urb\n", __func__); } /* Drop RTS and DTR */ @@ -2202,8 +2204,7 @@ no_data_parity_stop_changes: /* set the baudrate determined before */ mutex_lock(&priv->cfg_lock); if (change_speed(tty, port)) - dev_err(&port->dev, "%s urb failed to set baudrate\n", - __func__); + dev_err(ddev, "%s urb failed to set baudrate\n", __func__); mutex_unlock(&priv->cfg_lock); /* Ensure RTS and DTR are raised when baudrate changed from 0 */ if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) @@ -2214,17 +2215,15 @@ no_data_parity_stop_changes: /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ no_c_cflag_changes: if (cflag & CRTSCTS) { - dbg("%s Setting to CRTSCTS flow control", __func__); + dev_dbg(ddev, "%s Setting to CRTSCTS flow control\n", __func__); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to set to rts/cts flow control\n"); + dev_err(ddev, "urb failed to set to rts/cts flow control\n"); } - } else { /* * Xon/Xoff code @@ -2234,8 +2233,8 @@ no_c_cflag_changes: * code is executed. */ if (iflag & IXOFF) { - dbg("%s request to enable xonxoff iflag=%04x", - __func__, iflag); + dev_dbg(ddev, "%s request to enable xonxoff iflag=%04x\n", + __func__, iflag); /* Try to enable the XON/XOFF on the ftdi_sio * Set the vstart and vstop -- could have been done up * above where a lot of other dereferencing is done but @@ -2260,18 +2259,16 @@ no_c_cflag_changes: /* else clause to only run if cflag ! CRTSCTS and iflag * ! XOFF. CHECKME Assuming XON/XOFF handled by tty * stack - not by device */ - dbg("%s Turning off hardware flow control", __func__); + dev_dbg(ddev, "%s Turning off hardware flow control\n", __func__); if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to clear flow control\n"); + dev_err(ddev, "urb failed to clear flow control\n"); } } - } } @@ -2365,7 +2362,7 @@ static int ftdi_ioctl(struct tty_struct *tty, struct async_icount cnow; struct async_icount cprev; - dbg("%s cmd 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); /* Based on code from acm.c and others */ switch (cmd) { @@ -2413,14 +2410,13 @@ static int ftdi_ioctl(struct tty_struct *tty, /* This is not necessarily an error - turns out the higher layers * will do some ioctls themselves (see comment above) */ - dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd); + dev_dbg(&port->dev, "%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h\n", + __func__, cmd); return -ENOIOCTLCMD; } static int __init ftdi_init(void) { - int retval; - if (vendor > 0 && product > 0) { /* Add user specified VID/PID to reserved element of table. */ int i; @@ -2430,11 +2426,7 @@ static int __init ftdi_init(void) id_table_combined[i].idVendor = vendor; id_table_combined[i].idProduct = product; } - retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined); } static void __exit ftdi_exit(void) @@ -2450,8 +2442,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" __MODULE_STRING(FTDI_VID)")"); diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 41fe582..57c12ef 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -517,6 +517,11 @@ */ #define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ /********************************/ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 2357079..9362f8f 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -16,8 +16,6 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1404, 0xcddc) }, { }, @@ -40,6 +38,3 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 346c15a..3ee9264 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -41,9 +41,6 @@ /* the mode to be set when the port ist opened */ static int initial_mode = 1; -/* debug flag */ -static bool debug; - #define GARMIN_VENDOR_ID 0x091E /* @@ -258,10 +255,7 @@ static void send_to_tty(struct usb_serial_port *port, struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty && actual_length) { - - usb_serial_debug_data(debug, &port->dev, - __func__, actual_length, data); - + usb_serial_debug_data(&port->dev, __func__, actual_length, data); tty_insert_flip_string(tty, data, actual_length); tty_flip_buffer_push(tty); } @@ -303,8 +297,9 @@ static int pkt_add(struct garmin_data *garmin_data_p, state = garmin_data_p->state; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - dbg("%s - added: pkt: %d - %d bytes", - __func__, pkt->seq, data_length); + dev_dbg(&garmin_data_p->port->dev, + "%s - added: pkt: %d - %d bytes\n", __func__, + pkt->seq, data_length); /* in serial mode, if someone is waiting for data from the device, convert and send the next packet to tty. */ @@ -359,7 +354,8 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) __u8 *ptr = pkt; unsigned l = 0; - dbg("%s - pkt-id: 0x%X.", __func__, 0xFF & pkt_id); + dev_dbg(&garmin_data_p->port->dev, "%s - pkt-id: 0x%X.\n", __func__, + 0xFF & pkt_id); *ptr++ = DLE; *ptr++ = ACK; @@ -399,20 +395,20 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) */ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) { + struct device *dev = &garmin_data_p->port->dev; unsigned long flags; const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; - int cksum = 0; int n = 0; int pktid = recpkt[0]; int size = recpkt[1]; - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, count-GSP_INITIAL_OFFSET, recpkt); + usb_serial_debug_data(&garmin_data_p->port->dev, __func__, + count-GSP_INITIAL_OFFSET, recpkt); if (size != (count-GSP_INITIAL_OFFSET-3)) { - dbg("%s - invalid size, expected %d bytes, got %d", + dev_dbg(dev, "%s - invalid size, expected %d bytes, got %d\n", __func__, size, (count-GSP_INITIAL_OFFSET-3)); return -EINVPKT; } @@ -422,8 +418,8 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) /* sanity check, remove after test ... */ if ((__u8 *)&(usbdata[3]) != recpkt) { - dbg("%s - ptr mismatch %p - %p", - __func__, &(usbdata[4]), recpkt); + dev_dbg(dev, "%s - ptr mismatch %p - %p\n", __func__, + &(usbdata[4]), recpkt); return -EINVPKT; } @@ -433,7 +429,7 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) } if ((0xff & (cksum + *recpkt)) != 0) { - dbg("%s - invalid checksum, expected %02x, got %02x", + dev_dbg(dev, "%s - invalid checksum, expected %02x, got %02x\n", __func__, 0xff & -cksum, 0xff & *recpkt); return -EINVPKT; } @@ -480,6 +476,7 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) static int gsp_receive(struct garmin_data *garmin_data_p, const unsigned char *buf, int count) { + struct device *dev = &garmin_data_p->port->dev; unsigned long flags; int offs = 0; int ack_or_nak_seen = 0; @@ -500,7 +497,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, skip = garmin_data_p->flags & FLAGS_GSP_SKIP; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - /* dbg("%s - dle=%d skip=%d size=%d count=%d", + /* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n", __func__, dleSeen, skip, size, count); */ if (size == 0) @@ -530,12 +527,12 @@ static int gsp_receive(struct garmin_data *garmin_data_p, if (data == ACK) { ack_or_nak_seen = ACK; - dbg("ACK packet complete."); + dev_dbg(dev, "ACK packet complete.\n"); } else if (data == NAK) { ack_or_nak_seen = NAK; - dbg("NAK packet complete."); + dev_dbg(dev, "NAK packet complete.\n"); } else { - dbg("packet complete - id=0x%X.", + dev_dbg(dev, "packet complete - id=0x%X.\n", 0xFF & data); gsp_rec_packet(garmin_data_p, size); } @@ -557,7 +554,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, } if (size >= GPS_IN_BUFSIZ) { - dbg("%s - packet too large.", __func__); + dev_dbg(dev, "%s - packet too large.\n", __func__); skip = 1; size = GSP_INITIAL_OFFSET; dleSeen = 0; @@ -602,6 +599,7 @@ static int gsp_receive(struct garmin_data *garmin_data_p, static int gsp_send(struct garmin_data *garmin_data_p, const unsigned char *buf, int count) { + struct device *dev = &garmin_data_p->port->dev; const unsigned char *src; unsigned char *dst; int pktid = 0; @@ -610,12 +608,12 @@ static int gsp_send(struct garmin_data *garmin_data_p, int i = 0; int k; - dbg("%s - state %d - %d bytes.", __func__, - garmin_data_p->state, count); + dev_dbg(dev, "%s - state %d - %d bytes.\n", __func__, + garmin_data_p->state, count); k = garmin_data_p->outsize; if ((k+count) > GPS_OUT_BUFSIZ) { - dbg("packet too large"); + dev_dbg(dev, "packet too large\n"); garmin_data_p->outsize = 0; return -4; } @@ -634,28 +632,28 @@ static int gsp_send(struct garmin_data *garmin_data_p, return 0; } - dbg("%s - %d bytes in buffer, %d bytes in pkt.", __func__, k, i); + dev_dbg(dev, "%s - %d bytes in buffer, %d bytes in pkt.\n", __func__, k, i); /* garmin_data_p->outbuffer now contains a complete packet */ - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, k, garmin_data_p->outbuffer); + usb_serial_debug_data(&garmin_data_p->port->dev, __func__, k, + garmin_data_p->outbuffer); garmin_data_p->outsize = 0; if (GARMIN_LAYERID_APPL != getLayerId(garmin_data_p->outbuffer)) { - dbg("not an application packet (%d)", + dev_dbg(dev, "not an application packet (%d)\n", getLayerId(garmin_data_p->outbuffer)); return -1; } if (pktid > 255) { - dbg("packet-id %d too large", pktid); + dev_dbg(dev, "packet-id %d too large\n", pktid); return -2; } if (datalen > 255) { - dbg("packet-size %d too large", datalen); + dev_dbg(dev, "packet-size %d too large\n", datalen); return -3; } @@ -722,7 +720,7 @@ static int gsp_next_packet(struct garmin_data *garmin_data_p) struct garmin_packet *pkt = NULL; while ((pkt = pkt_pop(garmin_data_p)) != NULL) { - dbg("%s - next pkt: %d", __func__, pkt->seq); + dev_dbg(&garmin_data_p->port->dev, "%s - next pkt: %d\n", __func__, pkt->seq); result = gsp_send(garmin_data_p, pkt->data, pkt->size); if (result > 0) { kfree(pkt); @@ -768,7 +766,9 @@ static int nat_receive(struct garmin_data *garmin_data_p, if (len >= GPS_IN_BUFSIZ) { /* seems to be an invalid packet, ignore rest of input */ - dbg("%s - packet size too large: %d", __func__, len); + dev_dbg(&garmin_data_p->port->dev, + "%s - packet size too large: %d\n", + __func__, len); garmin_data_p->insize = 0; count = 0; result = -EINVPKT; @@ -849,10 +849,10 @@ static int process_resetdev_request(struct usb_serial_port *port) spin_unlock_irqrestore(&garmin_data_p->lock, flags); usb_kill_urb(port->interrupt_in_urb); - dbg("%s - usb_reset_device", __func__); + dev_dbg(&port->dev, "%s - usb_reset_device\n", __func__); status = usb_reset_device(port->serial->dev); if (status) - dbg("%s - usb_reset_device failed: %d", + dev_dbg(&port->dev, "%s - usb_reset_device failed: %d\n", __func__, status); return status; } @@ -889,7 +889,7 @@ static int garmin_init_session(struct usb_serial_port *port) if (status == 0) { usb_kill_urb(port->interrupt_in_urb); - dbg("%s - adding interrupt input", __func__); + dev_dbg(&serial->dev->dev, "%s - adding interrupt input\n", __func__); status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (status) dev_err(&serial->dev->dev, @@ -902,7 +902,7 @@ static int garmin_init_session(struct usb_serial_port *port) * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() */ if (status == 0) { - dbg("%s - starting session ...", __func__); + dev_dbg(&serial->dev->dev, "%s - starting session ...\n", __func__); garmin_data_p->state = STATE_ACTIVE; for (i = 0; i < 3; i++) { @@ -952,8 +952,8 @@ static void garmin_close(struct usb_serial_port *port) struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d - mode=%d state=%d flags=0x%X", __func__, - port->number, garmin_data_p->mode, + dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n", + __func__, port->number, garmin_data_p->mode, garmin_data_p->state, garmin_data_p->flags); if (!serial) @@ -1032,7 +1032,7 @@ static int garmin_write_bulk(struct usb_serial_port *port, memcpy(buffer, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); + usb_serial_debug_data(&port->dev, __func__, count, buffer); usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, @@ -1073,11 +1073,12 @@ static int garmin_write_bulk(struct usb_serial_port *port, static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { + struct device *dev = &port->dev; int pktid, pktsiz, len; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); __le32 *privpkt = (__le32 *)garmin_data_p->privpkt; - usb_serial_debug_data(debug, &port->dev, __func__, count, buf); + usb_serial_debug_data(dev, __func__, count, buf); if (garmin_data_p->state == STATE_RESET) return -EIO; @@ -1097,27 +1098,18 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, && GARMIN_LAYERID_PRIVATE == getLayerId(garmin_data_p->privpkt)) { - dbg("%s - processing private request %d", + dev_dbg(dev, "%s - processing private request %d\n", __func__, pktid); /* drop all unfinished transfers */ garmin_clear(garmin_data_p); switch (pktid) { - - case PRIV_PKTID_SET_DEBUG: - if (pktsiz != 4) - return -EINVPKT; - debug = __le32_to_cpu(privpkt[3]); - dbg("%s - debug level set to 0x%X", - __func__, debug); - break; - case PRIV_PKTID_SET_MODE: if (pktsiz != 4) return -EINVPKT; garmin_data_p->mode = __le32_to_cpu(privpkt[3]); - dbg("%s - mode set to %d", + dev_dbg(dev, "%s - mode set to %d\n", __func__, garmin_data_p->mode); break; @@ -1133,7 +1125,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, if (pktsiz != 4) return -EINVPKT; initial_mode = __le32_to_cpu(privpkt[3]); - dbg("%s - initial_mode set to %d", + dev_dbg(dev, "%s - initial_mode set to %d\n", __func__, garmin_data_p->mode); break; @@ -1169,7 +1161,7 @@ static void garmin_read_process(struct garmin_data *garmin_data_p, if (garmin_data_p->flags & FLAGS_DROP_DATA) { /* abort-transfer cmd is actice */ - dbg("%s - pkt dropped", __func__); + dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__); } else if (garmin_data_p->state != STATE_DISCONNECTED && garmin_data_p->state != STATE_RESET) { @@ -1178,7 +1170,7 @@ static void garmin_read_process(struct garmin_data *garmin_data_p, send it directly to the tty port */ if (garmin_data_p->flags & FLAGS_QUEUING) { pkt_add(garmin_data_p, data, data_length); - } else if (bulk_data || + } else if (bulk_data || getLayerId(data) == GARMIN_LAYERID_APPL) { spin_lock_irqsave(&garmin_data_p->lock, flags); @@ -1208,18 +1200,17 @@ static void garmin_read_bulk_callback(struct urb *urb) int retval; if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); + dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__); return; } if (status) { - dbg("%s - nonzero read bulk status received: %d", + dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status); return; } - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); garmin_read_process(garmin_data_p, data, urb->actual_length, 1); @@ -1239,11 +1230,11 @@ static void garmin_read_bulk_callback(struct urb *urb) retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (retval) dev_err(&port->dev, - "%s - failed resubmitting read urb, " - "error %d\n", __func__, retval); + "%s - failed resubmitting read urb, error %d\n", + __func__, retval); } } else { - dbg("%s - end of bulk data", __func__); + dev_dbg(&port->dev, "%s - end of bulk data\n", __func__); spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; spin_unlock_irqrestore(&garmin_data_p->lock, flags); @@ -1268,23 +1259,23 @@ static void garmin_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); return; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + urb->transfer_buffer); if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) && 0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY, sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) { - dbg("%s - bulk data available.", __func__); + dev_dbg(&port->dev, "%s - bulk data available.\n", __func__); if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { @@ -1319,7 +1310,7 @@ static void garmin_read_int_callback(struct urb *urb) garmin_data_p->serial_num = __le32_to_cpup( (__le32 *)(data+GARMIN_PKTHDR_LENGTH)); - dbg("%s - start-of-session reply seen - serial %u.", + dev_dbg(&port->dev, "%s - start-of-session reply seen - serial %u.\n", __func__, garmin_data_p->serial_num); } @@ -1495,7 +1486,5 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IWUSR | S_IRUGO); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(initial_mode, int, S_IRUGO); MODULE_PARM_DESC(initial_mode, "Initial mode"); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 9b026bf..2966121 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -24,8 +24,6 @@ #include <linux/kfifo.h> #include <linux/serial.h> -static int debug; - #ifdef CONFIG_USB_SERIAL_GENERIC static __u16 vendor = 0x05f9; @@ -60,11 +58,10 @@ static struct usb_serial_driver * const serial_drivers[] = { #endif -int usb_serial_generic_register(int _debug) +int usb_serial_generic_register(void) { int retval = 0; - debug = _debug; #ifdef CONFIG_USB_SERIAL_GENERIC generic_device_ids[0].idVendor = vendor; generic_device_ids[0].idProduct = product; @@ -171,8 +168,7 @@ retry: urb->transfer_buffer, port->bulk_out_size); urb->transfer_buffer_length = count; - usb_serial_debug_data(debug, &port->dev, __func__, count, - urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, urb->transfer_buffer); spin_lock_irqsave(&port->lock, flags); port->tx_bytes += count; spin_unlock_irqrestore(&port->lock, flags); @@ -365,8 +361,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) return; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); port->serial->type->process_read_urb(urb); /* Throttle the device if requested by tty */ diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f435575..8e6faaf 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -190,9 +190,6 @@ static const struct divisor_table_entry divisor_table[] = { { 230400, 1}, }; -/* local variables */ -static bool debug; - /* Number of outstanding Command Write Urbs */ static atomic_t CmdUrbs = ATOMIC_INIT(0); @@ -244,7 +241,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data); static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param); -static int calc_baud_rate_divisor(int baud_rate, int *divisor); +static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, int baudRate); static void change_port_settings(struct tty_struct *tty, @@ -286,6 +283,7 @@ static void unicode_to_ascii(char *string, int buflen, ************************************************************************/ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; __u32 BootCurVer; __u32 BootNewVer; __u8 BootMajorVersion; @@ -311,7 +309,7 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) response = request_ihex_firmware(&fw, fw_name, &edge_serial->serial->dev->dev); if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + dev_err(dev, "Failed to load image \"%s\" err %d\n", fw_name, response); return; } @@ -330,20 +328,20 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) (BootMinorVersion << 16) + BootBuildNumber; - dbg("Current Boot Image version %d.%d.%d", + dev_dbg(dev, "Current Boot Image version %d.%d.%d\n", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); if (BootNewVer > BootCurVer) { - dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d", + dev_dbg(dev, "**Update Boot Image from %d.%d.%d to %d.%d.%d\n", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber), BootMajorVersion, BootMinorVersion, BootBuildNumber); - dbg("Downloading new Boot Image"); + dev_dbg(dev, "Downloading new Boot Image\n"); for (rec = ihex_next_binrec(rec); rec; rec = ihex_next_binrec(rec)) { @@ -362,7 +360,7 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) } } } else { - dbg("Boot Image -- already up to date"); + dev_dbg(dev, "Boot Image -- already up to date\n"); } release_firmware(fw); } @@ -379,7 +377,7 @@ static int get_string_desc(struct usb_device *dev, int Id, struct usb_string_descriptor StringDesc; struct usb_string_descriptor *pStringDesc; - dbg("%s - USB String ID = %d", __func__, Id); + dev_dbg(&dev->dev, "%s - USB String ID = %d\n", __func__, Id); if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) @@ -400,34 +398,39 @@ static int get_string_desc(struct usb_device *dev, int Id, } #endif -static void dump_product_info(struct edgeport_product_info *product_info) +static void dump_product_info(struct edgeport_serial *edge_serial, + struct edgeport_product_info *product_info) { + struct device *dev = &edge_serial->serial->dev->dev; + /* Dump Product Info structure */ - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId); - dbg(" NumPorts %d", product_info->NumPorts); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232); - dbg(" IsRS422 %d", product_info->IsRS422); - dbg(" IsRS485 %d", product_info->IsRS485); - dbg(" RomSize %d", product_info->RomSize); - dbg(" RamSize %d", product_info->RamSize); - dbg(" CpuRev %x", product_info->CpuRev); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", - product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", - product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); - dbg(" EpicVer %d", product_info->EpicVer); + dev_dbg(dev, "**Product Information:\n"); + dev_dbg(dev, " ProductId %x\n", product_info->ProductId); + dev_dbg(dev, " NumPorts %d\n", product_info->NumPorts); + dev_dbg(dev, " ProdInfoVer %d\n", product_info->ProdInfoVer); + dev_dbg(dev, " IsServer %d\n", product_info->IsServer); + dev_dbg(dev, " IsRS232 %d\n", product_info->IsRS232); + dev_dbg(dev, " IsRS422 %d\n", product_info->IsRS422); + dev_dbg(dev, " IsRS485 %d\n", product_info->IsRS485); + dev_dbg(dev, " RomSize %d\n", product_info->RomSize); + dev_dbg(dev, " RamSize %d\n", product_info->RamSize); + dev_dbg(dev, " CpuRev %x\n", product_info->CpuRev); + dev_dbg(dev, " BoardRev %x\n", product_info->BoardRev); + dev_dbg(dev, " BootMajorVersion %d.%d.%d\n", + product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dev_dbg(dev, " FirmwareMajorVersion %d.%d.%d\n", + product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dev_dbg(dev, " ManufactureDescDate %d/%d/%d\n", + product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dev_dbg(dev, " iDownloadFile 0x%x\n", + product_info->iDownloadFile); + dev_dbg(dev, " EpicVer %d\n", product_info->EpicVer); } static void get_product_info(struct edgeport_serial *edge_serial) @@ -462,7 +465,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_80251; else product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_I930; - + /* Determine Product type and set appropriate flags */ switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) { case ION_DEVICE_ID_EDGEPORT_COMPATIBLE: @@ -490,7 +493,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) break; } - dump_product_info(product_info); + dump_product_info(edge_serial, product_info); } static int get_epic_descriptor(struct edgeport_serial *ep) @@ -500,6 +503,7 @@ static int get_epic_descriptor(struct edgeport_serial *ep) struct edgeport_product_info *product_info = &ep->product_info; struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; struct edge_compatibility_bits *bits; + struct device *dev = &serial->dev->dev; ep->is_epic = 0; result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -509,8 +513,6 @@ static int get_epic_descriptor(struct edgeport_serial *ep) sizeof(struct edge_compatibility_descriptor), 300); - dbg("%s result = %d", __func__, result); - if (result > 0) { ep->is_epic = 1; memset(product_info, 0, sizeof(struct edgeport_product_info)); @@ -524,23 +526,23 @@ static int get_epic_descriptor(struct edgeport_serial *ep) product_info->EpicVer = epic->EpicVer; product_info->Epic = epic->Supports; product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; - dump_product_info(product_info); + dump_product_info(ep, product_info); bits = &ep->epic_descriptor.Supports; - dbg("**EPIC descriptor:"); - dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); - dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE"); - dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE"); - dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE"); - dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE"); - dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE"); - dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE"); - dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE"); - dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE"); - dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); - dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE"); + dev_dbg(dev, "**EPIC descriptor:\n"); + dev_dbg(dev, " VendEnableSuspend: %s\n", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPOpen : %s\n", bits->IOSPOpen ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPClose : %s\n", bits->IOSPClose ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPChase : %s\n", bits->IOSPChase ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetRxFlow : %s\n", bits->IOSPSetRxFlow ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetTxFlow : %s\n", bits->IOSPSetTxFlow ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetXChar : %s\n", bits->IOSPSetXChar ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPRxCheck : %s\n", bits->IOSPRxCheck ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetClrBreak : %s\n", bits->IOSPSetClrBreak ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPWriteMCR : %s\n", bits->IOSPWriteMCR ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPWriteLCR : %s\n", bits->IOSPWriteLCR ? "TRUE": "FALSE"); + dev_dbg(dev, " IOSPSetBaudRate : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); + dev_dbg(dev, " TrueEdgeport : %s\n", bits->TrueEdgeport ? "TRUE": "FALSE"); } return result; @@ -561,7 +563,8 @@ static int get_epic_descriptor(struct edgeport_serial *ep) *****************************************************************************/ static void edge_interrupt_callback(struct urb *urb) { - struct edgeport_serial *edge_serial = urb->context; + struct edgeport_serial *edge_serial = urb->context; + struct device *dev; struct edgeport_port *edge_port; struct usb_serial_port *port; struct tty_struct *tty; @@ -574,8 +577,6 @@ static void edge_interrupt_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -584,36 +585,42 @@ static void edge_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } + dev = &edge_serial->serial->dev->dev; + /* process this interrupt-read even if there are no ports open */ if (length) { - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); + usb_serial_debug_data(dev, __func__, length, data); if (length > 1) { bytes_avail = data[0] | (data[1] << 8); if (bytes_avail) { spin_lock(&edge_serial->es_lock); edge_serial->rxBytesAvail += bytes_avail; - dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __func__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress); + dev_dbg(dev, + "%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n", + __func__, bytes_avail, + edge_serial->rxBytesAvail, + edge_serial->read_in_progress); if (edge_serial->rxBytesAvail > 0 && !edge_serial->read_in_progress) { - dbg("%s - posting a read", __func__); + dev_dbg(dev, "%s - posting a read\n", __func__); edge_serial->read_in_progress = true; /* we have pending bytes on the bulk in pipe, send a request */ result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { - dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result); + dev_err(dev, + "%s - usb_submit_urb(read bulk) failed with result = %d\n", + __func__, result); edge_serial->read_in_progress = false; } } @@ -633,9 +640,9 @@ static void edge_interrupt_callback(struct urb *urb) spin_lock(&edge_port->ep_lock); edge_port->txCredits += txCredits; spin_unlock(&edge_port->ep_lock); - dbg("%s - txcredits for port%d = %d", - __func__, portNumber, - edge_port->txCredits); + dev_dbg(dev, "%s - txcredits for port%d = %d\n", + __func__, portNumber, + edge_port->txCredits); /* tell the tty driver that something has changed */ @@ -673,49 +680,48 @@ exit: static void edge_bulk_in_callback(struct urb *urb) { struct edgeport_serial *edge_serial = urb->context; + struct device *dev; unsigned char *data = urb->transfer_buffer; int retval; __u16 raw_data_length; int status = urb->status; - dbg("%s", __func__); - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", + __func__, status); edge_serial->read_in_progress = false; return; } if (urb->actual_length == 0) { - dbg("%s - read bulk callback with no data", __func__); + dev_dbg(&urb->dev->dev, "%s - read bulk callback with no data\n", __func__); edge_serial->read_in_progress = false; return; } + dev = &edge_serial->serial->dev->dev; raw_data_length = urb->actual_length; - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, raw_data_length, data); + usb_serial_debug_data(dev, __func__, raw_data_length, data); spin_lock(&edge_serial->es_lock); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; - dbg("%s - Received = %d, rxBytesAvail %d", __func__, - raw_data_length, edge_serial->rxBytesAvail); + dev_dbg(dev, "%s - Received = %d, rxBytesAvail %d\n", __func__, + raw_data_length, edge_serial->rxBytesAvail); process_rcvd_data(edge_serial, data, urb->actual_length); /* check to see if there's any more data for us to read */ if (edge_serial->rxBytesAvail > 0) { - dbg("%s - posting a read", __func__); + dev_dbg(dev, "%s - posting a read\n", __func__); retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (retval) { - dev_err(&urb->dev->dev, - "%s - usb_submit_urb(read bulk) failed, " - "retval = %d\n", __func__, retval); + dev_err(dev, + "%s - usb_submit_urb(read bulk) failed, retval = %d\n", + __func__, retval); edge_serial->read_in_progress = false; } } else { @@ -737,11 +743,10 @@ static void edge_bulk_out_data_callback(struct urb *urb) struct tty_struct *tty; int status = urb->status; - dbg("%s", __func__); - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, status); } tty = tty_port_tty_get(&edge_port->port->port); @@ -773,11 +778,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) struct tty_struct *tty; int status = urb->status; - dbg("%s", __func__); - atomic_dec(&CmdUrbs); - dbg("%s - FREE URB %p (outstanding %d)", __func__, - urb, atomic_read(&CmdUrbs)); + dev_dbg(&urb->dev->dev, "%s - FREE URB %p (outstanding %d)\n", + __func__, urb, atomic_read(&CmdUrbs)); /* clean up the transfer buffer */ @@ -787,8 +790,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) usb_free_urb(urb); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } @@ -819,12 +823,11 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct device *dev = &port->dev; struct usb_serial *serial; struct edgeport_serial *edge_serial; int response; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; @@ -875,9 +878,8 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) { - dev_err(&port->dev, - "%s - Error %d submitting control urb\n", - __func__, response); + dev_err(dev, "%s - Error %d submitting control urb\n", + __func__, response); } } @@ -902,8 +904,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) response = send_iosp_ext_cmd(edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { - dev_err(&port->dev, "%s - error sending open port command\n", - __func__); + dev_err(dev, "%s - error sending open port command\n", __func__); edge_port->openPending = false; return -ENODEV; } @@ -914,7 +915,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (!edge_port->open) { /* open timed out */ - dbg("%s - open timedout", __func__); + dev_dbg(dev, "%s - open timedout\n", __func__); edge_port->openPending = false; return -ENODEV; } @@ -927,7 +928,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) edge_port->txfifo.fifo = kmalloc(edge_port->maxTxCredits, GFP_KERNEL); if (!edge_port->txfifo.fifo) { - dbg("%s - no memory", __func__); + dev_dbg(dev, "%s - no memory\n", __func__); edge_close(port); return -ENOMEM; } @@ -937,15 +938,13 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) edge_port->write_in_progress = false; if (!edge_port->write_urb) { - dbg("%s - no memory", __func__); + dev_dbg(dev, "%s - no memory\n", __func__); edge_close(port); return -ENOMEM; } - dbg("%s(%d) - Initialize TX fifo to %d bytes", - __func__, port->number, edge_port->maxTxCredits); - - dbg("%s exited", __func__); + dev_dbg(dev, "%s(%d) - Initialize TX fifo to %d bytes\n", + __func__, port->number, edge_port->maxTxCredits); return 0; } @@ -963,6 +962,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ************************************************************************/ static void block_until_chase_response(struct edgeport_port *edge_port) { + struct device *dev = &edge_port->port->dev; DEFINE_WAIT(wait); __u16 lastCredits; int timeout = 1*HZ; @@ -974,11 +974,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port) /* Did we get our Chase response */ if (!edge_port->chaseResponsePending) { - dbg("%s - Got Chase Response", __func__); + dev_dbg(dev, "%s - Got Chase Response\n", __func__); /* did we get all of our credit back? */ if (edge_port->txCredits == edge_port->maxTxCredits) { - dbg("%s - Got all credits", __func__); + dev_dbg(dev, "%s - Got all credits\n", __func__); return; } } @@ -994,12 +994,12 @@ static void block_until_chase_response(struct edgeport_port *edge_port) loop--; if (loop == 0) { edge_port->chaseResponsePending = false; - dbg("%s - Chase TIMEOUT", __func__); + dev_dbg(dev, "%s - Chase TIMEOUT\n", __func__); return; } } else { /* Reset timeout value back to 10 seconds */ - dbg("%s - Last %d, Current %d", __func__, + dev_dbg(dev, "%s - Last %d, Current %d\n", __func__, lastCredits, edge_port->txCredits); loop = 10; } @@ -1019,6 +1019,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) ************************************************************************/ static void block_until_tx_empty(struct edgeport_port *edge_port) { + struct device *dev = &edge_port->port->dev; DEFINE_WAIT(wait); struct TxFifo *fifo = &edge_port->txfifo; __u32 lastCount; @@ -1031,7 +1032,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) /* Is the Edgeport Buffer empty? */ if (lastCount == 0) { - dbg("%s - TX Buffer Empty", __func__); + dev_dbg(dev, "%s - TX Buffer Empty\n", __func__); return; } @@ -1041,13 +1042,13 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) schedule_timeout(timeout); finish_wait(&edge_port->wait_chase, &wait); - dbg("%s wait", __func__); + dev_dbg(dev, "%s wait\n", __func__); if (lastCount == fifo->count) { /* No activity.. count down. */ loop--; if (loop == 0) { - dbg("%s - TIMEOUT", __func__); + dev_dbg(dev, "%s - TIMEOUT\n", __func__); return; } } else { @@ -1068,8 +1069,6 @@ static void edge_close(struct usb_serial_port *port) struct edgeport_port *edge_port; int status; - dbg("%s - port %d", __func__, port->number); - edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); if (edge_serial == NULL || edge_port == NULL) @@ -1086,7 +1085,7 @@ static void edge_close(struct usb_serial_port *port) /* flush and chase */ edge_port->chaseResponsePending = true; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) /* block until chase finished */ @@ -1099,7 +1098,7 @@ static void edge_close(struct usb_serial_port *port) ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPClose))) { /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLOSE_PORT\n", __func__); send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0); } @@ -1119,8 +1118,6 @@ static void edge_close(struct usb_serial_port *port) } kfree(edge_port->txfifo.fifo); edge_port->txfifo.fifo = NULL; - - dbg("%s exited", __func__); } /***************************************************************************** @@ -1141,8 +1138,6 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, int secondhalf; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; @@ -1155,14 +1150,14 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, copySize = min((unsigned int)count, (edge_port->txCredits - fifo->count)); - dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", - __func__, port->number, count, + dev_dbg(&port->dev, "%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes\n", + __func__, port->number, count, edge_port->txCredits - fifo->count, copySize); /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */ if (copySize == 0) { - dbg("%s - copySize = Zero", __func__); + dev_dbg(&port->dev, "%s - copySize = Zero\n", __func__); goto finish_write; } @@ -1175,13 +1170,12 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, */ bytesleft = fifo->size - fifo->head; firsthalf = min(bytesleft, copySize); - dbg("%s - copy %d bytes of %d into fifo ", __func__, - firsthalf, bytesleft); + dev_dbg(&port->dev, "%s - copy %d bytes of %d into fifo \n", __func__, + firsthalf, bytesleft); /* now copy our data */ memcpy(&fifo->fifo[fifo->head], data, firsthalf); - usb_serial_debug_data(debug, &port->dev, __func__, - firsthalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(&port->dev, __func__, firsthalf, &fifo->fifo[fifo->head]); /* update the index and size */ fifo->head += firsthalf; @@ -1194,10 +1188,9 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, secondhalf = copySize-firsthalf; if (secondhalf) { - dbg("%s - copy rest of data %d", __func__, secondhalf); + dev_dbg(&port->dev, "%s - copy rest of data %d\n", __func__, secondhalf); memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); - usb_serial_debug_data(debug, &port->dev, __func__, - secondhalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(&port->dev, __func__, secondhalf, &fifo->fifo[fifo->head]); /* update the index and size */ fifo->count += secondhalf; fifo->head += secondhalf; @@ -1212,8 +1205,8 @@ finish_write: send_more_port_data((struct edgeport_serial *) usb_get_serial_data(port->serial), edge_port); - dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __func__, - copySize, edge_port->txCredits, fifo->count); + dev_dbg(&port->dev, "%s wrote %d byte(s) TxCredits %d, Fifo %d\n", + __func__, copySize, edge_port->txCredits, fifo->count); return copySize; } @@ -1236,6 +1229,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port) { struct TxFifo *fifo = &edge_port->txfifo; + struct device *dev = &edge_port->port->dev; struct urb *urb; unsigned char *buffer; int status; @@ -1245,16 +1239,14 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, int secondhalf; unsigned long flags; - dbg("%s(%d)", __func__, edge_port->port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->write_in_progress || !edge_port->open || (fifo->count == 0)) { - dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", - __func__, edge_port->port->number, - fifo->count, edge_port->write_in_progress); + dev_dbg(dev, "%s(%d) EXIT - fifo %d, PendingWrite = %d\n", + __func__, edge_port->port->number, + fifo->count, edge_port->write_in_progress); goto exit_send; } @@ -1266,7 +1258,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, * it's better to wait for more credits so we can do a larger write. */ if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits, EDGE_FW_BULK_MAX_PACKET_SIZE)) { - dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", + dev_dbg(dev, "%s(%d) Not enough credit - fifo %d TxCredit %d\n", __func__, edge_port->port->number, fifo->count, edge_port->txCredits); goto exit_send; @@ -1315,8 +1307,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, } if (count) - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, count, &buffer[2]); + usb_serial_debug_data(&edge_port->port->dev, __func__, count, &buffer[2]); /* fill up the urb with all of our data and submit it */ usb_fill_bulk_urb(urb, edge_serial->serial->dev, @@ -1341,8 +1332,8 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, edge_port->txCredits += count; edge_port->icount.tx -= count; } - dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", - __func__, count, edge_port->txCredits, fifo->count); + dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n", + __func__, count, edge_port->txCredits, fifo->count); exit_send: spin_unlock_irqrestore(&edge_port->ep_lock, flags); @@ -1363,17 +1354,13 @@ static int edge_write_room(struct tty_struct *tty) int room; unsigned long flags; - dbg("%s", __func__); - if (edge_port == NULL) return 0; if (edge_port->closePending) return 0; - dbg("%s - port %d", __func__, port->number); - if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return 0; } @@ -1382,7 +1369,7 @@ static int edge_write_room(struct tty_struct *tty) room = edge_port->txCredits - edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1403,15 +1390,13 @@ static int edge_chars_in_buffer(struct tty_struct *tty) int num_chars; unsigned long flags; - dbg("%s", __func__); - if (edge_port == NULL) return 0; if (edge_port->closePending) return 0; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return 0; } @@ -1420,8 +1405,8 @@ static int edge_chars_in_buffer(struct tty_struct *tty) edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); if (num_chars) { - dbg("%s(port %d) - returns %d", __func__, - port->number, num_chars); + dev_dbg(&port->dev, "%s(port %d) - returns %d\n", __func__, + port->number, num_chars); } return num_chars; @@ -1439,13 +1424,11 @@ static void edge_throttle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1479,13 +1462,11 @@ static void edge_unthrottle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1517,18 +1498,14 @@ static void edge_set_termios(struct tty_struct *tty, unsigned int cflag; cflag = tty->termios.c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios.c_cflag, tty->termios.c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios.c_cflag, tty->termios.c_iflag); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; if (!edge_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1556,7 +1533,7 @@ static int get_lsr_info(struct edgeport_port *edge_port, spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->maxTxCredits == edge_port->txCredits && edge_port->txfifo.count == 0) { - dbg("%s -- Empty", __func__); + dev_dbg(&edge_port->port->dev, "%s -- Empty\n", __func__); result = TIOCSER_TEMT; } spin_unlock_irqrestore(&edge_port->ep_lock, flags); @@ -1573,8 +1550,6 @@ static int edge_tiocmset(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - mcr = edge_port->shadowMCR; if (set & TIOCM_RTS) mcr |= MCR_RTS; @@ -1605,8 +1580,6 @@ static int edge_tiocmget(struct tty_struct *tty) unsigned int msr; unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - msr = edge_port->shadowMSR; mcr = edge_port->shadowMCR; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ @@ -1616,9 +1589,6 @@ static int edge_tiocmget(struct tty_struct *tty) | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - - dbg("%s -- %x", __func__, result); - return result; } @@ -1642,8 +1612,8 @@ static int edge_get_icount(struct tty_struct *tty, icount->brk = cnow.brk; icount->buf_overrun = cnow.buf_overrun; - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, icount->rx, icount->tx); + dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__, + port->number, icount->rx, icount->tx); return 0; } @@ -1686,19 +1656,19 @@ static int edge_ioctl(struct tty_struct *tty, struct async_icount cnow; struct async_icount cprev; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); switch (cmd) { case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCSERGETLSR\n", __func__, port->number); return get_lsr_info(edge_port, (unsigned int __user *) arg); case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__, port->number); return get_serial_info(edge_port, (struct serial_struct __user *) arg); case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number); cprev = edge_port->icount; while (1) { prepare_to_wait(&edge_port->delta_msr_wait, @@ -1745,7 +1715,7 @@ static void edge_break(struct tty_struct *tty, int break_state) /* flush and chase */ edge_port->chaseResponsePending = true; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CHASE_PORT\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) { /* block until chase finished */ @@ -1759,16 +1729,16 @@ static void edge_break(struct tty_struct *tty, int break_state) ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_SET_BREAK\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_BREAK, 0); } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __func__); + dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLEAR_BREAK\n", __func__); status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CLEAR_BREAK, 0); } if (status) - dbg("%s - error sending break set/clear command.", + dev_dbg(&port->dev, "%s - error sending break set/clear command.\n", __func__); } } @@ -1781,20 +1751,19 @@ static void edge_break(struct tty_struct *tty, int break_state) static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { + struct device *dev = &edge_serial->serial->dev->dev; struct usb_serial_port *port; struct edgeport_port *edge_port; struct tty_struct *tty; __u16 lastBufferLength; __u16 rxLen; - dbg("%s", __func__); - lastBufferLength = bufferLength + 1; while (bufferLength > 0) { /* failsafe incase we get a message that we don't understand */ if (lastBufferLength == bufferLength) { - dbg("%s - stuck in loop, exiting it.", __func__); + dev_dbg(dev, "%s - stuck in loop, exiting it.\n", __func__); break; } lastBufferLength = bufferLength; @@ -1815,8 +1784,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, ++buffer; --bufferLength; - dbg("%s - Hdr1=%02X Hdr2=%02X", __func__, - edge_serial->rxHeader1, edge_serial->rxHeader2); + dev_dbg(dev, "%s - Hdr1=%02X Hdr2=%02X\n", __func__, + edge_serial->rxHeader1, edge_serial->rxHeader2); /* Process depending on whether this header is * data or status */ @@ -1855,10 +1824,10 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, IOSP_GET_HDR_DATA_LEN( edge_serial->rxHeader1, edge_serial->rxHeader2); - dbg("%s - Data for Port %u Len %u", - __func__, - edge_serial->rxPort, - edge_serial->rxBytesRemaining); + dev_dbg(dev, "%s - Data for Port %u Len %u\n", + __func__, + edge_serial->rxPort, + edge_serial->rxBytesRemaining); /* ASSERT(DevExt->RxPort < DevExt->NumPorts); * ASSERT(DevExt->RxBytesRemaining < @@ -1896,7 +1865,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, tty = tty_port_tty_get( &edge_port->port->port); if (tty) { - dbg("%s - Sending %d bytes to TTY for port %d", + dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", __func__, rxLen, edge_serial->rxPort); edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); tty_kref_put(tty); @@ -1935,6 +1904,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, struct usb_serial_port *port; struct edgeport_port *edge_port; struct tty_struct *tty; + struct device *dev; __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ @@ -1946,16 +1916,15 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, __func__, edge_serial->rxPort); return; } - - dbg("%s - port %d", __func__, edge_serial->rxPort); + dev = &port->dev; if (code == IOSP_EXT_STATUS) { switch (byte2) { case IOSP_EXT_STATUS_CHASE_RSP: /* we want to do EXT status regardless of port * open/closed */ - dbg("%s - Port %u EXT CHASE_RSP Data = %02x", - __func__, edge_serial->rxPort, byte3); + dev_dbg(dev, "%s - Port %u EXT CHASE_RSP Data = %02x\n", + __func__, edge_serial->rxPort, byte3); /* Currently, the only EXT_STATUS is Chase, so process * here instead of one more call to one more subroutine * If/when more EXT_STATUS, there'll be more work to do @@ -1970,7 +1939,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, return; case IOSP_EXT_STATUS_RX_CHECK_RSP: - dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3); + dev_dbg(dev, "%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", + __func__, edge_serial->rxPort, byte3); /* Port->RxCheckRsp = true; */ return; } @@ -1979,7 +1949,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, if (code == IOSP_STATUS_OPEN_RSP) { edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); edge_port->maxTxCredits = edge_port->txCredits; - dbg("%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits); + dev_dbg(dev, "%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d\n", + __func__, edge_serial->rxPort, byte2, edge_port->txCredits); handle_new_msr(edge_port, byte2); /* send the current line settings to the port so we are @@ -2008,27 +1979,27 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, switch (code) { /* Not currently sent by Edgeport */ case IOSP_STATUS_LSR: - dbg("%s - Port %u LSR Status = %02x", - __func__, edge_serial->rxPort, byte2); + dev_dbg(dev, "%s - Port %u LSR Status = %02x\n", + __func__, edge_serial->rxPort, byte2); handle_new_lsr(edge_port, false, byte2, 0); break; case IOSP_STATUS_LSR_DATA: - dbg("%s - Port %u LSR Status = %02x, Data = %02x", - __func__, edge_serial->rxPort, byte2, byte3); + dev_dbg(dev, "%s - Port %u LSR Status = %02x, Data = %02x\n", + __func__, edge_serial->rxPort, byte2, byte3); /* byte2 is LSR Register */ /* byte3 is broken data byte */ handle_new_lsr(edge_port, true, byte2, byte3); break; /* * case IOSP_EXT_4_STATUS: - * dbg("%s - Port %u LSR Status = %02x Data = %02x", + * dev_dbg(dev, "%s - Port %u LSR Status = %02x Data = %02x\n", * __func__, edge_serial->rxPort, byte2, byte3); * break; */ case IOSP_STATUS_MSR: - dbg("%s - Port %u MSR Status = %02x", - __func__, edge_serial->rxPort, byte2); + dev_dbg(dev, "%s - Port %u MSR Status = %02x\n", + __func__, edge_serial->rxPort, byte2); /* * Process this new modem status and generate appropriate * events, etc, based on the new status. This routine @@ -2038,7 +2009,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, break; default: - dbg("%s - Unrecognized IOSP status code %u", __func__, code); + dev_dbg(dev, "%s - Unrecognized IOSP status code %u\n", __func__, code); break; } } @@ -2073,8 +2044,6 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) { struct async_icount *icount; - dbg("%s %02x", __func__, newMsr); - if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { icount = &edge_port->icount; @@ -2107,8 +2076,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, (LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); struct async_icount *icount; - dbg("%s - %02x", __func__, newLsr); - edge_port->shadowLSR = lsr; if (newLsr & LSR_BREAK) { @@ -2156,7 +2123,7 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 current_length; unsigned char *transfer_buffer; - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); + dev_dbg(&serial->dev->dev, "%s - %x, %x, %d\n", __func__, extAddr, addr, length); transfer_buffer = kmalloc(64, GFP_KERNEL); if (!transfer_buffer) { @@ -2173,8 +2140,7 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, else current_length = length; -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ +/* dev_dbg(&serial->dev->dev, "%s - writing %x, %x, %d\n", __func__, extAddr, addr, current_length); */ memcpy(transfer_buffer, data, current_length); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2207,8 +2173,6 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 current_length; unsigned char *transfer_buffer; -/* dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); */ - transfer_buffer = kmalloc(64, GFP_KERNEL); if (!transfer_buffer) { dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", @@ -2223,8 +2187,6 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, current_length = 64; else current_length = length; -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ memcpy(transfer_buffer, data, current_length); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2257,8 +2219,6 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 current_length; unsigned char *transfer_buffer; - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); - transfer_buffer = kmalloc(64, GFP_KERNEL); if (!transfer_buffer) { dev_err(&serial->dev->dev, @@ -2273,8 +2233,6 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, current_length = 64; else current_length = length; -/* dbg("%s - %x, %x, %d", __func__, - extAddr, addr, current_length); */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, @@ -2305,8 +2263,6 @@ static int send_iosp_ext_cmd(struct edgeport_port *edge_port, int length = 0; int status = 0; - dbg("%s - %d, %d", __func__, command, param); - buffer = kmalloc(10, GFP_ATOMIC); if (!buffer) { dev_err(&edge_port->port->dev, @@ -2339,11 +2295,11 @@ static int write_cmd_usb(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; int status = 0; struct urb *urb; - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, length, buffer); + usb_serial_debug_data(dev, __func__, length, buffer); /* Allocate our next urb */ urb = usb_alloc_urb(0, GFP_ATOMIC); @@ -2351,8 +2307,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port, return -ENOMEM; atomic_inc(&CmdUrbs); - dbg("%s - ALLOCATE URB %p (outstanding %d)", - __func__, urb, atomic_read(&CmdUrbs)); + dev_dbg(dev, "%s - ALLOCATE URB %p (outstanding %d)\n", + __func__, urb, atomic_read(&CmdUrbs)); usb_fill_bulk_urb(urb, edge_serial->serial->dev, usb_sndbulkpipe(edge_serial->serial->dev, @@ -2364,9 +2320,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port, if (status) { /* something went wrong */ - dev_err(&edge_port->port->dev, - "%s - usb_submit_urb(write command) failed, status = %d\n", - __func__, status); + dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n", + __func__, status); usb_kill_urb(urb); usb_free_urb(urb); atomic_dec(&CmdUrbs); @@ -2378,7 +2333,7 @@ static int write_cmd_usb(struct edgeport_port *edge_port, if (edge_port->commandPending) { /* command timed out */ - dbg("%s - command timed out", __func__); + dev_dbg(dev, "%s - command timed out\n", __func__); status = -EINVAL; } #endif @@ -2396,6 +2351,7 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; @@ -2406,26 +2362,24 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) { - dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", - edge_port->port->number, baudRate); + dev_dbg(dev, "SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d\n", + edge_port->port->number, baudRate); return 0; } - dbg("%s - port = %d, baud = %d", __func__, - edge_port->port->number, baudRate); + dev_dbg(dev, "%s - port = %d, baud = %d\n", __func__, + edge_port->port->number, baudRate); - status = calc_baud_rate_divisor(baudRate, &divisor); + status = calc_baud_rate_divisor(dev, baudRate, &divisor); if (status) { - dev_err(&edge_port->port->dev, "%s - bad baud rate\n", - __func__); + dev_err(dev, "%s - bad baud rate\n", __func__); return status; } /* Alloc memory for the string of commands. */ cmdBuffer = kmalloc(0x100, GFP_ATOMIC); if (!cmdBuffer) { - dev_err(&edge_port->port->dev, - "%s - kmalloc(%d) failed.\n", __func__, 0x100); + dev_err(dev, "%s - kmalloc(%d) failed.\n", __func__, 0x100); return -ENOMEM; } currCmd = cmdBuffer; @@ -2456,14 +2410,11 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) +static int calc_baud_rate_divisor(struct device *dev, int baudrate, int *divisor) { int i; __u16 custom; - - dbg("%s - %d", __func__, baudrate); - for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { if (divisor_table[i].BaudRate == baudrate) { *divisor = divisor_table[i].Divisor; @@ -2480,7 +2431,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) *divisor = custom; - dbg("%s - Baud %d = %d", __func__, baudrate, custom); + dev_dbg(dev, "%s - Baud %d = %d\n", __func__, baudrate, custom); return 0; } @@ -2497,25 +2448,26 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, { struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); + struct device *dev = &edge_port->port->dev; unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; int status; - dbg("%s - write to %s register 0x%02x", - (regNum == MCR) ? "MCR" : "LCR", __func__, regValue); + dev_dbg(dev, "%s - write to %s register 0x%02x\n", + (regNum == MCR) ? "MCR" : "LCR", __func__, regValue); if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPWriteMCR && regNum == MCR) { - dbg("SendCmdWriteUartReg - Not writing to MCR Register"); + dev_dbg(dev, "SendCmdWriteUartReg - Not writing to MCR Register\n"); return 0; } if (edge_serial->is_epic && !edge_serial->epic_descriptor.Supports.IOSPWriteLCR && regNum == LCR) { - dbg("SendCmdWriteUartReg - Not writing to LCR Register"); + dev_dbg(dev, "SendCmdWriteUartReg - Not writing to LCR Register\n"); return 0; } @@ -2550,6 +2502,7 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct device *dev = &edge_port->port->dev; struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); int baud; @@ -2562,11 +2515,11 @@ static void change_port_settings(struct tty_struct *tty, __u8 txFlow; int status; - dbg("%s - port %d", __func__, edge_port->port->number); + dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number); if (!edge_port->open && !edge_port->openPending) { - dbg("%s - port not opened", __func__); + dev_dbg(dev, "%s - port not opened\n", __func__); return; } @@ -2575,20 +2528,20 @@ static void change_port_settings(struct tty_struct *tty, switch (cflag & CSIZE) { case CS5: lData = LCR_BITS_5; mask = 0x1f; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: lData = LCR_BITS_6; mask = 0x3f; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: lData = LCR_BITS_7; mask = 0x7f; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; default: case CS8: lData = LCR_BITS_8; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; } @@ -2597,28 +2550,28 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & CMSPAR) { if (cflag & PARODD) { lParity = LCR_PAR_MARK; - dbg("%s - parity = mark", __func__); + dev_dbg(dev, "%s - parity = mark\n", __func__); } else { lParity = LCR_PAR_SPACE; - dbg("%s - parity = space", __func__); + dev_dbg(dev, "%s - parity = space\n", __func__); } } else if (cflag & PARODD) { lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); + dev_dbg(dev, "%s - parity = odd\n", __func__); } else { lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); + dev_dbg(dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(dev, "%s - parity = none\n", __func__); } if (cflag & CSTOPB) { lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } /* figure out the flow control settings */ @@ -2626,9 +2579,9 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & CRTSCTS) { rxFlow |= IOSP_RX_FLOW_RTS; txFlow |= IOSP_TX_FLOW_CTS; - dbg("%s - RTS/CTS is enabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__); } else { - dbg("%s - RTS/CTS is disabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__); } /* if we are implementing XON/XOFF, set the start and stop character @@ -2649,19 +2602,19 @@ static void change_port_settings(struct tty_struct *tty, /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { rxFlow |= IOSP_RX_FLOW_XON_XOFF; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); + dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, start_char, stop_char); } else { - dbg("%s - INBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__); } /* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) { txFlow |= IOSP_TX_FLOW_XON_XOFF; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, start_char, stop_char); } else { - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__); } } @@ -2704,7 +2657,7 @@ static void change_port_settings(struct tty_struct *tty, baud = 9600; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud); status = send_cmd_write_baud_rate(edge_port, baud); if (status == -1) { /* Speed change was not possible - put back the old speed */ @@ -2746,9 +2699,10 @@ static void unicode_to_ascii(char *string, int buflen, ****************************************************************************/ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; int response; - dbg("getting manufacturer descriptor"); + dev_dbg(dev, "getting manufacturer descriptor\n"); response = rom_read(edge_serial->serial, (EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16, @@ -2757,42 +2711,41 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->manuf_descriptor)); if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting manufacturer descriptor\n"); + dev_err(dev, "error in getting manufacturer descriptor\n"); else { char string[30]; - dbg("**Manufacturer Descriptor"); - dbg(" RomSize: %dK", + dev_dbg(dev, "**Manufacturer Descriptor\n"); + dev_dbg(dev, " RomSize: %dK\n", edge_serial->manuf_descriptor.RomSize); - dbg(" RamSize: %dK", + dev_dbg(dev, " RamSize: %dK\n", edge_serial->manuf_descriptor.RamSize); - dbg(" CpuRev: %d", + dev_dbg(dev, " CpuRev: %d\n", edge_serial->manuf_descriptor.CpuRev); - dbg(" BoardRev: %d", + dev_dbg(dev, " BoardRev: %d\n", edge_serial->manuf_descriptor.BoardRev); - dbg(" NumPorts: %d", + dev_dbg(dev, " NumPorts: %d\n", edge_serial->manuf_descriptor.NumPorts); - dbg(" DescDate: %d/%d/%d", + dev_dbg(dev, " DescDate: %d/%d/%d\n", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2); - dbg(" SerialNumber: %s", string); + dev_dbg(dev, " SerialNumber: %s\n", string); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2); - dbg(" AssemblyNumber: %s", string); + dev_dbg(dev, " AssemblyNumber: %s\n", string); unicode_to_ascii(string, sizeof(string), edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2); - dbg(" OemAssyNumber: %s", string); - dbg(" UartType: %d", + dev_dbg(dev, " OemAssyNumber: %s\n", string); + dev_dbg(dev, " UartType: %d\n", edge_serial->manuf_descriptor.UartType); - dbg(" IonPid: %d", + dev_dbg(dev, " IonPid: %d\n", edge_serial->manuf_descriptor.IonPid); - dbg(" IonConfig: %d", + dev_dbg(dev, " IonConfig: %d\n", edge_serial->manuf_descriptor.IonConfig); } } @@ -2805,9 +2758,10 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) ****************************************************************************/ static void get_boot_desc(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; int response; - dbg("getting boot descriptor"); + dev_dbg(dev, "getting boot descriptor\n"); response = rom_read(edge_serial->serial, (EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16, @@ -2816,23 +2770,22 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) (__u8 *)(&edge_serial->boot_descriptor)); if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting boot descriptor\n"); + dev_err(dev, "error in getting boot descriptor\n"); else { - dbg("**Boot Descriptor:"); - dbg(" BootCodeLength: %d", - le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); - dbg(" MajorVersion: %d", + dev_dbg(dev, "**Boot Descriptor:\n"); + dev_dbg(dev, " BootCodeLength: %d\n", + le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); + dev_dbg(dev, " MajorVersion: %d\n", edge_serial->boot_descriptor.MajorVersion); - dbg(" MinorVersion: %d", + dev_dbg(dev, " MinorVersion: %d\n", edge_serial->boot_descriptor.MinorVersion); - dbg(" BuildNumber: %d", + dev_dbg(dev, " BuildNumber: %d\n", le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); - dbg(" Capabilities: 0x%x", + dev_dbg(dev, " Capabilities: 0x%x\n", le16_to_cpu(edge_serial->boot_descriptor.Capabilities)); - dbg(" UConfig0: %d", + dev_dbg(dev, " UConfig0: %d\n", edge_serial->boot_descriptor.UConfig0); - dbg(" UConfig1: %d", + dev_dbg(dev, " UConfig1: %d\n", edge_serial->boot_descriptor.UConfig1); } } @@ -2844,6 +2797,7 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) ****************************************************************************/ static void load_application_firmware(struct edgeport_serial *edge_serial) { + struct device *dev = &edge_serial->serial->dev->dev; const struct ihex_binrec *rec; const struct firmware *fw; const char *fw_name; @@ -2864,7 +2818,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) break; case EDGE_DOWNLOAD_FILE_NONE: - dbg("No download file specified, skipping download"); + dev_dbg(dev, "No download file specified, skipping download\n"); return; default: @@ -2874,7 +2828,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) response = request_ihex_firmware(&fw, fw_name, &edge_serial->serial->dev->dev); if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + dev_err(dev, "Failed to load image \"%s\" err %d\n", fw_name, response); return; } @@ -2882,7 +2836,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) rec = (const struct ihex_binrec *)fw->data; build = (rec->data[2] << 8) | rec->data[3]; - dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build); + dev_dbg(dev, "%s %d.%d.%d\n", fw_info, rec->data[0], rec->data[1], build); edge_serial->product_info.FirmwareMajorVersion = rec->data[0]; edge_serial->product_info.FirmwareMinorVersion = rec->data[1]; @@ -2905,10 +2859,10 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) } } - dbg("sending exec_dl_code"); - response = usb_control_msg (edge_serial->serial->dev, - usb_sndctrlpipe(edge_serial->serial->dev, 0), - USB_REQUEST_ION_EXEC_DL_CODE, + dev_dbg(dev, "sending exec_dl_code\n"); + response = usb_control_msg (edge_serial->serial->dev, + usb_sndctrlpipe(edge_serial->serial->dev, 0), + USB_REQUEST_ION_EXEC_DL_CODE, 0x40, 0x4000, 0x0001, NULL, 0, 3000); release_firmware(fw); @@ -2923,6 +2877,7 @@ static int edge_startup(struct usb_serial *serial) struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; struct usb_device *dev; + struct device *ddev = &serial->dev->dev; int i, j; int response; bool interrupt_in_found; @@ -2974,32 +2929,31 @@ static int edge_startup(struct usb_serial *serial) /* serial->num_ports = serial->product_info.NumPorts; */ if ((!edge_serial->is_epic) && (edge_serial->product_info.NumPorts != serial->num_ports)) { - dev_warn(&serial->dev->dev, "Device Reported %d serial ports " - "vs. core thinking we have %d ports, email " - "greg@kroah.com this information.\n", + dev_warn(ddev, + "Device Reported %d serial ports vs. core thinking we have %d ports, email greg@kroah.com this information.\n", edge_serial->product_info.NumPorts, serial->num_ports); } - dbg("%s - time 1 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 1 %ld\n", __func__, jiffies); /* If not an EPiC device */ if (!edge_serial->is_epic) { /* now load the application firmware into this device */ load_application_firmware(edge_serial); - dbg("%s - time 2 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 2 %ld\n", __func__, jiffies); /* Check current Edgeport EEPROM and update if necessary */ update_edgeport_E2PROM(edge_serial); - dbg("%s - time 3 %ld", __func__, jiffies); + dev_dbg(ddev, "%s - time 3 %ld\n", __func__, jiffies); /* set the configuration to use #1 */ -/* dbg("set_configuration 1"); */ +/* dev_dbg(ddev, "set_configuration 1\n"); */ /* usb_set_configuration (dev, 1); */ } - dbg(" FirmwareMajorVersion %d.%d.%d", + dev_dbg(ddev, " FirmwareMajorVersion %d.%d.%d\n", edge_serial->product_info.FirmwareMajorVersion, edge_serial->product_info.FirmwareMinorVersion, le16_to_cpu(edge_serial->product_info.FirmwareBuildNumber)); @@ -3011,8 +2965,7 @@ static int edge_startup(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); + dev_err(ddev, "%s - Out of memory\n", __func__); for (j = 0; j < i; ++j) { kfree(usb_get_serial_port_data(serial->port[j])); usb_set_serial_port_data(serial->port[j], @@ -3044,19 +2997,19 @@ static int edge_startup(struct usb_serial *serial) if (!interrupt_in_found && (usb_endpoint_is_int_in(endpoint))) { /* we found a interrupt in endpoint */ - dbg("found interrupt in"); + dev_dbg(ddev, "found interrupt in\n"); /* not set up yet, so do it now */ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); if (!edge_serial->interrupt_read_urb) { - dev_err(&dev->dev, "out of memory\n"); + dev_err(ddev, "out of memory\n"); return -ENOMEM; } edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!edge_serial->interrupt_in_buffer) { - dev_err(&dev->dev, "out of memory\n"); + dev_err(ddev, "out of memory\n"); usb_free_urb(edge_serial->interrupt_read_urb); return -ENOMEM; } @@ -3081,13 +3034,13 @@ static int edge_startup(struct usb_serial *serial) if (!bulk_in_found && (usb_endpoint_is_bulk_in(endpoint))) { /* we found a bulk in endpoint */ - dbg("found bulk in"); + dev_dbg(ddev, "found bulk in\n"); /* not set up yet, so do it now */ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); if (!edge_serial->read_urb) { - dev_err(&dev->dev, "out of memory\n"); + dev_err(ddev, "out of memory\n"); return -ENOMEM; } edge_serial->bulk_in_buffer = @@ -3114,7 +3067,7 @@ static int edge_startup(struct usb_serial *serial) if (!bulk_out_found && (usb_endpoint_is_bulk_out(endpoint))) { /* we found a bulk out endpoint */ - dbg("found bulk out"); + dev_dbg(ddev, "found bulk out\n"); edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; bulk_out_found = true; @@ -3122,8 +3075,7 @@ static int edge_startup(struct usb_serial *serial) } if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) { - dev_err(&dev->dev, "Error - the proper endpoints " - "were not found!\n"); + dev_err(ddev, "Error - the proper endpoints were not found!\n"); return -ENODEV; } @@ -3132,8 +3084,7 @@ static int edge_startup(struct usb_serial *serial) response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) - dev_err(&dev->dev, - "%s - Error %d submitting control urb\n", + dev_err(ddev, "%s - Error %d submitting control urb\n", __func__, response); } return response; @@ -3148,8 +3099,6 @@ static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - dbg("%s", __func__); - /* stop reads and writes on all ports */ /* free up our endpoint stuff */ if (edge_serial->is_epic) { @@ -3173,8 +3122,6 @@ static void edge_release(struct usb_serial *serial) struct edgeport_serial *edge_serial = usb_get_serial_data(serial); int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); @@ -3190,6 +3137,3 @@ MODULE_FIRMWARE("edgeport/boot.fw"); MODULE_FIRMWARE("edgeport/boot2.fw"); MODULE_FIRMWARE("edgeport/down.fw"); MODULE_FIRMWARE("edgeport/down2.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 765978a..a2209cd 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -201,8 +201,6 @@ static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; -static bool debug; - static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -233,8 +231,8 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, if (status < 0) return status; if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); + dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", + __func__, size, status); return -ECOMM; } return 0; @@ -251,8 +249,8 @@ static int ti_vsend_sync(struct usb_device *dev, __u8 request, if (status < 0) return status; if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); + dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n", + __func__, size, status); return -ECOMM; } return 0; @@ -270,7 +268,7 @@ static int purge_port(struct usb_serial_port *port, __u16 mask) { int port_number = port->number - port->serial->minor; - dbg("%s - port %d, mask %x", __func__, port_number, mask); + dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask); return send_cmd(port->serial->dev, UMPC_PURGE_PORT, @@ -295,7 +293,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, __u8 read_length; __be16 be_start_address; - dbg("%s - @ %x for %d", __func__, start_address, length); + dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); /* Read in blocks of 64 bytes * (TI firmware can't handle more than 64 byte reads) @@ -307,8 +305,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, read_length = (__u8)length; if (read_length > 1) { - dbg("%s - @ %x for %d", __func__, - start_address, read_length); + dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); } be_start_address = cpu_to_be16(start_address); status = ti_vread_sync(dev, UMPC_MEMORY_READ, @@ -317,13 +314,12 @@ static int read_download_mem(struct usb_device *dev, int start_address, buffer, read_length); if (status) { - dbg("%s - ERROR %x", __func__, status); + dev_dbg(&dev->dev, "%s - ERROR %x\n", __func__, status); return status; } if (read_length > 1) - usb_serial_debug_data(debug, &dev->dev, __func__, - read_length, buffer); + usb_serial_debug_data(&dev->dev, __func__, read_length, buffer); /* Update pointers/length */ start_address += read_length; @@ -353,15 +349,14 @@ static int read_boot_mem(struct edgeport_serial *serial, UMPC_MEMORY_READ, serial->TI_I2C_Type, (__u16)(start_address+i), &buffer[i], 0x01); if (status) { - dbg("%s - ERROR %x", __func__, status); + dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status; } } - dbg("%s - start_address = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); + dev_dbg(&serial->serial->dev->dev, "%s - start_address = %x, length = %d\n", + __func__, start_address, length); + usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer); serial->TiReadI2C = 1; @@ -398,10 +393,8 @@ static int write_boot_mem(struct edgeport_serial *serial, return status; } - dbg("%s - start_sddr = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); + dev_dbg(&serial->serial->dev->dev, "%s - start_sddr = %x, length = %d\n", __func__, start_address, length); + usb_serial_debug_data(&serial->serial->dev->dev, __func__, length, buffer); return status; } @@ -411,6 +404,7 @@ static int write_boot_mem(struct edgeport_serial *serial, static int write_i2c_mem(struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer) { + struct device *dev = &serial->serial->dev->dev; int status = 0; int write_length; __be16 be_start_address; @@ -424,10 +418,9 @@ static int write_i2c_mem(struct edgeport_serial *serial, if (write_length > length) write_length = length; - dbg("%s - BytesInFirstPage Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); + dev_dbg(dev, "%s - BytesInFirstPage Addr = %x, length = %d\n", + __func__, start_address, write_length); + usb_serial_debug_data(dev, __func__, write_length, buffer); /* Write first page */ be_start_address = cpu_to_be16(start_address); @@ -436,7 +429,7 @@ static int write_i2c_mem(struct edgeport_serial *serial, (__force __u16)be_start_address, buffer, write_length); if (status) { - dbg("%s - ERROR %d", __func__, status); + dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status; } @@ -452,10 +445,9 @@ static int write_i2c_mem(struct edgeport_serial *serial, else write_length = length; - dbg("%s - Page Write Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); + dev_dbg(dev, "%s - Page Write Addr = %x, length = %d\n", + __func__, start_address, write_length); + usb_serial_debug_data(dev, __func__, write_length, buffer); /* Write next page */ be_start_address = cpu_to_be16(start_address); @@ -464,8 +456,7 @@ static int write_i2c_mem(struct edgeport_serial *serial, (__force __u16)be_start_address, buffer, write_length); if (status) { - dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n", - __func__, status); + dev_err(dev, "%s - ERROR %d\n", __func__, status); return status; } @@ -508,7 +499,7 @@ static int tx_active(struct edgeport_port *port) if (status) goto exit_is_tx_active; - dbg("%s - XByteCount 0x%X", __func__, oedb->XByteCount); + dev_dbg(&port->port->dev, "%s - XByteCount 0x%X\n", __func__, oedb->XByteCount); /* and the LSR */ status = read_ram(port->port->serial->dev, @@ -516,7 +507,7 @@ static int tx_active(struct edgeport_port *port) if (status) goto exit_is_tx_active; - dbg("%s - LSR = 0x%X", __func__, *lsr); + dev_dbg(&port->port->dev, "%s - LSR = 0x%X\n", __func__, *lsr); /* If either buffer has data or we are transmitting then return TRUE */ if ((oedb->XByteCount & 0x80) != 0) @@ -527,7 +518,7 @@ static int tx_active(struct edgeport_port *port) /* We return Not Active if we get any kind of error */ exit_is_tx_active: - dbg("%s - return %d", __func__, bytes_left); + dev_dbg(&port->port->dev, "%s - return %d\n", __func__, bytes_left); kfree(lsr); kfree(oedb); @@ -599,14 +590,13 @@ static int choose_config(struct usb_device *dev) * configuration # 1, which is Config Descriptor 0. */ - dbg("%s - Number of Interfaces = %d", - __func__, dev->config->desc.bNumInterfaces); - dbg("%s - MAX Power = %d", - __func__, dev->config->desc.bMaxPower * 2); + dev_dbg(&dev->dev, "%s - Number of Interfaces = %d\n", + __func__, dev->config->desc.bNumInterfaces); + dev_dbg(&dev->dev, "%s - MAX Power = %d\n", + __func__, dev->config->desc.bMaxPower * 2); if (dev->config->desc.bNumInterfaces != 1) { - dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", - __func__); + dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __func__); return -ENODEV; } @@ -684,7 +674,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) cs = (__u8)(cs + buffer[i]); if (cs != rom_desc->CheckSum) { - dbg("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); + pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); return -EINVAL; } return 0; @@ -736,11 +726,11 @@ static int check_i2c_image(struct edgeport_serial *serial) if ((start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size) > TI_MAX_I2C_SIZE) { status = -ENODEV; - dbg("%s - structure too big, erroring out.", __func__); + dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__); break; } - dbg("%s Type = 0x%x", __func__, rom_desc->Type); + dev_dbg(dev, "%s Type = 0x%x\n", __func__, rom_desc->Type); /* Skip type 2 record */ ttype = rom_desc->Type & 0x0f; @@ -779,18 +769,18 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) int start_address; struct ti_i2c_desc *rom_desc; struct edge_ti_manuf_descriptor *desc; + struct device *dev = &serial->serial->dev->dev; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); if (!rom_desc) { - dev_err(&serial->serial->dev->dev, "%s - out of memory\n", - __func__); + dev_err(dev, "%s - out of memory\n", __func__); return -ENOMEM; } start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION, rom_desc); if (!start_address) { - dbg("%s - Edge Descriptor not found in I2C", __func__); + dev_dbg(dev, "%s - Edge Descriptor not found in I2C\n", __func__); status = -ENODEV; goto exit; } @@ -804,12 +794,12 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) status = valid_csum(rom_desc, buffer); desc = (struct edge_ti_manuf_descriptor *)buffer; - dbg("%s - IonConfig 0x%x", __func__, desc->IonConfig); - dbg("%s - Version %d", __func__, desc->Version); - dbg("%s - Cpu/Board 0x%x", __func__, desc->CpuRev_BoardRev); - dbg("%s - NumPorts %d", __func__, desc->NumPorts); - dbg("%s - NumVirtualPorts %d", __func__, desc->NumVirtualPorts); - dbg("%s - TotalPorts %d", __func__, desc->TotalPorts); + dev_dbg(dev, "%s - IonConfig 0x%x\n", __func__, desc->IonConfig); + dev_dbg(dev, "%s - Version %d\n", __func__, desc->Version); + dev_dbg(dev, "%s - Cpu/Board 0x%x\n", __func__, desc->CpuRev_BoardRev); + dev_dbg(dev, "%s - NumPorts %d\n", __func__, desc->NumPorts); + dev_dbg(dev, "%s - NumVirtualPorts %d\n", __func__, desc->NumVirtualPorts); + dev_dbg(dev, "%s - TotalPorts %d\n", __func__, desc->TotalPorts); exit: kfree(rom_desc); @@ -855,8 +845,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) err = request_firmware(&fw, fw_name, dev); if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, err); kfree(buffer); return err; } @@ -903,13 +893,13 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) /* Try to figure out what type of I2c we have */ static int i2c_type_bootmode(struct edgeport_serial *serial) { + struct device *dev = &serial->serial->dev->dev; int status; u8 *data; data = kmalloc(1, GFP_KERNEL); if (!data) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); + dev_err(dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -917,11 +907,11 @@ static int i2c_type_bootmode(struct edgeport_serial *serial) status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01); if (status) - dbg("%s - read 2 status error = %d", __func__, status); + dev_dbg(dev, "%s - read 2 status error = %d\n", __func__, status); else - dbg("%s - read 2 data = 0x%x", __func__, *data); + dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_II", __func__); + dev_dbg(dev, "%s - ROM_TYPE_II\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto out; } @@ -930,16 +920,16 @@ static int i2c_type_bootmode(struct edgeport_serial *serial) status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01); if (status) - dbg("%s - read 3 status error = %d", __func__, status); + dev_dbg(dev, "%s - read 3 status error = %d\n", __func__, status); else - dbg("%s - read 2 data = 0x%x", __func__, *data); + dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_III", __func__); + dev_dbg(dev, "%s - ROM_TYPE_III\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; goto out; } - dbg("%s - Unknown", __func__); + dev_dbg(dev, "%s - Unknown\n", __func__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; status = -ENODEV; out: @@ -1050,11 +1040,11 @@ static int download_fw(struct edgeport_serial *serial) if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { struct ti_i2c_desc *rom_desc; - dbg("%s - RUNNING IN DOWNLOAD MODE", __func__); + dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__); status = check_i2c_image(serial); if (status) { - dbg("%s - DOWNLOAD MODE -- BAD I2C", __func__); + dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__); return status; } @@ -1074,7 +1064,7 @@ static int download_fw(struct edgeport_serial *serial) /* Check version number of ION descriptor */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", + dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", __func__, ti_cpu_rev(ti_manuf_desc)); kfree(ti_manuf_desc); return -EINVAL; @@ -1094,8 +1084,7 @@ static int download_fw(struct edgeport_serial *serial) struct ti_i2c_firmware_rec *firmware_version; u8 *record; - dbg("%s - Found Type FIRMWARE (Type 2) record", - __func__); + dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", __func__); firmware_version = kmalloc(sizeof(*firmware_version), GFP_KERNEL); @@ -1127,22 +1116,21 @@ static int download_fw(struct edgeport_serial *serial) download_new_ver = (OperationalMajorVersion << 8) + (OperationalMinorVersion); - dbg("%s - >> FW Versions Device %d.%d Driver %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", + __func__, firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalMajorVersion, + OperationalMinorVersion); /* Check if we have an old version in the I2C and update if necessary */ if (download_cur_ver < download_new_ver) { - dbg("%s - Update I2C dld from %d.%d to %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n", + __func__, + firmware_version->Ver_Major, + firmware_version->Ver_Minor, + OperationalMajorVersion, + OperationalMinorVersion); record = kmalloc(1, GFP_KERNEL); if (!record) { @@ -1196,9 +1184,7 @@ static int download_fw(struct edgeport_serial *serial) } if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) { - dev_err(dev, - "%s - error resetting device\n", - __func__); + dev_err(dev, "%s - error resetting device\n", __func__); kfree(record); kfree(firmware_version); kfree(rom_desc); @@ -1206,15 +1192,14 @@ static int download_fw(struct edgeport_serial *serial) return -ENODEV; } - dbg("%s - HARDWARE RESET", __func__); + dev_dbg(dev, "%s - HARDWARE RESET\n", __func__); /* Reset UMP -- Back to BOOT MODE */ status = ti_vsend_sync(serial->serial->dev, UMPC_HARDWARE_RESET, 0, 0, NULL, 0); - dbg("%s - HARDWARE RESET return %d", - __func__, status); + dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status); /* return an error on purpose. */ kfree(record); @@ -1249,8 +1234,7 @@ static int download_fw(struct edgeport_serial *serial) return -ENOMEM; } - dbg("%s - Found Type BLANK FIRMWARE (Type F2) record", - __func__); + dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", __func__); /* * In order to update the I2C firmware we must change @@ -1292,7 +1276,7 @@ static int download_fw(struct edgeport_serial *serial) HEADER_SIZE, vheader); if (status) { - dbg("%s - can't read header back", __func__); + dev_dbg(dev, "%s - can't read header back\n", __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1300,8 +1284,7 @@ static int download_fw(struct edgeport_serial *serial) return status; } if (memcmp(vheader, header, HEADER_SIZE)) { - dbg("%s - write download record failed", - __func__); + dev_dbg(dev, "%s - write download record failed\n", __func__); kfree(vheader); kfree(header); kfree(rom_desc); @@ -1312,13 +1295,13 @@ static int download_fw(struct edgeport_serial *serial) kfree(vheader); kfree(header); - dbg("%s - Start firmware update", __func__); + dev_dbg(dev, "%s - Start firmware update\n", __func__); /* Tell firmware to copy download image into I2C */ status = ti_vsend_sync(serial->serial->dev, UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); - dbg("%s - Update complete 0x%x", __func__, status); + dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status); if (status) { dev_err(dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", @@ -1338,7 +1321,7 @@ static int download_fw(struct edgeport_serial *serial) /********************************************************************/ /* Boot Mode */ /********************************************************************/ - dbg("%s - RUNNING IN BOOT MODE", __func__); + dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__); /* Configure the TI device so we can use the BULK pipes for download */ status = config_boot_dev(serial->serial->dev); @@ -1347,8 +1330,8 @@ static int download_fw(struct edgeport_serial *serial) if (le16_to_cpu(serial->serial->dev->descriptor.idVendor) != USB_VENDOR_ID_ION) { - dbg("%s - VID = 0x%x", __func__, - le16_to_cpu(serial->serial->dev->descriptor.idVendor)); + dev_dbg(dev, "%s - VID = 0x%x\n", __func__, + le16_to_cpu(serial->serial->dev->descriptor.idVendor)); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto stayinbootmode; } @@ -1385,8 +1368,8 @@ static int download_fw(struct edgeport_serial *serial) /* Check for version 2 */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", - __func__, ti_cpu_rev(ti_manuf_desc)); + dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n", + __func__, ti_cpu_rev(ti_manuf_desc)); kfree(ti_manuf_desc); goto stayinbootmode; } @@ -1421,8 +1404,8 @@ static int download_fw(struct edgeport_serial *serial) err = request_firmware(&fw, fw_name, dev); if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, err); kfree(buffer); return err; } @@ -1442,23 +1425,20 @@ static int download_fw(struct edgeport_serial *serial) header->CheckSum = cs; /* Download the operational code */ - dbg("%s - Downloading operational code image (TI UMP)", - __func__); + dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); status = download_code(serial, buffer, buffer_size); kfree(buffer); if (status) { - dbg("%s - Error downloading operational code image", - __func__); + dev_dbg(dev, "%s - Error downloading operational code image\n", __func__); return status; } /* Device will reboot */ serial->product_info.TiMode = TI_MODE_TRANSITIONING; - dbg("%s - Download successful -- Device rebooting...", - __func__); + dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__); /* return an error on purpose */ return -ENODEV; @@ -1466,7 +1446,7 @@ static int download_fw(struct edgeport_serial *serial) stayinbootmode: /* Eprom is invalid or blank stay in boot mode */ - dbg("%s - STAYING IN BOOT MODE", __func__); + dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__); serial->product_info.TiMode = TI_MODE_BOOT; return 0; @@ -1487,7 +1467,7 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr) { int status = 0; - dbg("%s - %x", __func__, mcr); + dev_dbg(&port->port->dev, "%s - %x\n", __func__, mcr); status = ti_do_config(port, UMPC_SET_CLR_DTR, mcr & MCR_DTR); if (status) @@ -1524,7 +1504,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) struct async_icount *icount; struct tty_struct *tty; - dbg("%s - %02x", __func__, msr); + dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, msr); if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { @@ -1566,7 +1546,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, LSR_FRM_ERR | LSR_BREAK)); struct tty_struct *tty; - dbg("%s - %02x", __func__, new_lsr); + dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr); edge_port->shadow_lsr = lsr; @@ -1604,6 +1584,7 @@ static void edge_interrupt_callback(struct urb *urb) struct edgeport_serial *edge_serial = urb->context; struct usb_serial_port *port; struct edgeport_port *edge_port; + struct device *dev; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; int port_number; @@ -1613,8 +1594,6 @@ static void edge_interrupt_callback(struct urb *urb) __u8 msr; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -1623,7 +1602,7 @@ static void edge_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: @@ -1633,27 +1612,26 @@ static void edge_interrupt_callback(struct urb *urb) } if (!length) { - dbg("%s - no data in urb", __func__); + dev_dbg(&urb->dev->dev, "%s - no data in urb\n", __func__); goto exit; } - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); + dev = &edge_serial->serial->dev->dev; + usb_serial_debug_data(dev, __func__, length, data); if (length != 2) { - dbg("%s - expecting packet of size 2, got %d", - __func__, length); + dev_dbg(dev, "%s - expecting packet of size 2, got %d\n", __func__, length); goto exit; } port_number = TIUMP_GET_PORT_FROM_CODE(data[0]); function = TIUMP_GET_FUNC_FROM_CODE(data[0]); - dbg("%s - port_number %d, function %d, info 0x%x", - __func__, port_number, function, data[1]); + dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__, + port_number, function, data[1]); port = edge_serial->serial->port[port_number]; edge_port = usb_get_serial_port_data(port); if (!edge_port) { - dbg("%s - edge_port not found", __func__); + dev_dbg(dev, "%s - edge_port not found\n", __func__); return; } switch (function) { @@ -1662,13 +1640,13 @@ static void edge_interrupt_callback(struct urb *urb) if (lsr & UMP_UART_LSR_DATA_MASK) { /* Save the LSR event for bulk read completion routine */ - dbg("%s - LSR Event Port %u LSR Status = %02x", - __func__, port_number, lsr); + dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n", + __func__, port_number, lsr); edge_port->lsr_event = 1; edge_port->lsr_mask = lsr; } else { - dbg("%s - ===== Port %d LSR Status = %02x ======", - __func__, port_number, lsr); + dev_dbg(dev, "%s - ===== Port %d LSR Status = %02x ======\n", + __func__, port_number, lsr); handle_new_lsr(edge_port, 0, lsr, 0); } break; @@ -1676,8 +1654,8 @@ static void edge_interrupt_callback(struct urb *urb) case TIUMP_INTERRUPT_CODE_MSR: /* MSR */ /* Copy MSR from UMP */ msr = data[1]; - dbg("%s - ===== Port %u MSR Status = %02x ======", - __func__, port_number, msr); + dev_dbg(dev, "%s - ===== Port %u MSR Status = %02x ======\n", + __func__, port_number, msr); handle_new_msr(edge_port, msr); break; @@ -1700,14 +1678,13 @@ exit: static void edge_bulk_in_callback(struct urb *urb) { struct edgeport_port *edge_port = urb->context; + struct device *dev = &edge_port->port->dev; unsigned char *data = urb->transfer_buffer; struct tty_struct *tty; int retval = 0; int port_number; int status = urb->status; - dbg("%s", __func__); - switch (status) { case 0: /* success */ @@ -1716,13 +1693,10 @@ static void edge_bulk_in_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dev_err(&urb->dev->dev, - "%s - nonzero read bulk status received: %d\n", - __func__, status); + dev_err(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status); } if (status == -EPIPE) @@ -1737,8 +1711,8 @@ static void edge_bulk_in_callback(struct urb *urb) if (edge_port->lsr_event) { edge_port->lsr_event = 0; - dbg("%s ===== Port %u LSR Status = %02x, Data = %02x ======", - __func__, port_number, edge_port->lsr_mask, *data); + dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n", + __func__, port_number, edge_port->lsr_mask, *data); handle_new_lsr(edge_port, 1, edge_port->lsr_mask, *data); /* Adjust buffer length/pointer */ --urb->actual_length; @@ -1747,14 +1721,12 @@ static void edge_bulk_in_callback(struct urb *urb) tty = tty_port_tty_get(&edge_port->port->port); if (tty && urb->actual_length) { - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (edge_port->close_pending) - dbg("%s - close pending, dropping data on the floor", + dev_dbg(dev, "%s - close pending, dropping data on the floor\n", __func__); else - edge_tty_recv(&edge_port->port->dev, tty, data, - urb->actual_length); + edge_tty_recv(dev, tty, data, urb->actual_length); edge_port->icount.rx += urb->actual_length; } tty_kref_put(tty); @@ -1769,9 +1741,7 @@ exit: spin_unlock(&edge_port->ep_lock); if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); + dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } static void edge_tty_recv(struct device *dev, struct tty_struct *tty, @@ -1793,8 +1763,6 @@ static void edge_bulk_out_callback(struct urb *urb) int status = urb->status; struct tty_struct *tty; - dbg("%s - port %d", __func__, port->number); - edge_port->ep_write_urb_in_use = 0; switch (status) { @@ -1805,7 +1773,7 @@ static void edge_bulk_out_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: @@ -1830,8 +1798,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) u16 open_settings; u8 transaction_timeout; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return -ENODEV; @@ -1850,9 +1816,8 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) return -ENODEV; } - dbg("%s - port_number = %d, uart_base = %04x, dma_address = %04x", - __func__, port_number, edge_port->uart_base, - edge_port->dma_address); + dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", + __func__, port_number, edge_port->uart_base, edge_port->dma_address); dev = port->serial->dev; @@ -1885,7 +1850,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) UMP_PIPE_TRANS_TIMEOUT_ENA | (transaction_timeout << 2)); - dbg("%s - Sending UMPC_OPEN_PORT", __func__); + dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__); /* Tell TI to open and start the port */ status = send_cmd(dev, UMPC_OPEN_PORT, @@ -1924,11 +1889,11 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) return status; } - dbg("ShadowMSR 0x%X", edge_port->shadow_msr); + dev_dbg(&port->dev, "ShadowMSR 0x%X\n", edge_port->shadow_msr); /* Set Initial MCR */ edge_port->shadow_mcr = MCR_RTS | MCR_DTR; - dbg("ShadowMCR 0x%X", edge_port->shadow_mcr); + dev_dbg(&port->dev, "ShadowMCR 0x%X\n", edge_port->shadow_mcr); edge_serial = edge_port->edge_serial; if (mutex_lock_interruptible(&edge_serial->es_lock)) @@ -1980,8 +1945,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ++edge_serial->num_ports_open; - dbg("%s - exited", __func__); - goto release_es_lock; unlink_int_urb: @@ -1999,8 +1962,6 @@ static void edge_close(struct usb_serial_port *port) struct usb_serial *serial = port->serial; int port_number; - dbg("%s - port %d", __func__, port->number); - edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); if (edge_serial == NULL || edge_port == NULL) @@ -2019,7 +1980,7 @@ static void edge_close(struct usb_serial_port *port) /* assuming we can still talk to the device, * send a close port command to it */ - dbg("%s - send umpc_close_port", __func__); + dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); port_number = port->number - port->serial->minor; mutex_lock(&serial->disc_mutex); @@ -2042,8 +2003,6 @@ static void edge_close(struct usb_serial_port *port) } mutex_unlock(&edge_serial->es_lock); edge_port->close_pending = 0; - - dbg("%s - exited", __func__); } static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -2051,10 +2010,8 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } @@ -2077,9 +2034,6 @@ static void edge_send(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->ep_write_urb_in_use) { @@ -2100,8 +2054,7 @@ static void edge_send(struct tty_struct *tty) spin_unlock_irqrestore(&edge_port->ep_lock, flags); - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, port->write_urb->transfer_buffer); /* set up our urb */ port->write_urb->transfer_buffer_length = count; @@ -2130,8 +2083,6 @@ static int edge_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return 0; if (edge_port->close_pending == 1) @@ -2141,7 +2092,7 @@ static int edge_write_room(struct tty_struct *tty) room = kfifo_avail(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -2152,8 +2103,6 @@ static int edge_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return 0; if (edge_port->close_pending == 1) @@ -2163,7 +2112,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -2173,8 +2122,6 @@ static void edge_throttle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; @@ -2200,8 +2147,6 @@ static void edge_unthrottle(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (edge_port == NULL) return; @@ -2261,6 +2206,7 @@ static int restart_read(struct edgeport_port *edge_port) static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct device *dev = &edge_port->port->dev; struct ump_uart_config *config; int baud; unsigned cflag; @@ -2268,13 +2214,12 @@ static void change_port_settings(struct tty_struct *tty, int port_number = edge_port->port->number - edge_port->port->serial->minor; - dbg("%s - port %d", __func__, edge_port->port->number); + dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number); config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { tty->termios = *old_termios; - dev_err(&edge_port->port->dev, "%s - out of memory\n", - __func__); + dev_err(dev, "%s - out of memory\n", __func__); return; } @@ -2290,20 +2235,20 @@ static void change_port_settings(struct tty_struct *tty, switch (cflag & CSIZE) { case CS5: config->bDataBits = UMP_UART_CHAR5BITS; - dbg("%s - data bits = 5", __func__); + dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6: config->bDataBits = UMP_UART_CHAR6BITS; - dbg("%s - data bits = 6", __func__); + dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7: config->bDataBits = UMP_UART_CHAR7BITS; - dbg("%s - data bits = 7", __func__); + dev_dbg(dev, "%s - data bits = 7\n", __func__); break; default: case CS8: config->bDataBits = UMP_UART_CHAR8BITS; - dbg("%s - data bits = 8", __func__); + dev_dbg(dev, "%s - data bits = 8\n", __func__); break; } @@ -2311,32 +2256,32 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & PARODD) { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_ODDPARITY; - dbg("%s - parity = odd", __func__); + dev_dbg(dev, "%s - parity = odd\n", __func__); } else { config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; config->bParity = UMP_UART_EVENPARITY; - dbg("%s - parity = even", __func__); + dev_dbg(dev, "%s - parity = even\n", __func__); } } else { config->bParity = UMP_UART_NOPARITY; - dbg("%s - parity = none", __func__); + dev_dbg(dev, "%s - parity = none\n", __func__); } if (cflag & CSTOPB) { config->bStopBits = UMP_UART_STOPBIT2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(dev, "%s - stop bits = 2\n", __func__); } else { config->bStopBits = UMP_UART_STOPBIT1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(dev, "%s - stop bits = 1\n", __func__); } /* figure out the flow control settings */ if (cflag & CRTSCTS) { config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW; config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW; - dbg("%s - RTS/CTS is enabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__); } else { - dbg("%s - RTS/CTS is disabled", __func__); + dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__); tty->hw_stopped = 0; restart_read(edge_port); } @@ -2349,18 +2294,18 @@ static void change_port_settings(struct tty_struct *tty, /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { config->wFlags |= UMP_MASK_UART_FLAGS_IN_X; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); + dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, config->cXon, config->cXoff); } else - dbg("%s - INBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__); /* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) { config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n", + __func__, config->cXon, config->cXoff); } else - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); + dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__); tty->termios.c_cflag &= ~CMSPAR; @@ -2377,17 +2322,16 @@ static void change_port_settings(struct tty_struct *tty, /* FIXME: Recompute actual baud from divisor here */ - dbg("%s - baud rate = %d, wBaudRate = %d", __func__, baud, - config->wBaudRate); + dev_dbg(dev, "%s - baud rate = %d, wBaudRate = %d\n", __func__, baud, config->wBaudRate); - dbg("wBaudRate: %d", (int)(461550L / config->wBaudRate)); - dbg("wFlags: 0x%x", config->wFlags); - dbg("bDataBits: %d", config->bDataBits); - dbg("bParity: %d", config->bParity); - dbg("bStopBits: %d", config->bStopBits); - dbg("cXon: %d", config->cXon); - dbg("cXoff: %d", config->cXoff); - dbg("bUartMode: %d", config->bUartMode); + dev_dbg(dev, "wBaudRate: %d\n", (int)(461550L / config->wBaudRate)); + dev_dbg(dev, "wFlags: 0x%x\n", config->wFlags); + dev_dbg(dev, "bDataBits: %d\n", config->bDataBits); + dev_dbg(dev, "bParity: %d\n", config->bParity); + dev_dbg(dev, "bStopBits: %d\n", config->bStopBits); + dev_dbg(dev, "cXon: %d\n", config->cXon); + dev_dbg(dev, "cXoff: %d\n", config->cXoff); + dev_dbg(dev, "bUartMode: %d\n", config->bUartMode); /* move the word values into big endian mode */ cpu_to_be16s(&config->wFlags); @@ -2397,8 +2341,8 @@ static void change_port_settings(struct tty_struct *tty, (__u8)(UMPM_UART1_PORT + port_number), 0, (__u8 *)config, sizeof(*config)); if (status) - dbg("%s - error %d when trying to write config to device", - __func__, status); + dev_dbg(dev, "%s - error %d when trying to write config to device\n", + __func__, status); kfree(config); } @@ -2410,11 +2354,11 @@ static void edge_set_termios(struct tty_struct *tty, cflag = tty->termios.c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios.c_cflag, tty->termios.c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, tty->termios.c_iflag); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, old_termios->c_iflag); + dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); if (edge_port == NULL) return; @@ -2430,8 +2374,6 @@ static int edge_tiocmset(struct tty_struct *tty, unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); mcr = edge_port->shadow_mcr; if (set & TIOCM_RTS) @@ -2464,8 +2406,6 @@ static int edge_tiocmget(struct tty_struct *tty) unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&edge_port->ep_lock, flags); msr = edge_port->shadow_msr; @@ -2478,7 +2418,7 @@ static int edge_tiocmget(struct tty_struct *tty) | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - dbg("%s -- %x", __func__, result); + dev_dbg(&port->dev, "%s -- %x\n", __func__, result); spin_unlock_irqrestore(&edge_port->ep_lock, flags); return result; @@ -2538,15 +2478,15 @@ static int edge_ioctl(struct tty_struct *tty, struct async_icount cnow; struct async_icount cprev; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return get_serial_info(edge_port, (struct serial_struct __user *) arg); case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); cprev = edge_port->icount; while (1) { interruptible_sleep_on(&edge_port->delta_msr_wait); @@ -2578,8 +2518,6 @@ static void edge_break(struct tty_struct *tty, int break_state) int status; int bv = 0; /* Off */ - dbg("%s - state = %d", __func__, break_state); - /* chase the port close */ chase_port(edge_port, 0, 0); @@ -2587,8 +2525,8 @@ static void edge_break(struct tty_struct *tty, int break_state) bv = 1; /* On */ status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); if (status) - dbg("%s - error %d sending break set/clear command.", - __func__, status); + dev_dbg(&port->dev, "%s - error %d sending break set/clear command.\n", + __func__, status); } static int edge_startup(struct usb_serial *serial) @@ -2655,7 +2593,6 @@ cleanup: static void edge_disconnect(struct usb_serial *serial) { - dbg("%s", __func__); } static void edge_release(struct usb_serial *serial) @@ -2663,8 +2600,6 @@ static void edge_release(struct usb_serial *serial) int i; struct edgeport_port *edge_port; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { edge_port = usb_get_serial_port_data(serial->port[i]); kfifo_free(&edge_port->write_fifo); @@ -2692,7 +2627,7 @@ static ssize_t store_uart_mode(struct device *dev, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int v = simple_strtoul(valbuf, NULL, 0); - dbg("%s: setting uart_mode = %d", __func__, v); + dev_dbg(dev, "%s: setting uart_mode = %d\n", __func__, v); if (v < 256) edge_port->bUartMode = v; @@ -2789,9 +2724,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("edgeport/down3.bin"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c85a7eb..1068bf2 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -33,7 +33,6 @@ #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" -static bool debug; static int connect_retries = KP_RETRIES; static int initial_wait; @@ -616,9 +615,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(connect_retries, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)"); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 2cb30c5..20a132e 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -138,11 +138,10 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static bool debug; - static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT; u8 *buf_flow_init; int result; @@ -154,8 +153,8 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) /* --1: Tell the modem to initialize (we think) From sniffs this is * always the first thing that gets sent to the modem during * opening of the device */ - dbg("%s: Sending SIO_INIT (we guess)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s: Sending SIO_INIT (we guess)\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_INIT, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0, @@ -164,22 +163,19 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0, 100000); if (result < 0) - dev_err(&port->dev, - "Init of modem failed (error = %d)\n", result); + dev_err(dev, "Init of modem failed (error = %d)\n", result); /* reset the bulk pipes */ - usb_clear_halt(dev, - usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress)); - usb_clear_halt(dev, - usb_sndbulkpipe(dev, port->bulk_out_endpointAddress)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, port->bulk_in_endpointAddress)); + usb_clear_halt(udev, usb_sndbulkpipe(udev, port->bulk_out_endpointAddress)); /*--2: Start reading from the device */ - dbg("%s: setting up bulk read callback", __func__); + dev_dbg(dev, "%s: setting up bulk read callback\n", __func__); usb_wwan_open(tty, port); /*--3: Tell the modem to open the floodgates on the rx bulk channel */ - dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:asking modem for RxRead (RXBULK_ON)\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_RXCTL, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, IPW_RXBULK_ON, @@ -188,12 +184,11 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0, 100000); if (result < 0) - dev_err(&port->dev, - "Enabling bulk RxRead failed (error = %d)\n", result); + dev_err(dev, "Enabling bulk RxRead failed (error = %d)\n", result); /*--4: setup the initial flowcontrol */ - dbg("%s:setting init flowcontrol (%s)", __func__, buf_flow_init); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:setting init flowcontrol (%s)\n", __func__, buf_flow_init); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_HANDFLOW, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0, @@ -202,8 +197,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) 0x10, 200000); if (result < 0) - dev_err(&port->dev, - "initial flowcontrol failed (error = %d)\n", result); + dev_err(dev, "initial flowcontrol failed (error = %d)\n", result); kfree(buf_flow_init); return 0; @@ -233,12 +227,13 @@ static void ipw_release(struct usb_serial *serial) static void ipw_dtr_rts(struct usb_serial_port *port, int on) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; int result; - dbg("%s: on = %d", __func__, on); + dev_dbg(dev, "%s: on = %d\n", __func__, on); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR, @@ -247,10 +242,9 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) 0, 200000); if (result < 0) - dev_err(&port->dev, "setting dtr failed (error = %d)\n", - result); + dev_err(dev, "setting dtr failed (error = %d)\n", result); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS, @@ -259,18 +253,18 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) 0, 200000); if (result < 0) - dev_err(&port->dev, "setting rts failed (error = %d)\n", - result); + dev_err(dev, "setting rts failed (error = %d)\n", result); } static void ipw_close(struct usb_serial_port *port) { - struct usb_device *dev = port->serial->dev; + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; int result; /*--3: purge */ - dbg("%s:sending purge", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + dev_dbg(dev, "%s:sending purge\n", __func__); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_PURGE, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 0x03, @@ -279,12 +273,12 @@ static void ipw_close(struct usb_serial_port *port) 0, 200000); if (result < 0) - dev_err(&port->dev, "purge failed (error = %d)\n", result); + dev_err(dev, "purge failed (error = %d)\n", result); /* send RXBULK_off (tell modem to stop transmitting bulk data on rx chan) */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), IPW_SIO_RXCTL, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, IPW_RXBULK_OFF, @@ -294,8 +288,7 @@ static void ipw_close(struct usb_serial_port *port) 100000); if (result < 0) - dev_err(&port->dev, - "Disabling bulk RxRead failed (error = %d)\n", result); + dev_err(dev, "Disabling bulk RxRead failed (error = %d)\n", result); usb_wwan_close(port); } @@ -328,6 +321,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 5a96692..e24e2d4 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -38,15 +38,9 @@ #include <linux/usb/serial.h> #include <linux/usb/irda.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB IR Dongle driver" -static bool debug; - /* if overridden by the user, then use their value for the size of the read and * write urbs */ static int buffer_size; @@ -430,18 +424,12 @@ err_buf: static int __init ir_init(void) { - int retval; - if (buffer_size) { ir_device.bulk_in_size = buffer_size; ir_device.bulk_out_size = buffer_size; } - retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table); } static void __exit ir_exit(void) @@ -457,8 +445,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(xbof, int, 0); MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); module_param(buffer_size, int, 0); diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index bf38640..01da3ea 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -32,13 +32,6 @@ #include "iuu_phoenix.h" #include <linux/random.h> - -#ifdef CONFIG_USB_SERIAL_DEBUG -static bool debug = 1; -#else -static bool debug; -#endif - /* * Version Information */ @@ -72,7 +65,6 @@ struct iuu_private { u8 *writebuf; /* buffer for writing to device */ int writelen; /* num of byte to write to device */ u8 *buf; /* used for initialize speed */ - u8 *dbgbuf; /* debug buffer */ u8 len; int vcc; /* vcc (either 3 or 5 V) */ u32 baud; @@ -84,32 +76,31 @@ struct iuu_private { static void iuu_free_buf(struct iuu_private *priv) { kfree(priv->buf); - kfree(priv->dbgbuf); kfree(priv->writebuf); } -static int iuu_alloc_buf(struct iuu_private *priv) +static int iuu_alloc_buf(struct usb_serial *serial, struct iuu_private *priv) { priv->buf = kzalloc(256, GFP_KERNEL); - priv->dbgbuf = kzalloc(256, GFP_KERNEL); priv->writebuf = kzalloc(256, GFP_KERNEL); - if (!priv->buf || !priv->dbgbuf || !priv->writebuf) { + if (!priv->buf || !priv->writebuf) { iuu_free_buf(priv); - dbg("%s problem allocation buffer", __func__); + dev_dbg(&serial->dev->dev, "%s problem allocation buffer\n", __func__); return -ENOMEM; } - dbg("%s - Privates buffers allocation success", __func__); + dev_dbg(&serial->dev->dev, "%s - Privates buffers allocation success\n", __func__); return 0; } static int iuu_startup(struct usb_serial *serial) { struct iuu_private *priv; + priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); - dbg("%s- priv allocation success", __func__); + dev_dbg(&serial->dev->dev, "%s- priv allocation success\n", __func__); if (!priv) return -ENOMEM; - if (iuu_alloc_buf(priv)) { + if (iuu_alloc_buf(serial, priv)) { kfree(priv); return -ENOMEM; } @@ -130,13 +121,13 @@ static void iuu_release(struct usb_serial *serial) if (priv) { iuu_free_buf(priv); - dbg("%s - I will free all", __func__); + dev_dbg(&port->dev, "%s - I will free all\n", __func__); usb_set_serial_port_data(port, NULL); - dbg("%s - priv is not anymore in port structure", __func__); + dev_dbg(&port->dev, "%s - priv is not anymore in port structure\n", __func__); kfree(priv); - dbg("%s priv is now kfree", __func__); + dev_dbg(&port->dev, "%s priv is now kfree\n", __func__); } } @@ -148,13 +139,13 @@ static int iuu_tiocmset(struct tty_struct *tty, unsigned long flags; /* FIXME: locking on tiomstatus */ - dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __func__, - port->number, set, clear); + dev_dbg(&port->dev, "%s msg : SET = 0x%04x, CLEAR = 0x%04x\n", + __func__, set, clear); spin_lock_irqsave(&priv->lock, flags); if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) { - dbg("%s TIOCMSET RESET called !!!", __func__); + dev_dbg(&port->dev, "%s TIOCMSET RESET called !!!\n", __func__); priv->reset = 1; } if (set & TIOCM_RTS) @@ -190,7 +181,7 @@ static void iuu_rxcmd(struct urb *urb) int status = urb->status; if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } @@ -244,13 +235,13 @@ static void iuu_update_status_callback(struct urb *urb) int status = urb->status; if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } st = urb->transfer_buffer; - dbg("%s - enter", __func__); + dev_dbg(&port->dev, "%s - enter\n", __func__); if (urb->actual_length == 1) { switch (st[0]) { case 0x1: @@ -272,7 +263,7 @@ static void iuu_status_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), @@ -311,9 +302,9 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) count, &actual, HZ * 1); if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); + dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); else - dbg("%s - write OK !", __func__); + dev_dbg(&port->dev, "%s - write OK !\n", __func__); return status; } @@ -331,9 +322,9 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) count, &actual, HZ * 1); if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); + dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); else - dbg("%s - read OK !", __func__); + dev_dbg(&port->dev, "%s - read OK !\n", __func__); return status; } @@ -357,9 +348,9 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R, status = bulk_immediate(port, buf, 8); kfree(buf); if (status != IUU_OPERATION_OK) - dbg("%s - led error status = %2x", __func__, status); + dev_dbg(&port->dev, "%s - led error status = %2x\n", __func__, status); else - dbg("%s - led OK !", __func__); + dev_dbg(&port->dev, "%s - led OK !\n", __func__); return IUU_OPERATION_OK; } @@ -445,7 +436,7 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) status = bulk_immediate(port, (u8 *) priv->buf, Count); if (status != 0) { - dbg("%s - write error ", __func__); + dev_dbg(&port->dev, "%s - write error\n", __func__); return status; } } else if (frq == 3579000) { @@ -554,12 +545,13 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) status = bulk_immediate(port, (u8 *) priv->buf, Count); if (status != IUU_OPERATION_OK) - dbg("%s - write error ", __func__); + dev_dbg(&port->dev, "%s - write error\n", __func__); return status; } static int iuu_uart_flush(struct usb_serial_port *port) { + struct device *dev = &port->dev; int i; int status; u8 rxcmd = IUU_UART_RX; @@ -571,27 +563,26 @@ static int iuu_uart_flush(struct usb_serial_port *port) for (i = 0; i < 2; i++) { status = bulk_immediate(port, &rxcmd, 1); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_write error", __func__); + dev_dbg(dev, "%s - uart_flush_write error\n", __func__); return status; } status = read_immediate(port, &priv->len, 1); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); + dev_dbg(dev, "%s - uart_flush_read error\n", __func__); return status; } if (priv->len > 0) { - dbg("%s - uart_flush datalen is : %i ", __func__, - priv->len); + dev_dbg(dev, "%s - uart_flush datalen is : %i\n", __func__, priv->len); status = read_immediate(port, priv->buf, priv->len); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); + dev_dbg(dev, "%s - uart_flush_read error\n", __func__); return status; } } } - dbg("%s - uart_flush_read OK!", __func__); + dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__); iuu_led(port, 0, 0xF000, 0, 0xFF); return status; } @@ -610,10 +601,10 @@ static void read_buf_callback(struct urb *urb) return; } - dbg("%s - %i chars to write", __func__, urb->actual_length); + dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length); tty = tty_port_tty_get(&port->port); if (data == NULL) - dbg("%s - data is NULL !!!", __func__); + dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); if (tty && urb->actual_length && data) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); @@ -627,7 +618,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result; - int i; int buf_len; char *buf_ptr = port->write_urb->transfer_buffer; @@ -640,14 +630,8 @@ static int iuu_bulk_write(struct usb_serial_port *port) buf_len = priv->writelen; priv->writelen = 0; spin_unlock_irqrestore(&priv->lock, flags); - if (debug == 1) { - for (i = 0; i < buf_len; i++) - sprintf(priv->dbgbuf + i*2 , - "%02X", priv->writebuf[i]); - priv->dbgbuf[buf_len+i*2] = 0; - dbg("%s - writing %i chars : %s", __func__, - buf_len, priv->dbgbuf); - } + dev_dbg(&port->dev, "%s - writing %i chars : %*ph\n", __func__, + buf_len, buf_len, buf_ptr); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), @@ -683,18 +667,18 @@ static void iuu_uart_read_callback(struct urb *urb) priv->poll++; if (status) { - dbg("%s - status = %d", __func__, status); + dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); /* error stop all */ return; } if (data == NULL) - dbg("%s - data is NULL !!!", __func__); + dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); if (urb->actual_length == 1 && data != NULL) len = (int) data[0]; if (urb->actual_length > 1) { - dbg("%s - urb->actual_length = %i", __func__, + dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__, urb->actual_length); error = 1; return; @@ -702,7 +686,7 @@ static void iuu_uart_read_callback(struct urb *urb) /* if len > 0 call readbuf */ if (len > 0 && error == 0) { - dbg("%s - call read buf - len to read is %i ", + dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n", __func__, len); status = iuu_read_buf(port, len); return; @@ -729,7 +713,7 @@ static void iuu_uart_read_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); /* if nothing to write call again rxcmd */ - dbg("%s - rxcmd recall", __func__); + dev_dbg(&port->dev, "%s - rxcmd recall\n", __func__); iuu_led_activity_off(urb); } @@ -769,7 +753,7 @@ static void read_rxcmd_callback(struct urb *urb) port->read_urb->transfer_buffer, 256, iuu_uart_read_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - dbg("%s - submit result = %d", __func__, result); + dev_dbg(&port->dev, "%s - submit result = %d\n", __func__, result); } static int iuu_uart_on(struct usb_serial_port *port) @@ -789,13 +773,13 @@ static int iuu_uart_on(struct usb_serial_port *port) status = bulk_immediate(port, buf, 4); if (status != IUU_OPERATION_OK) { - dbg("%s - uart_on error", __func__); + dev_dbg(&port->dev, "%s - uart_on error\n", __func__); goto uart_enable_failed; } /* iuu_reset() the card after iuu_uart_on() */ status = iuu_uart_flush(port); if (status != IUU_OPERATION_OK) - dbg("%s - uart_flush error", __func__); + dev_dbg(&port->dev, "%s - uart_flush error\n", __func__); uart_enable_failed: kfree(buf); return status; @@ -813,7 +797,7 @@ static int iuu_uart_off(struct usb_serial_port *port) status = bulk_immediate(port, buf, 1); if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); + dev_dbg(&port->dev, "%s - uart_off error\n", __func__); kfree(buf); return status; @@ -830,7 +814,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, u8 T1reload = 0; unsigned int T1FrekvensHZ = 0; - dbg("%s - enter baud_base=%d", __func__, baud_base); + dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base); dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); if (!dataout) @@ -911,7 +895,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, status = bulk_immediate(port, dataout, DataCount); if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); + dev_dbg(&port->dev, "%s - uart_off error\n", __func__); kfree(dataout); return status; } @@ -932,7 +916,7 @@ static void iuu_set_termios(struct tty_struct *tty, /* Just use the ospeed. ispeed should be the same. */ baud = tty->termios.c_ospeed; - dbg("%s - enter c_ospeed or baud=%d", __func__, baud); + dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud); /* compute the parity parameter */ parity = 0; @@ -983,7 +967,7 @@ static void iuu_close(struct usb_serial_port *port) if (serial->dev) { /* free writebuf */ /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); + dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); @@ -1006,6 +990,7 @@ static void iuu_init_termios(struct tty_struct *tty) static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + struct device *dev = &port->dev; u8 *buf; int result; int baud; @@ -1017,7 +1002,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) /* Re-encode speed */ tty_encode_baud_rate(tty, baud, baud); - dbg("%s - port %d, baud %d", __func__, port->number, baud); + dev_dbg(dev, "%s - baud %d\n", __func__, baud); usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -1032,14 +1017,14 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_control_msg(port->serial->dev, \ usb_rcvctrlpipe(port->serial->dev, 0), \ b, a, c, d, buf, 1, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \ + dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \ buf[0]); } while (0); #define SOUP(a, b, c, d) do { \ result = usb_control_msg(port->serial->dev, \ usb_sndctrlpipe(port->serial->dev, 0), \ b, a, c, d, NULL, 0, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0) + dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d\n", a, b, c, d, result); } while (0) /* This is not UART related but IUU USB driver related or something */ /* like that. Basically no IUU will accept any commands from the USB */ @@ -1119,7 +1104,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) iuu_uart_flush(port); - dbg("%s - initialization done", __func__); + dev_dbg(dev, "%s - initialization done\n", __func__); memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); usb_fill_bulk_urb(port->write_urb, port->serial->dev, @@ -1129,11 +1114,10 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) read_rxcmd_callback, port); result = usb_submit_urb(port->write_urb, GFP_KERNEL); if (result) { - dev_err(&port->dev, "%s - failed submitting read urb," - " error %d\n", __func__, result); + dev_err(dev, "%s - failed submitting read urb, error %d\n", __func__, result); iuu_close(port); } else { - dbg("%s - rxcmd OK", __func__); + dev_dbg(dev, "%s - rxcmd OK\n", __func__); } return result; @@ -1159,9 +1143,9 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) kfree(buf); if (status != IUU_OPERATION_OK) - dbg("%s - vcc error status = %2x", __func__, status); + dev_dbg(&port->dev, "%s - vcc error status = %2x\n", __func__, status); else - dbg("%s - vcc OK !", __func__); + dev_dbg(&port->dev, "%s - vcc OK !\n", __func__); return status; } @@ -1192,7 +1176,7 @@ static ssize_t store_vcc_mode(struct device *dev, goto fail_store_vcc_mode; } - dbg("%s: setting vcc_mode = %ld", __func__, v); + dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v); if ((v != 3) && (v != 5)) { dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v); @@ -1257,8 +1241,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); module_param(xmas, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(xmas, "Xmas colors enabled or not"); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7bcbb47..29c943d 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -38,15 +38,12 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/firmware.h> -#include <linux/ihex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/usb/ezusb.h> #include "keyspan.h" -static bool debug; - /* * Version Information */ @@ -165,7 +162,7 @@ static void keyspan_set_termios(struct tty_struct *tty, so other rates can be generated if desired. */ baud_rate = tty_get_baud_rate(tty); /* If no match or invalid, don't change */ - if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk, + if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { /* FIXME - more to do here to ensure rate changes cleanly */ /* FIXME - calcuate exact rate from divisor ? */ @@ -241,8 +238,8 @@ static int keyspan_write(struct tty_struct *tty, dataOffset = 1; } - dbg("%s - for port %d (%d chars), flip=%d", - __func__, port->number, count, p_priv->out_flip); + dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n", + __func__, port->number, count, p_priv->out_flip); for (left = count; left > 0; left -= todo) { todo = left; @@ -255,11 +252,11 @@ static int keyspan_write(struct tty_struct *tty, this_urb = p_priv->out_urbs[flip]; if (this_urb == NULL) { /* no bulk out, so return 0 bytes written */ - dbg("%s - no output urb :(", __func__); + dev_dbg(&port->dev, "%s - no output urb :(\n", __func__); return count; } - dbg("%s - endpoint %d flip %d", + dev_dbg(&port->dev, "%s - endpoint %d flip %d\n", __func__, usb_pipeendpoint(this_urb->pipe), flip); if (this_urb->status == -EINPROGRESS) { @@ -282,7 +279,7 @@ static int keyspan_write(struct tty_struct *tty, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("usb_submit_urb(write bulk) failed (%d)", err); + dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err); p_priv->tx_start_time[flip] = jiffies; /* Flip for next time if usa26 or usa28 interface @@ -305,8 +302,8 @@ static void usa26_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, endpoint); + dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n", + __func__, status, endpoint); return; } @@ -325,7 +322,7 @@ static void usa26_indat_callback(struct urb *urb) tty_insert_flip_char(tty, data[i], err); } else { /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); + dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { int stat = data[i], flag = 0; if (stat & RXERROR_OVERRUN) @@ -345,7 +342,7 @@ static void usa26_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } /* Outdat handling is common for all devices */ @@ -356,7 +353,7 @@ static void usa2x_outdat_callback(struct urb *urb) port = urb->context; p_priv = usb_get_serial_port_data(port); - dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]); + dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]); usb_serial_port_softint(port); } @@ -374,7 +371,7 @@ static void usa26_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa26_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -394,20 +391,22 @@ static void usa26_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != 9) { - dbg("%s - %d byte report??", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); goto exit; } msg = (struct keyspan_usa26_portStatusMessage *)data; #if 0 - dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", - __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff, - msg->_txXoff, msg->rxEnabled, msg->controlResponse); + dev_dbg(&urb->dev->dev, + "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", + __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, + msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled, + msg->controlResponse); #endif /* Now do something useful with the data */ @@ -415,7 +414,7 @@ static void usa26_instat_callback(struct urb *urb) /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); goto exit; } port = serial->port[msg->port]; @@ -438,7 +437,7 @@ static void usa26_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } @@ -465,8 +464,8 @@ static void usa28_indat_callback(struct urb *urb) do { if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, usb_pipeendpoint(urb->pipe)); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + __func__, status, usb_pipeendpoint(urb->pipe)); return; } @@ -484,7 +483,7 @@ static void usa28_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); p_priv->in_flip ^= 1; @@ -505,7 +504,7 @@ static void usa28_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa28_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -526,25 +525,28 @@ static void usa28_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); goto exit; } - /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__ - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10], data[11]);*/ + /* + dev_dbg(&urb->dev->dev, + "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__, + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10], data[11]); + */ /* Now do something useful with the data */ msg = (struct keyspan_usa28_portStatusMessage *)data; /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); goto exit; } port = serial->port[msg->port]; @@ -567,7 +569,7 @@ static void usa28_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } @@ -589,7 +591,7 @@ static void usa49_glocont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa49_send_setup(serial, port, p_priv->resend_cont - 1); break; @@ -613,27 +615,29 @@ static void usa49_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); goto exit; } - /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__, - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10]);*/ + /* + dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x", + __func__, data[0], data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], data[9], data[10]); + */ /* Now do something useful with the data */ msg = (struct keyspan_usa49_portStatusMessage *)data; /* Check port number from message and retrieve private data */ if (msg->portNumber >= serial->num_ports) { - dbg("%s - Unexpected port number %d", - __func__, msg->portNumber); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", + __func__, msg->portNumber); goto exit; } port = serial->port[msg->portNumber]; @@ -656,7 +660,7 @@ static void usa49_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } @@ -676,8 +680,8 @@ static void usa49_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", __func__, - status, endpoint); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + __func__, status, endpoint); return; } @@ -710,7 +714,7 @@ static void usa49_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } static void usa49wg_indat_callback(struct urb *urb) @@ -725,7 +729,7 @@ static void usa49wg_indat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } @@ -738,7 +742,7 @@ static void usa49wg_indat_callback(struct urb *urb) /* Check port number from message*/ if (data[i] >= serial->num_ports) { - dbg("%s - Unexpected port number %d", + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, data[i]); return; } @@ -778,7 +782,7 @@ static void usa49wg_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } /* not used, usa-49 doesn't have per-port control endpoints */ @@ -799,7 +803,7 @@ static void usa90_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", __func__, status, endpoint); return; } @@ -828,7 +832,7 @@ static void usa90_indat_callback(struct urb *urb) err); } else { /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); + dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); for (i = 0; i + 1 < urb->actual_length; i += 2) { int stat = data[i], flag = 0; if (stat & RXERROR_OVERRUN) @@ -850,7 +854,7 @@ static void usa90_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } @@ -868,11 +872,11 @@ static void usa90_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length < 14) { - dbg("%s - %d byte report??", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); goto exit; } @@ -900,7 +904,7 @@ static void usa90_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); exit: ; } @@ -914,7 +918,7 @@ static void usa90_outcont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__); keyspan_usa90_send_setup(port->serial, port, p_priv->resend_cont - 1); } @@ -935,13 +939,13 @@ static void usa67_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dbg("%s - nonzero status: %x", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); return; } if (urb->actual_length != sizeof(struct keyspan_usa67_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); + dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); return; } @@ -951,7 +955,7 @@ static void usa67_instat_callback(struct urb *urb) /* Check port number from message and retrieve private data */ if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); return; } @@ -973,7 +977,7 @@ static void usa67_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); + dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); } static void usa67_glocont_callback(struct urb *urb) @@ -989,7 +993,7 @@ static void usa67_glocont_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); + dev_dbg(&port->dev, "%s - sending setup\n", __func__); keyspan_usa67_send_setup(serial, port, p_priv->resend_cont - 1); break; @@ -1068,8 +1072,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(urb->dev, urb->pipe); err = usb_submit_urb(urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit urb %d failed (%d)", - __func__, i, err); + dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err); } /* Reset low level data toggle on out endpoints */ @@ -1092,7 +1095,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) baud_rate = tty_get_baud_rate(tty); /* If no match or invalid, leave as default */ if (baud_rate >= 0 - && d_details->calculate_baud_rate(baud_rate, d_details->baudclk, + && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { p_priv->baud = baud_rate; } @@ -1142,7 +1145,7 @@ static void keyspan_close(struct usb_serial_port *port) } /*while (p_priv->outcont_urb->status == -EINPROGRESS) { - dbg("%s - urb in progress", __func__); + dev_dbg(&port->dev, "%s - urb in progress\n", __func__); }*/ p_priv->out_flip = 0; @@ -1162,18 +1165,15 @@ static void keyspan_close(struct usb_serial_port *port) /* download the firmware to a pre-renumeration device */ static int keyspan_fake_startup(struct usb_serial *serial) { - int response; - const struct ihex_binrec *record; - char *fw_name; - const struct firmware *fw; + char *fw_name; - dbg("Keyspan startup version %04x product %04x", - le16_to_cpu(serial->dev->descriptor.bcdDevice), - le16_to_cpu(serial->dev->descriptor.idProduct)); + dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n", + le16_to_cpu(serial->dev->descriptor.bcdDevice), + le16_to_cpu(serial->dev->descriptor.idProduct)); if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000) != 0x8000) { - dbg("Firmware already loaded. Quitting."); + dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n"); return 1; } @@ -1233,34 +1233,16 @@ static int keyspan_fake_startup(struct usb_serial *serial) return 1; } - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { - dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name); - return 1; - } - - dbg("Uploading Keyspan %s firmware.", fw_name); + dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name); - /* download the firmware image */ - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)fw->data; - - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); + if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { + dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", + fw_name); + return -ENOENT; } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a - moment and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); + + /* after downloading firmware Renumeration will occur in a + moment and the new device will bind to the real driver */ /* we don't want this device to have a driver assigned to it. */ return 1; @@ -1296,10 +1278,10 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, if (endpoint == -1) return NULL; /* endpoint not needed */ - dbg("%s - alloc for endpoint %d.", __func__, endpoint); + dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint); urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ if (urb == NULL) { - dbg("%s - alloc for endpoint %d failed.", __func__, endpoint); + dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint); return NULL; } @@ -1332,7 +1314,7 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, return NULL; } - dbg("%s - using urb %p for %s endpoint %x", + dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n", __func__, urb, ep_type_name, endpoint); return urb; } @@ -1464,14 +1446,15 @@ static void keyspan_setup_urbs(struct usb_serial *serial) } /* usa19 function doesn't require prescaler */ -static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, +static int keyspan_usa19_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div, /* divisor */ cnt; /* inverse of divisor (programmed into 8051) */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero... */ b16 = baud_rate * 16L; @@ -1498,19 +1481,20 @@ static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, if (rate_hi) *rate_hi = (u8) ((cnt >> 8) & 0xff); if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", + dev_dbg(&port->dev, "%s - %d %02x %02x.\n", __func__, baud_rate, *rate_hi, *rate_low); return KEYSPAN_BAUD_RATE_OK; } /* usa19hs function doesn't require prescaler */ -static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) +static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, + u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div; /* divisor */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero... */ b16 = baud_rate * 16L; @@ -1533,13 +1517,14 @@ static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_hi = (u8) ((div >> 8) & 0xff); if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", + dev_dbg(&port->dev, "%s - %d %02x %02x.\n", __func__, baud_rate, *rate_hi, *rate_low); return KEYSPAN_BAUD_RATE_OK; } -static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, +static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ @@ -1551,7 +1536,7 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 best_prescaler; int i; - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero */ b16 = baud_rate * 16L; @@ -1596,20 +1581,21 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_hi = (u8) ((div >> 8) & 0xff); if (prescaler) { *prescaler = best_prescaler; - /* dbg("%s - %d %d", __func__, *prescaler, div); */ + /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */ } return KEYSPAN_BAUD_RATE_OK; } /* USA-28 supports different maximum baud rates on each port */ -static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) +static int keyspan_usa28_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, + u8 *rate_low, u8 *prescaler, int portnum) { u32 b16, /* baud rate times 16 (actual rate used internally) */ div, /* divisor */ cnt; /* inverse of divisor (programmed into 8051) */ - dbg("%s - %d.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); /* prevent divide by zero */ b16 = baud_rate * 16L; @@ -1642,7 +1628,7 @@ static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, *rate_low = (u8) (cnt & 0xff); if (rate_hi) *rate_hi = (u8) ((cnt >> 8) & 0xff); - dbg("%s - %d OK.", __func__, baud_rate); + dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate); return KEYSPAN_BAUD_RATE_OK; } @@ -1658,7 +1644,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, struct urb *this_urb; int device_port, err; - dbg("%s reset=%d", __func__, reset_port); + dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port); s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); @@ -1668,11 +1654,11 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, outcont_urb = d_details->outcont_endpoints[port->number]; this_urb = p_priv->outcont_urb; - dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe)); + dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } @@ -1681,7 +1667,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } @@ -1692,11 +1678,11 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -1790,12 +1776,12 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); #if 0 else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__ - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); + dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__ + outcont_urb, this_urb->transfer_buffer_length, + usb_pipeendpoint(this_urb->pipe)); } #endif @@ -1821,7 +1807,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, /* only do something if we have a bulk out endpoint */ this_urb = p_priv->outcont_urb; if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } @@ -1830,7 +1816,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); + dev_dbg(&port->dev, "%s already writing\n", __func__); mdelay(5); return -1; } @@ -1838,9 +1824,10 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage)); msg.setBaudRate = 1; - if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, - &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate requested %d.", + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, NULL, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n", __func__, p_priv->baud); msg.baudLo = 0xff; msg.baudHi = 0xb2; /* Values for 9600 baud */ @@ -1915,10 +1902,10 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed", __func__); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__); #if 0 else { - dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__, + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__, this_urb->transfer_buffer_length); } #endif @@ -1949,13 +1936,13 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, port->number); + dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number); return -1; } - dbg("%s - endpoint %d port %d (%d)", - __func__, usb_pipeendpoint(this_urb->pipe), - port->number, device_port); + dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n", + __func__, usb_pipeendpoint(this_urb->pipe), + port->number, device_port); /* Save reset port val for resend. Don't overwrite resend for open/close condition. */ @@ -1963,7 +1950,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } @@ -1977,11 +1964,11 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -2100,12 +2087,12 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, } err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); #if 0 else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__, - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); + dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__, + outcont_urb, this_urb->transfer_buffer_length, + usb_pipeendpoint(this_urb->pipe)); } #endif @@ -2131,7 +2118,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, /* only do something if we have a bulk out endpoint */ this_urb = p_priv->outcont_urb; if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); + dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); return -1; } @@ -2140,7 +2127,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); + dev_dbg(&port->dev, "%s already writing\n", __func__); mdelay(5); return -1; } @@ -2151,13 +2138,12 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0x01; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); p_priv->baud = 9600; - d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, + d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, &msg.baudHi, &msg.baudLo, &prescaler, 0); } msg.setRxMode = 1; @@ -2239,7 +2225,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -2265,7 +2251,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, /* Make sure we have an urb then send the message */ if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, + dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number); return -1; } @@ -2275,7 +2261,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, if ((reset_port + 1) > p_priv->resend_cont) p_priv->resend_cont = reset_port + 1; if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ + /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ mdelay(5); return -1; } @@ -2288,11 +2274,11 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, if (p_priv->old_baud != p_priv->baud) { p_priv->old_baud = p_priv->baud; msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); + if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, &msg.prescaler, + device_port) == KEYSPAN_INVALID_BAUD_RATE) { + dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", + __func__, p_priv->baud); msg.baudLo = 0; msg.baudHi = 125; /* Values for 9600 baud */ msg.prescaler = 10; @@ -2383,8 +2369,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, - err); + dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); return 0; } @@ -2440,8 +2425,7 @@ static int keyspan_startup(struct usb_serial *serial) /* Setup private data for serial driver */ s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); if (!s_priv) { - dbg("%s - kmalloc for keyspan_serial_private failed.", - __func__); + dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__); return -ENOMEM; } @@ -2454,7 +2438,7 @@ static int keyspan_startup(struct usb_serial *serial) p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL); if (!p_priv) { - dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i); + dev_dbg(&port->dev, "%s - kmalloc for keyspan_port_private (%d) failed!.\n", __func__, i); return 1; } p_priv->device_details = d_details; @@ -2466,14 +2450,12 @@ static int keyspan_startup(struct usb_serial *serial) if (s_priv->instat_urb != NULL) { err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit instat urb failed %d", __func__, - err); + dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err); } if (s_priv->indat_urb != NULL) { err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL); if (err != 0) - dbg("%s - submit indat urb failed %d", __func__, - err); + dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err); } return 0; @@ -2527,10 +2509,8 @@ static void keyspan_release(struct usb_serial *serial) s_priv = usb_get_serial_data(serial); - /* dbg("Freeing serial->private."); */ kfree(s_priv); - /* dbg("Freeing port->private."); */ /* Now free per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -2554,7 +2534,3 @@ MODULE_FIRMWARE("keyspan/usa18x.fw"); MODULE_FIRMWARE("keyspan/usa19w.fw"); MODULE_FIRMWARE("keyspan/usa49w.fw"); MODULE_FIRMWARE("keyspan/usa49wlc.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index fe1c5d9..0a8a40b 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -64,19 +64,23 @@ static int keyspan_tiocmset (struct tty_struct *tty, unsigned int clear); static int keyspan_fake_startup (struct usb_serial *serial); -static int keyspan_usa19_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa19w_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19w_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa28_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa28_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); -static int keyspan_usa19hs_calc_baud (u32 baud_rate, u32 baudclk, +static int keyspan_usa19hs_calc_baud (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); @@ -188,8 +192,9 @@ struct keyspan_device_details { /* Endpoint used for global control functions */ int glocont_endpoint; - int (*calculate_baud_rate) (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); + int (*calculate_baud_rate) (struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); u32 baudclk; }; diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index dcada86..ca43ecb4 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -25,13 +25,10 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <linux/firmware.h> -#include <linux/ihex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> - -static bool debug; +#include <linux/usb/ezusb.h> /* make a simple define to handle if we are compiling keyspan_pda or xircom support */ #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) @@ -137,8 +134,8 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) 0, 2000); if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); + dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n", + __func__, result); } @@ -160,12 +157,10 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } @@ -183,7 +178,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) break; case 1: /* status interrupt */ - dbg(" rx int, d1=%d, d2=%d", data[1], data[2]); + dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]); switch (data[1]) { case 1: /* modemline change */ break; @@ -229,7 +224,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) /* just restart the receive interrupt URB */ if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) - dbg(" usb_submit_urb(read urb) failed"); + dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n"); } @@ -308,8 +303,8 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, value, 0, NULL, 0, 2000); if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); + dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n", + __func__, result); /* there is something funky about this.. the TCSBRK that 'cu' performs ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 seconds apart, but it feels like the break sent isn't as long as it @@ -347,7 +342,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, speed = keyspan_pda_setbaud(serial, speed); if (speed == 0) { - dbg("can't handle requested baud rate"); + dev_dbg(&port->dev, "can't handle requested baud rate\n"); /* It hasn't changed so.. */ speed = tty_termios_baud_rate(old_termios); } @@ -459,7 +454,7 @@ static int keyspan_pda_write(struct tty_struct *tty, Block if we can't write anything at all, otherwise write as much as we can. */ if (count == 0) { - dbg(" write request of 0 bytes"); + dev_dbg(&port->dev, "write request of 0 bytes\n"); return 0; } @@ -505,16 +500,16 @@ static int keyspan_pda_write(struct tty_struct *tty, 1, 2000); if (rc > 0) { - dbg(" roomquery says %d", *room); + dev_dbg(&port->dev, "roomquery says %d\n", *room); priv->tx_room = *room; } kfree(room); if (rc < 0) { - dbg(" roomquery failed"); + dev_dbg(&port->dev, "roomquery failed\n"); goto exit; } if (rc == 0) { - dbg(" roomquery returned 0 bytes"); + dev_dbg(&port->dev, "roomquery returned 0 bytes\n"); rc = -EIO; /* device didn't return any data */ goto exit; } @@ -536,7 +531,7 @@ static int keyspan_pda_write(struct tty_struct *tty, rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (rc) { - dbg(" usb_submit_urb(write bulk) failed"); + dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n"); goto exit; } } else { @@ -639,11 +634,11 @@ static int keyspan_pda_open(struct tty_struct *tty, 1, 2000); if (rc < 0) { - dbg("%s - roomquery failed", __func__); + dev_dbg(&port->dev, "%s - roomquery failed\n", __func__); goto error; } if (rc == 0) { - dbg("%s - roomquery returned 0 bytes", __func__); + dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__); rc = -EIO; goto error; } @@ -654,7 +649,7 @@ static int keyspan_pda_open(struct tty_struct *tty, /*Start reading from the device*/ rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (rc) { - dbg("%s - usb_submit_urb(read int) failed", __func__); + dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__); goto error; } error: @@ -678,11 +673,9 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) { int response; const char *fw_name; - const struct ihex_binrec *record; - const struct firmware *fw; /* download the firmware here ... */ - response = ezusb_set_reset(serial, 1); + response = ezusb_fx1_set_reset(serial->dev, 1); if (0) { ; } #ifdef KEYSPAN @@ -699,30 +692,15 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) __func__); return -ENODEV; } - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { + + if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", fw_name); return -ENOENT; } - record = (const struct ihex_binrec *)fw->data; - - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed " - "for Keyspan PDA firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a moment - and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); + + /* after downloading firmware Renumeration will occur in a + moment and the new device will bind to the real driver */ /* we want this device to fail to have a driver assigned to it. */ return 1; @@ -828,6 +806,3 @@ module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index def9ad2..3f6d737 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -49,8 +49,6 @@ #include <linux/usb/serial.h> #include "kl5kusb105.h" -static bool debug; - /* * Version Information */ @@ -239,7 +237,9 @@ static int klsi_105_startup(struct usb_serial *serial) priv = kmalloc(sizeof(struct klsi_105_private), GFP_KERNEL); if (!priv) { - dbg("%skmalloc for klsi_105_private failed.", __func__); + dev_dbg(&serial->interface->dev, + "%s - kmalloc for klsi_105_private failed.\n", + __func__); i--; goto err_cleanup; } @@ -344,14 +344,14 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc); retval = rc; } else - dbg("%s - enabled reading", __func__); + dev_dbg(&port->dev, "%s - enabled reading\n", __func__); rc = klsi_105_get_line_state(port, &line_state); if (rc >= 0) { spin_lock_irqsave(&priv->lock, flags); priv->line_state = line_state; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); + dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state); retval = 0; } else retval = rc; @@ -421,7 +421,7 @@ static void klsi_105_process_read_urb(struct urb *urb) return; if (urb->actual_length <= KLSI_HDR_LEN) { - dbg("%s - malformed packet", __func__); + dev_dbg(&port->dev, "%s - malformed packet\n", __func__); return; } @@ -431,7 +431,7 @@ static void klsi_105_process_read_urb(struct urb *urb) len = get_unaligned_le16(data); if (len > urb->actual_length - KLSI_HDR_LEN) { - dbg("%s - packet length mismatch", __func__); + dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__); len = urb->actual_length - KLSI_HDR_LEN; } @@ -445,6 +445,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); + struct device *dev = &port->dev; unsigned int iflag = tty->termios.c_iflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int cflag = tty->termios.c_cflag; @@ -455,8 +456,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) { - dev_err(&port->dev, "%s - out of memory for config buffer.\n", - __func__); + dev_err(dev, "%s - out of memory for config buffer.\n", __func__); return; } @@ -471,7 +471,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, if ((cflag & CBAUD) != (old_cflag & CBAUD)) { /* reassert DTR and (maybe) RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); + dev_dbg(dev, "%s: baud was B0\n", __func__); #if 0 priv->control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ @@ -509,14 +509,13 @@ static void klsi_105_set_termios(struct tty_struct *tty, priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: - dbg("KLSI USB->Serial converter:" - " unsupported baudrate request, using default of 9600"); - priv->cfg.baudrate = kl5kusb105a_sio_b9600; + dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600"); + priv->cfg.baudrate = kl5kusb105a_sio_b9600; baud = 9600; break; } if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); + dev_dbg(dev, "%s: baud is B0\n", __func__); /* Drop RTS and DTR */ /* maybe this should be simulated by sending read * disable and read enable messages? @@ -533,11 +532,11 @@ static void klsi_105_set_termios(struct tty_struct *tty, /* set the number of data bits */ switch (cflag & CSIZE) { case CS5: - dbg("%s - 5 bits/byte not supported", __func__); + dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto err; case CS6: - dbg("%s - 6 bits/byte not supported", __func__); + dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__); spin_unlock_irqrestore(&priv->lock, flags); goto err; case CS7: @@ -547,8 +546,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, priv->cfg.databits = kl5kusb105a_dtb_8; break; default: - dev_err(&port->dev, - "CSIZE was not CS5-CS8, using default of 8\n"); + dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n"); priv->cfg.databits = kl5kusb105a_dtb_8; break; } @@ -616,7 +614,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) (struct mct_u232_private *)port->private; unsigned char lcr = priv->last_lcr; - dbg("%sstate=%d", __func__, break_state); + dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state); /* LOCKING */ if (break_state) @@ -645,7 +643,7 @@ static int klsi_105_tiocmget(struct tty_struct *tty) spin_lock_irqsave(&priv->lock, flags); priv->line_state = line_state; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); + dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state); return (int)line_state; } @@ -681,6 +679,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable extensive debugging messages"); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index bf5c749..5c4d2fb 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -38,8 +38,6 @@ #include <linux/ioctl.h> #include "kobil_sct.h" -static bool debug; - /* Version Information */ #define DRIVER_VERSION "21/05/2004" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" @@ -139,17 +137,16 @@ static int kobil_startup(struct usb_serial *serial) switch (priv->device_type) { case KOBIL_ADAPTER_B_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL B1 PRO / KAAN PRO detected\n"); break; case KOBIL_ADAPTER_K_PRODUCT_ID: - printk(KERN_DEBUG - "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n"); break; case KOBIL_USBTWIN_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL USBTWIN detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL USBTWIN detected\n"); break; case KOBIL_KAAN_SIM_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL KAAN SIM detected\n"); + dev_dbg(&serial->dev->dev, "KOBIL KAAN SIM detected\n"); break; } usb_set_serial_port_data(serial->port[0], priv); @@ -164,13 +161,15 @@ static int kobil_startup(struct usb_serial *serial) for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { endpoint = &altsetting->endpoint[i]; if (usb_endpoint_is_int_out(&endpoint->desc)) { - dbg("%s Found interrupt out endpoint. Address: %d", + dev_dbg(&serial->dev->dev, + "%s Found interrupt out endpoint. Address: %d\n", __func__, endpoint->desc.bEndpointAddress); priv->write_int_endpoint_address = endpoint->desc.bEndpointAddress; } if (usb_endpoint_is_int_in(&endpoint->desc)) { - dbg("%s Found interrupt in endpoint. Address: %d", + dev_dbg(&serial->dev->dev, + "%s Found interrupt in endpoint. Address: %d\n", __func__, endpoint->desc.bEndpointAddress); priv->read_int_endpoint_address = endpoint->desc.bEndpointAddress; @@ -200,6 +199,7 @@ static void kobil_init_termios(struct tty_struct *tty) static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct device *dev = &port->dev; int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; @@ -215,12 +215,10 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) /* allocate write_urb */ if (!port->write_urb) { - dbg("%s - port %d Allocating port->write_urb", - __func__, port->number); + dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__); port->write_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->write_urb) { - dbg("%s - port %d usb_alloc_urb failed", - __func__, port->number); + dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__); kfree(transfer_buffer); return -ENOMEM; } @@ -247,10 +245,9 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) transfer_buffer_length, KOBIL_TIMEOUT ); - dbg("%s - port %d Send get_HW_version URB returns: %i", - __func__, port->number, result); - dbg("Harware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); + dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result); + dev_dbg(dev, "Harware version: %i.%i.%i\n", transfer_buffer[0], + transfer_buffer[1], transfer_buffer[2]); /* get firmware version */ result = usb_control_msg(port->serial->dev, @@ -263,10 +260,9 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) transfer_buffer_length, KOBIL_TIMEOUT ); - dbg("%s - port %d Send get_FW_version URB returns: %i", - __func__, port->number, result); - dbg("Firmware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); + dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result); + dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0], + transfer_buffer[1], transfer_buffer[2]); if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { @@ -282,8 +278,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) 0, KOBIL_TIMEOUT ); - dbg("%s - port %d Send set_baudrate URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send set_baudrate URB returns: %i\n", __func__, result); /* reset all queues */ result = usb_control_msg(port->serial->dev, @@ -296,16 +291,14 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) 0, KOBIL_TIMEOUT ); - dbg("%s - port %d Send reset_all_queues URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send reset_all_queues URB returns: %i\n", __func__, result); } if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* start reading (Adapter B 'cause PNP string) */ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result); } kfree(transfer_buffer); @@ -333,11 +326,9 @@ static void kobil_read_int_callback(struct urb *urb) struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; -/* char *dbg_data; */ if (status) { - dbg("%s - port %d Read int status not zero: %d", - __func__, port->number, status); + dev_dbg(&port->dev, "%s - Read int status not zero: %d\n", __func__, status); return; } @@ -346,6 +337,8 @@ static void kobil_read_int_callback(struct urb *urb) /* BEGIN DEBUG */ /* + char *dbg_data; + dbg_data = kzalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); if (! dbg_data) { @@ -354,7 +347,7 @@ static void kobil_read_int_callback(struct urb *urb) for (i = 0; i < purb->actual_length; i++) { sprintf(dbg_data +3*i, "%02X ", data[i]); } - dbg(" <-- %s", dbg_data); + dev_dbg(&port->dev, " <-- %s\n", dbg_data); kfree(dbg_data); */ /* END DEBUG */ @@ -365,8 +358,7 @@ static void kobil_read_int_callback(struct urb *urb) tty_kref_put(tty); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result); } @@ -384,22 +376,20 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, struct kobil_private *priv; if (count == 0) { - dbg("%s - port %d write request of 0 bytes", - __func__, port->number); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } priv = usb_get_serial_port_data(port); if (count > (KOBIL_BUF_LENGTH - priv->filled)) { - dbg("%s - port %d Error: write request bigger than buffer size", __func__, port->number); + dev_dbg(&port->dev, "%s - Error: write request bigger than buffer size\n", __func__); return -ENOMEM; } /* Copy data to buffer */ memcpy(priv->buf + priv->filled, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->buf + priv->filled); + usb_serial_debug_data(&port->dev, __func__, count, priv->buf + priv->filled); priv->filled = priv->filled + count; /* only send complete block. TWIN, KAAN SIM and adapter K @@ -432,8 +422,7 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, priv->cur_pos = priv->cur_pos + length; result = usb_submit_urb(port->write_urb, GFP_NOIO); - dbg("%s - port %d Send write URB returns: %i", - __func__, port->number, result); + dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result); todo = priv->filled - priv->cur_pos; if (todo > 0) @@ -448,8 +437,7 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); + dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result); } } return count; @@ -493,8 +481,8 @@ static int kobil_tiocmget(struct tty_struct *tty) transfer_buffer_length, KOBIL_TIMEOUT); - dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x", - __func__, port->number, result, transfer_buffer[0]); + dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n", + __func__, result, transfer_buffer[0]); result = 0; if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) @@ -507,6 +495,7 @@ static int kobil_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct device *dev = &port->dev; struct kobil_private *priv; int result; int dtr = 0; @@ -538,11 +527,9 @@ static int kobil_tiocmset(struct tty_struct *tty, if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) { if (dtr != 0) - dbg("%s - port %d Setting DTR", - __func__, port->number); + dev_dbg(dev, "%s - Setting DTR\n", __func__); else - dbg("%s - port %d Clearing DTR", - __func__, port->number); + dev_dbg(dev, "%s - Clearing DTR\n", __func__); result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, @@ -554,11 +541,9 @@ static int kobil_tiocmset(struct tty_struct *tty, KOBIL_TIMEOUT); } else { if (rts != 0) - dbg("%s - port %d Setting RTS", - __func__, port->number); + dev_dbg(dev, "%s - Setting RTS\n", __func__); else - dbg("%s - port %d Clearing RTS", - __func__, port->number); + dev_dbg(dev, "%s - Clearing RTS\n", __func__); result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), SUSBCRequest_SetStatusLinesOrQueues, @@ -569,8 +554,7 @@ static int kobil_tiocmset(struct tty_struct *tty, 0, KOBIL_TIMEOUT); } - dbg("%s - port %d Send set_status_line URB returns: %i", - __func__, port->number, result); + dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result); kfree(transfer_buffer); return (result < 0) ? result : 0; } @@ -658,7 +642,8 @@ static int kobil_ioctl(struct tty_struct *tty, KOBIL_TIMEOUT ); - dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result); + dev_dbg(&port->dev, + "%s - Send reset_all_queues (FLUSH) URB returns: %i", __func__, result); kfree(transfer_buffer); return (result < 0) ? -EIO: 0; default: @@ -671,6 +656,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index df98cff..f394771 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -45,8 +45,6 @@ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" -static bool debug; - /* * Function prototypes */ @@ -214,7 +212,7 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, value, rc); else tty_encode_baud_rate(tty, speed, speed); - dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor); + dev_dbg(&port->dev, "set_baud_rate: value: 0x%x, divisor: 0x%x\n", value, divisor); /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which always sends two extra USB 'device request' messages after the @@ -247,8 +245,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, if (port && C_CRTSCTS(tty)) cts_enable_byte = 1; - dbg("set_baud_rate: send second control message, data = %02X", - cts_enable_byte); + dev_dbg(&port->dev, "set_baud_rate: send second control message, data = %02X\n", + cts_enable_byte); buf[0] = cts_enable_byte; rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_CTS_REQUEST, @@ -263,7 +261,8 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty, return rc; } /* mct_u232_set_baud_rate */ -static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr) +static int mct_u232_set_line_ctrl(struct usb_serial_port *port, + unsigned char lcr) { int rc; unsigned char *buf; @@ -273,20 +272,19 @@ static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr) return -ENOMEM; buf[0] = lcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), MCT_U232_SET_LINE_CTRL_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE, WDR_TIMEOUT); if (rc < 0) - dev_err(&serial->dev->dev, - "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); - dbg("set_line_ctrl: 0x%x", lcr); + dev_err(&port->dev, "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); + dev_dbg(&port->dev, "set_line_ctrl: 0x%x\n", lcr); kfree(buf); return rc; } /* mct_u232_set_line_ctrl */ -static int mct_u232_set_modem_ctrl(struct usb_serial *serial, +static int mct_u232_set_modem_ctrl(struct usb_serial_port *port, unsigned int control_state) { int rc; @@ -304,25 +302,24 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial, mcr |= MCT_U232_MCR_RTS; buf[0] = mcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), MCT_U232_SET_MODEM_CTRL_REQUEST, MCT_U232_SET_REQUEST_TYPE, 0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE, WDR_TIMEOUT); kfree(buf); - dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr); + dev_dbg(&port->dev, "set_modem_ctrl: state=0x%x ==> mcr=0x%x\n", control_state, mcr); if (rc < 0) { - dev_err(&serial->dev->dev, - "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); + dev_err(&port->dev, "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); return rc; } return 0; } /* mct_u232_set_modem_ctrl */ -static int mct_u232_get_modem_stat(struct usb_serial *serial, - unsigned char *msr) +static int mct_u232_get_modem_stat(struct usb_serial_port *port, + unsigned char *msr) { int rc; unsigned char *buf; @@ -332,19 +329,18 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial, *msr = 0; return -ENOMEM; } - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + rc = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), MCT_U232_GET_MODEM_STAT_REQUEST, MCT_U232_GET_REQUEST_TYPE, 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, WDR_TIMEOUT); if (rc < 0) { - dev_err(&serial->dev->dev, - "Get MODEM STATus failed (error = %d)\n", rc); + dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc); *msr = 0; } else { *msr = buf[0]; } - dbg("get_modem_stat: 0x%x", *msr); + dev_dbg(&port->dev, "get_modem_stat: 0x%x\n", *msr); kfree(buf); return rc; } /* mct_u232_get_modem_stat */ @@ -363,8 +359,8 @@ static void mct_u232_msr_to_icount(struct async_icount *icount, icount->dcd++; } /* mct_u232_msr_to_icount */ -static void mct_u232_msr_to_state(unsigned int *control_state, - unsigned char msr) +static void mct_u232_msr_to_state(struct usb_serial_port *port, + unsigned int *control_state, unsigned char msr) { /* Translate Control Line states */ if (msr & MCT_U232_MSR_DSR) @@ -383,7 +379,7 @@ static void mct_u232_msr_to_state(unsigned int *control_state, *control_state |= TIOCM_CD; else *control_state &= ~TIOCM_CD; - dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state); + dev_dbg(&port->dev, "msr_to_state: msr=0x%x ==> state=0x%x\n", msr, *control_state); } /* mct_u232_msr_to_state */ /* @@ -465,14 +461,14 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) control_state = priv->control_state; last_lcr = priv->last_lcr; spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_modem_ctrl(serial, control_state); - mct_u232_set_line_ctrl(serial, last_lcr); + mct_u232_set_modem_ctrl(port, control_state); + mct_u232_set_line_ctrl(port, last_lcr); /* Read modem status and update control state */ - mct_u232_get_modem_stat(serial, &last_msr); + mct_u232_get_modem_stat(port, &last_msr); spin_lock_irqsave(&priv->lock, flags); priv->last_msr = last_msr; - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); + mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -512,7 +508,7 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); control_state = priv->control_state; spin_unlock_irq(&priv->lock); - mct_u232_set_modem_ctrl(port->serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } mutex_unlock(&port->serial->disc_mutex); } @@ -532,7 +528,6 @@ static void mct_u232_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int retval; @@ -547,22 +542,16 @@ static void mct_u232_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here @@ -588,7 +577,7 @@ static void mct_u232_read_int_callback(struct urb *urb) priv->last_msr = data[MCT_U232_MSR_INDEX]; /* Record Control Line states */ - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); + mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); mct_u232_msr_to_icount(&priv->icount, priv->last_msr); @@ -656,18 +645,18 @@ static void mct_u232_set_termios(struct tty_struct *tty, /* reassert DTR and RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); + dev_dbg(&port->dev, "%s: baud was B0\n", __func__); control_state |= TIOCM_DTR | TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty)); if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); + dev_dbg(&port->dev, "%s: baud is B0\n", __func__); /* Drop RTS and DTR */ control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } /* @@ -704,7 +693,7 @@ static void mct_u232_set_termios(struct tty_struct *tty, last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - mct_u232_set_line_ctrl(serial, last_lcr); + mct_u232_set_line_ctrl(port, last_lcr); /* save off the modified port settings */ spin_lock_irqsave(&priv->lock, flags); @@ -716,7 +705,6 @@ static void mct_u232_set_termios(struct tty_struct *tty, static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned char lcr; unsigned long flags; @@ -728,7 +716,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) lcr |= MCT_U232_SET_BREAK; spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_line_ctrl(serial, lcr); + mct_u232_set_line_ctrl(port, lcr); } /* mct_u232_break_ctl */ @@ -750,7 +738,6 @@ static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; unsigned long flags; @@ -769,7 +756,7 @@ static int mct_u232_tiocmset(struct tty_struct *tty, priv->control_state = control_state; spin_unlock_irqrestore(&priv->lock, flags); - return mct_u232_set_modem_ctrl(serial, control_state); + return mct_u232_set_modem_ctrl(port, control_state); } static void mct_u232_throttle(struct tty_struct *tty) @@ -784,7 +771,7 @@ static void mct_u232_throttle(struct tty_struct *tty) priv->control_state &= ~TIOCM_RTS; control_state = priv->control_state; spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } else { spin_unlock_irq(&priv->lock); } @@ -802,7 +789,7 @@ static void mct_u232_unthrottle(struct tty_struct *tty) priv->control_state |= TIOCM_RTS; control_state = priv->control_state; spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); + mct_u232_set_modem_ctrl(port, control_state); } else { spin_unlock_irq(&priv->lock); } @@ -817,13 +804,13 @@ static int mct_u232_ioctl(struct tty_struct *tty, struct async_icount cnow, cprev; unsigned long flags; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); switch (cmd) { case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__); spin_lock_irqsave(&mct_u232_port->lock, flags); cprev = mct_u232_port->icount; @@ -879,8 +866,8 @@ static int mct_u232_get_icount(struct tty_struct *tty, spin_unlock_irqrestore(&mct_u232_port->lock, flags); - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, icount->rx, icount->tx); + dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", + __func__, icount->rx, icount->tx); return 0; } @@ -889,6 +876,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 2b0627b..0b257dd 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -52,9 +52,6 @@ static struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -/* Input parameter constants. */ -static bool debug; - /* UNI-Directional mode commands for device configure */ #define UNI_CMD_OPEN 0x80 #define UNI_CMD_CLOSE 0xFF @@ -436,7 +433,3 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Nicastro"); MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>"); MODULE_DESCRIPTION(DRIVER_DESC); - -/* Module input parameters */ -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)"); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 012f67b..1bf1ad0 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -71,8 +71,6 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; }; -static bool debug; - static struct usb_serial_driver moschip7720_2port_driver; #define USB_VENDOR_ID_MOSCHIP 0x9710 @@ -281,16 +279,19 @@ static void send_deferred_urbs(unsigned long _mos_parport) int ret_val; unsigned long flags; struct mos7715_parport *mos_parport = (void *)_mos_parport; - struct urbtracker *urbtrack; + struct urbtracker *urbtrack, *tmp; struct list_head *cursor, *next; + struct device *dev; /* if release function ran, game over */ if (unlikely(mos_parport->serial == NULL)) return; + dev = &mos_parport->serial->dev->dev; + /* try again to get the mutex */ if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { - dbg("%s: rescheduling tasklet", __func__); + dev_dbg(dev, "%s: rescheduling tasklet\n", __func__); tasklet_schedule(&mos_parport->urb_tasklet); return; } @@ -305,20 +306,19 @@ static void send_deferred_urbs(unsigned long _mos_parport) if (list_empty(&mos_parport->deferred_urbs)) { spin_unlock_irqrestore(&mos_parport->listlock, flags); mutex_unlock(&mos_parport->serial->disc_mutex); - dbg("%s: deferred_urbs list empty", __func__); + dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__); return; } /* move contents of deferred_urbs list to active_urbs list and submit */ list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) list_move_tail(cursor, &mos_parport->active_urbs); - list_for_each_entry(urbtrack, &mos_parport->active_urbs, + list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs, urblist_entry) { ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - dbg("%s: urb submitted", __func__); + dev_dbg(dev, "%s: urb submitted\n", __func__); if (ret_val) { - dev_err(&mos_parport->serial->dev->dev, - "usb_submit_urb() failed: %d", ret_val); + dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val); list_del(&urbtrack->urblist_entry); kref_put(&urbtrack->ref_count, destroy_urbtracker); } @@ -334,7 +334,7 @@ static void async_complete(struct urb *urb) int status = urb->status; if (unlikely(status)) - dbg("%s - nonzero urb status received: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); /* remove the urbtracker from the active_urbs list */ spin_lock(&urbtrack->mos_parport->listlock); @@ -389,7 +389,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, &mos_parport->deferred_urbs); spin_unlock_irqrestore(&mos_parport->listlock, flags); tasklet_schedule(&mos_parport->urb_tasklet); - dbg("tasklet scheduled"); + dev_dbg(&usbdev->dev, "tasklet scheduled"); return 0; } @@ -690,7 +690,7 @@ static int mos7715_parport_init(struct usb_serial *serial) /* allocate and initialize parallel port control struct */ mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); if (mos_parport == NULL) { - dbg("mos7715_parport_init: kzalloc failed"); + dev_dbg(&serial->dev->dev, "%s: kzalloc failed\n", __func__); return -ENOMEM; } mos_parport->msg_pending = false; @@ -743,6 +743,7 @@ static void mos7720_interrupt_callback(struct urb *urb) int result; int length; int status = urb->status; + struct device *dev = &urb->dev->dev; __u8 *data; __u8 sp1; __u8 sp2; @@ -755,12 +756,10 @@ static void mos7720_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } @@ -777,7 +776,7 @@ static void mos7720_interrupt_callback(struct urb *urb) * oneukum 2007-03-14 */ if (unlikely(length != 4)) { - dbg("Wrong data !!!"); + dev_dbg(dev, "Wrong data !!!\n"); return; } @@ -786,31 +785,29 @@ static void mos7720_interrupt_callback(struct urb *urb) if ((sp1 | sp2) & 0x01) { /* No Interrupt Pending in both the ports */ - dbg("No Interrupt !!!"); + dev_dbg(dev, "No Interrupt !!!\n"); } else { switch (sp1 & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port 1: Receiver status error or address " - "bit detected in 9-bit mode\n"); + dev_dbg(dev, "Serial Port 1: Receiver status error or address bit detected in 9-bit mode\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port 1: Receiver time out"); + dev_dbg(dev, "Serial Port 1: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port 1: Modem status change"); */ + /* dev_dbg(dev, "Serial Port 1: Modem status change\n"); */ break; } switch (sp2 & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port 2: Receiver status error or address " - "bit detected in 9-bit mode"); + dev_dbg(dev, "Serial Port 2: Receiver status error or address bit detected in 9-bit mode\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port 2: Receiver time out"); + dev_dbg(dev, "Serial Port 2: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port 2: Modem status change"); */ + /* dev_dbg(dev, "Serial Port 2: Modem status change\n"); */ break; } } @@ -818,9 +815,7 @@ static void mos7720_interrupt_callback(struct urb *urb) exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); + dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result); } /* @@ -833,6 +828,7 @@ static void mos7715_interrupt_callback(struct urb *urb) int result; int length; int status = urb->status; + struct device *dev = &urb->dev->dev; __u8 *data; __u8 iir; @@ -845,12 +841,10 @@ static void mos7715_interrupt_callback(struct urb *urb) case -ESHUTDOWN: case -ENODEV: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } @@ -864,7 +858,7 @@ static void mos7715_interrupt_callback(struct urb *urb) * Byte 4: FIFO status for both */ if (unlikely(length != 4)) { - dbg("Wrong data !!!"); + dev_dbg(dev, "Wrong data !!!\n"); return; } @@ -872,14 +866,13 @@ static void mos7715_interrupt_callback(struct urb *urb) if (!(iir & 0x01)) { /* serial port interrupt pending */ switch (iir & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port: Receiver status error or address " - "bit detected in 9-bit mode\n"); + dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n\n"); break; case SERIAL_IIR_CTI: - dbg("Serial Port: Receiver time out"); + dev_dbg(dev, "Serial Port: Receiver time out\n"); break; case SERIAL_IIR_MS: - /* dbg("Serial Port: Modem status change"); */ + /* dev_dbg(dev, "Serial Port: Modem status change\n"); */ break; } } @@ -897,9 +890,7 @@ static void mos7715_interrupt_callback(struct urb *urb) exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); + dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result); } /* @@ -916,13 +907,13 @@ static void mos7720_bulk_in_callback(struct urb *urb) int status = urb->status; if (status) { - dbg("nonzero read bulk status received: %d", status); + dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status); return; } port = urb->context; - dbg("Entering...%s", __func__); + dev_dbg(&port->dev, "Entering...%s\n", __func__); data = urb->transfer_buffer; @@ -936,8 +927,7 @@ static void mos7720_bulk_in_callback(struct urb *urb) if (port->read_urb->status != -EINPROGRESS) { retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (retval) - dbg("usb_submit_urb(read bulk) failed, retval = %d", - retval); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval); } } @@ -953,13 +943,13 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) int status = urb->status; if (status) { - dbg("nonzero write bulk status received:%d", status); + dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status); return; } mos7720_port = urb->context; if (!mos7720_port) { - dbg("NULL mos7720_port pointer"); + dev_dbg(&urb->dev->dev, "NULL mos7720_port pointer\n"); return ; } @@ -1061,9 +1051,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) port_number = port->number - port->serial->minor; read_mos_reg(serial, port_number, LSR, &data); - dbg("SS::%p LSR:%x", mos7720_port, data); - - dbg("Check:Sending Command .........."); + dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data); write_mos_reg(serial, dummy, SP1_REG, 0x02); write_mos_reg(serial, dummy, SP2_REG, 0x02); @@ -1122,20 +1110,16 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty) int chars = 0; struct moschip_port *mos7720_port; - dbg("%s:entering ...........", __func__); - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); + if (mos7720_port == NULL) return 0; - } for (i = 0; i < NUM_URBS; ++i) { if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) chars += URB_TRANSFER_BUFFER_SIZE; } - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1145,8 +1129,6 @@ static void mos7720_close(struct usb_serial_port *port) struct moschip_port *mos7720_port; int j; - dbg("mos7720_close:entering..."); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); @@ -1166,9 +1148,7 @@ static void mos7720_close(struct usb_serial_port *port) /* While closing port, shutdown all bulk read, write * * and interrupt read if they exists, otherwise nop */ - dbg("Shutdown bulk write"); usb_kill_urb(port->write_urb); - dbg("Shutdown bulk read"); usb_kill_urb(port->read_urb); mutex_lock(&serial->disc_mutex); @@ -1182,8 +1162,6 @@ static void mos7720_close(struct usb_serial_port *port) } mutex_unlock(&serial->disc_mutex); mos7720_port->open = 0; - - dbg("Leaving %s", __func__); } static void mos7720_break(struct tty_struct *tty, int break_state) @@ -1193,8 +1171,6 @@ static void mos7720_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7720_port; - dbg("Entering %s", __func__); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); @@ -1225,13 +1201,9 @@ static int mos7720_write_room(struct tty_struct *tty) int room = 0; int i; - dbg("%s:entering ...........", __func__); - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); + if (mos7720_port == NULL) return -ENODEV; - } /* FIXME: Locking */ for (i = 0; i < NUM_URBS; ++i) { @@ -1240,7 +1212,7 @@ static int mos7720_write_room(struct tty_struct *tty) room += URB_TRANSFER_BUFFER_SIZE; } - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1257,15 +1229,11 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, struct urb *urb; const unsigned char *current_position = data; - dbg("%s:entering ...........", __func__); - serial = port->serial; mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("mos7720_port is NULL"); + if (mos7720_port == NULL) return -ENODEV; - } /* try to find a free urb in the list */ urb = NULL; @@ -1274,13 +1242,13 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { urb = mos7720_port->write_urb_pool[i]; - dbg("URB:%d", i); + dev_dbg(&port->dev, "URB:%d\n", i); break; } } if (urb == NULL) { - dbg("%s - no more free urbs", __func__); + dev_dbg(&port->dev, "%s - no more free urbs\n", __func__); goto exit; } @@ -1296,7 +1264,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); memcpy(urb->transfer_buffer, current_position, transfer_size); - usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, + usb_serial_debug_data(&port->dev, __func__, transfer_size, urb->transfer_buffer); /* fill urb with data and submit */ @@ -1326,20 +1294,16 @@ static void mos7720_throttle(struct tty_struct *tty) struct moschip_port *mos7720_port; int status; - dbg("%s- port %d", __func__, port->number); - mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return; if (!mos7720_port->open) { - dbg("port not opened"); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1368,12 +1332,10 @@ static void mos7720_unthrottle(struct tty_struct *tty) return; if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); @@ -1409,7 +1371,7 @@ static int set_higher_rates(struct moschip_port *mos7720_port, /*********************************************** * Init Sequence for higher rates ***********************************************/ - dbg("Sending Setting Commands .........."); + dev_dbg(&port->dev, "Sending Setting Commands ..........\n"); port_number = port->number - port->serial->minor; write_mos_reg(serial, port_number, IER, 0x00); @@ -1478,7 +1440,7 @@ static struct divisor_table_entry divisor_table[] = { * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) +static int calc_baud_rate_divisor(struct usb_serial_port *port, int baudrate, int *divisor) { int i; __u16 custom; @@ -1486,7 +1448,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) __u16 round; - dbg("%s - %d", __func__, baudrate); + dev_dbg(&port->dev, "%s - %d\n", __func__, baudrate); for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { if (divisor_table[i].baudrate == baudrate) { @@ -1508,11 +1470,11 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor) custom++; *divisor = custom; - dbg("Baud %d = %d", baudrate, custom); + dev_dbg(&port->dev, "Baud %d = %d\n", baudrate, custom); return 0; } - dbg("Baud calculation Failed..."); + dev_dbg(&port->dev, "Baud calculation Failed...\n"); return -EINVAL; } @@ -1536,13 +1498,11 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, port = mos7720_port->port; serial = port->serial; - dbg("%s: Entering ..........", __func__); - number = port->number - port->serial->minor; - dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate); + dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudrate); /* Calculate the Divisor */ - status = calc_baud_rate_divisor(baudrate, &divisor); + status = calc_baud_rate_divisor(port, baudrate, &divisor); if (status) { dev_err(&port->dev, "%s - bad baud rate\n", __func__); return status; @@ -1591,15 +1551,11 @@ static void change_port_settings(struct tty_struct *tty, serial = port->serial; port_number = port->number - port->serial->minor; - dbg("%s - port %d", __func__, port->number); - if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s: Entering ..........", __func__); - lData = UART_LCR_WLEN8; lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ @@ -1633,14 +1589,14 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) { lParity = UART_LCR_PARITY; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "%s - parity = odd\n", __func__); } else { lParity = (UART_LCR_EPAR | UART_LCR_PARITY); - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "%s - parity = none\n", __func__); } if (cflag & CMSPAR) @@ -1649,10 +1605,10 @@ static void change_port_settings(struct tty_struct *tty, /* Change the Stop bit */ if (cflag & CSTOPB) { lStop = UART_LCR_STOP; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__); } else { lStop = 0x00; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__); } #define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ @@ -1698,7 +1654,7 @@ static void change_port_settings(struct tty_struct *tty, baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */ - dbg("Picked default baud..."); + dev_dbg(&port->dev, "Picked default baud...\n"); baud = 9600; } @@ -1709,7 +1665,7 @@ static void change_port_settings(struct tty_struct *tty, return; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud); status = send_cmd_write_baud_rate(mos7720_port, baud); /* FIXME: needs to write actual resulting baud back not just blindly do so */ @@ -1721,8 +1677,7 @@ static void change_port_settings(struct tty_struct *tty, if (port->read_urb->status != -EINPROGRESS) { status = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } } @@ -1747,23 +1702,19 @@ static void mos7720_set_termios(struct tty_struct *tty, return; if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s\n", "setting termios - ASPIRE"); + dev_dbg(&port->dev, "setting termios - ASPIRE\n"); cflag = tty->termios.c_cflag; - dbg("%s - cflag %08x iflag %08x", __func__, - tty->termios.c_cflag, - RELEVANT_IFLAG(tty->termios.c_iflag)); + dev_dbg(&port->dev, "%s - cflag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); - dbg("%s - old cflag %08x old iflag %08x", __func__, - old_termios->c_cflag, - RELEVANT_IFLAG(old_termios->c_iflag)); - - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - old cflag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); /* change the port settings to the new ones specified */ change_port_settings(tty, mos7720_port, old_termios); @@ -1771,8 +1722,7 @@ static void mos7720_set_termios(struct tty_struct *tty, if (port->read_urb->status != -EINPROGRESS) { status = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); } } @@ -1800,7 +1750,7 @@ static int get_lsr_info(struct tty_struct *tty, read_mos_reg(port->serial, port_number, LSR, &data); if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) == (UART_LSR_TEMT | UART_LSR_THRE)) { - dbg("%s -- Empty", __func__); + dev_dbg(&port->dev, "%s -- Empty\n", __func__); result = TIOCSER_TEMT; } } @@ -1817,8 +1767,6 @@ static int mos7720_tiocmget(struct tty_struct *tty) unsigned int mcr ; unsigned int msr ; - dbg("%s - port %d", __func__, port->number); - mcr = mos7720_port->shadowMCR; msr = mos7720_port->shadowMSR; @@ -1829,8 +1777,6 @@ static int mos7720_tiocmget(struct tty_struct *tty) | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ - dbg("%s -- %x", __func__, result); - return result; } @@ -1840,8 +1786,6 @@ static int mos7720_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port = usb_get_serial_port_data(port); unsigned int mcr ; - dbg("%s - port %d", __func__, port->number); - dbg("he was at tiocmset"); mcr = mos7720_port->shadowMCR; @@ -1888,8 +1832,8 @@ static int mos7720_get_icount(struct tty_struct *tty, icount->brk = cnow.brk; icount->buf_overrun = cnow.buf_overrun; - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); + dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, + icount->rx, icount->tx); return 0; } @@ -1975,29 +1919,28 @@ static int mos7720_ioctl(struct tty_struct *tty, if (mos7720_port == NULL) return -ENODEV; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - cmd = 0x%x", __func__, cmd); switch (cmd) { case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(tty, mos7720_port, (unsigned int __user *)arg); /* FIXME: These should be using the mode methods */ case TIOCMBIS: case TIOCMBIC: - dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", - __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__); return set_modem_info(mos7720_port, cmd, (unsigned int __user *)arg); case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return get_serial_info(mos7720_port, (struct serial_struct __user *)arg); case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); cprev = mos7720_port->icount; while (1) { if (signal_pending(current)) @@ -2030,13 +1973,6 @@ static int mos7720_startup(struct usb_serial *serial) u16 product; int ret_val; - dbg("%s: Entering ..........", __func__); - - if (!serial) { - dbg("Invalid Handler"); - return -ENODEV; - } - product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; @@ -2081,8 +2017,8 @@ static int mos7720_startup(struct usb_serial *serial) mos7720_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], mos7720_port); - dbg("port number is %d", serial->port[i]->number); - dbg("serial number is %d", serial->minor); + dev_dbg(&dev->dev, "port number is %d\n", serial->port[i]->number); + dev_dbg(&dev->dev, "serial number is %d\n", serial->minor); } @@ -2106,7 +2042,7 @@ static int mos7720_startup(struct usb_serial *serial) #endif /* LSR For Port 1 */ read_mos_reg(serial, 0, LSR, &data); - dbg("LSR:%x", data); + dev_dbg(&dev->dev, "LSR:%x\n", data); return 0; } @@ -2195,6 +2131,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 402c32d..d6d4eec 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -252,8 +252,6 @@ struct moschip_port { struct timer_list led_timer2; /* Timer for LED off */ }; -static bool debug; - /* * mos7840_set_reg_sync * To set the Control register by calling usb_fill_control_urb function @@ -265,7 +263,7 @@ static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg, { struct usb_device *dev = port->serial->dev; val = val & 0x00ff; - dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val); + dev_dbg(&port->dev, "mos7840_set_reg_sync offset is %x, value %x\n", reg, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, @@ -293,7 +291,7 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); *val = buf[0]; - dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val); + dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val); kfree(buf); return ret; @@ -316,21 +314,16 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, if (port->serial->num_ports == 4) { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", val); } else { if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); } else { - val |= - (((__u16) port->number - + val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); } } + dev_dbg(&port->dev, "%s application number is %x\n", __func__, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, MOS_WDR_TIMEOUT); @@ -354,27 +347,21 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, if (!buf) return -ENOMEM; - /* dbg("application number is %4x", - (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */ /* Wval is same as application number */ if (port->serial->num_ports == 4) { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", Wval); } else { if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); } else { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); } } + dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval); ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); @@ -384,14 +371,13 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, return ret; } -static void mos7840_dump_serial_port(struct moschip_port *mos7840_port) +static void mos7840_dump_serial_port(struct usb_serial_port *port, + struct moschip_port *mos7840_port) { - dbg("***************************************"); - dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset); - dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset); - dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset); - dbg("***************************************"); + dev_dbg(&port->dev, "SpRegOffset is %2x\n", mos7840_port->SpRegOffset); + dev_dbg(&port->dev, "ControlRegOffset is %2x\n", mos7840_port->ControlRegOffset); + dev_dbg(&port->dev, "DCRRegOffset is %2x\n", mos7840_port->DcrRegOffset); } @@ -450,8 +436,6 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) { struct async_icount *icount; - dbg("%s - %02x", __func__, new_lsr); - if (new_lsr & SERIAL_LSR_BI) { /* * Parity and Framing errors only count if they @@ -492,6 +476,7 @@ static void mos7840_control_callback(struct urb *urb) { unsigned char *data; struct moschip_port *mos7840_port; + struct device *dev = &urb->dev->dev; __u8 regval = 0x0; int result = 0; int status = urb->status; @@ -506,21 +491,19 @@ static void mos7840_control_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); goto exit; } - dbg("%s urb buffer size is %d", __func__, urb->actual_length); - dbg("%s mos7840_port->MsrLsr is %d port %d", __func__, - mos7840_port->MsrLsr, mos7840_port->port_num); + dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); + dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__, + mos7840_port->MsrLsr, mos7840_port->port_num); data = urb->transfer_buffer; regval = (__u8) data[0]; - dbg("%s data is %x", __func__, regval); + dev_dbg(dev, "%s data is %x\n", __func__, regval); if (mos7840_port->MsrLsr == 0) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) @@ -532,8 +515,7 @@ exit: result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); spin_unlock(&mos7840_port->pool_lock); if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", + dev_err(dev, "%s - Error %d submitting interrupt urb\n", __func__, result); } } @@ -570,12 +552,12 @@ static void mos7840_set_led_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d", + __func__, urb->status); break; default: - dbg("%s - nonzero urb status received: %d", __func__, - urb->status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d", + __func__, urb->status); } } @@ -650,12 +632,12 @@ static void mos7840_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -672,7 +654,7 @@ static void mos7840_interrupt_callback(struct urb *urb) * Byte 5 FIFO status for both */ if (length && length > 5) { - dbg("%s", "Wrong data !!!"); + dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n"); return; } @@ -689,17 +671,17 @@ static void mos7840_interrupt_callback(struct urb *urb) (__u16) (serial->minor)) + 1) << 8; if (mos7840_port->open) { if (sp[i] & 0x01) { - dbg("SP%d No Interrupt !!!", i); + dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i); } else { switch (sp[i] & 0x0f) { case SERIAL_IIR_RLS: - dbg("Serial Port %d: Receiver status error or ", i); - dbg("address bit detected in 9-bit mode"); + dev_dbg(&urb->dev->dev, "Serial Port %d: Receiver status error or \n", i); + dev_dbg(&urb->dev->dev, "address bit detected in 9-bit mode\n"); mos7840_port->MsrLsr = 1; wreg = LINE_STATUS_REGISTER; break; case SERIAL_IIR_MS: - dbg("Serial Port %d: Modem status change", i); + dev_dbg(&urb->dev->dev, "Serial Port %d: Modem status change\n", i); mos7840_port->MsrLsr = 0; wreg = MODEM_STATUS_REGISTER; break; @@ -731,11 +713,11 @@ static int mos7840_port_paranoia_check(struct usb_serial_port *port, const char *function) { if (!port) { - dbg("%s - port == NULL", function); + pr_debug("%s - port == NULL\n", function); return -1; } if (!port->serial) { - dbg("%s - port->serial == NULL", function); + pr_debug("%s - port->serial == NULL\n", function); return -1; } @@ -747,11 +729,11 @@ static int mos7840_serial_paranoia_check(struct usb_serial *serial, const char *function) { if (!serial) { - dbg("%s - serial == NULL", function); + pr_debug("%s - serial == NULL\n", function); return -1; } if (!serial->type) { - dbg("%s - serial->type == NULL!", function); + pr_debug("%s - serial->type == NULL!\n", function); return -1; } @@ -790,49 +772,44 @@ static void mos7840_bulk_in_callback(struct urb *urb) int status = urb->status; mos7840_port = urb->context; - if (!mos7840_port) { - dbg("%s", "NULL mos7840_port pointer"); + if (!mos7840_port) return; - } if (status) { - dbg("nonzero read bulk status received: %d", status); + dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status); mos7840_port->read_urb_busy = false; return; } - port = (struct usb_serial_port *)mos7840_port->port; + port = mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); mos7840_port->read_urb_busy = false; return; } serial = mos7840_get_usb_serial(port, __func__); if (!serial) { - dbg("%s", "Bad serial pointer"); mos7840_port->read_urb_busy = false; return; } data = urb->transfer_buffer; + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); if (urb->actual_length) { tty = tty_port_tty_get(&mos7840_port->port->port); if (tty) { tty_insert_flip_string(tty, data, urb->actual_length); - dbg(" %s ", data); tty_flip_buffer_push(tty); tty_kref_put(tty); } mos7840_port->icount.rx += urb->actual_length; smp_wmb(); - dbg("mos7840_port->icount.rx is %d:", - mos7840_port->icount.rx); + dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx); } if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!"); + dev_dbg(&port->dev, "%s", "URB KILLED !!!\n"); mos7840_port->read_urb_busy = false; return; } @@ -850,7 +827,7 @@ static void mos7840_bulk_in_callback(struct urb *urb) retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (retval) { - dbg("usb_submit_urb(read bulk) failed, retval = %d", retval); + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval); mos7840_port->read_urb_busy = false; } } @@ -864,11 +841,13 @@ static void mos7840_bulk_in_callback(struct urb *urb) static void mos7840_bulk_out_data_callback(struct urb *urb) { struct moschip_port *mos7840_port; + struct usb_serial_port *port; struct tty_struct *tty; int status = urb->status; int i; mos7840_port = urb->context; + port = mos7840_port->port; spin_lock(&mos7840_port->pool_lock); for (i = 0; i < NUM_URBS; i++) { if (urb == mos7840_port->write_urb_pool[i]) { @@ -879,16 +858,14 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) spin_unlock(&mos7840_port->pool_lock); if (status) { - dbg("nonzero write bulk status received:%d", status); + dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status); return; } - if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - tty = tty_port_tty_get(&mos7840_port->port->port); + tty = tty_port_tty_get(&port->port); if (tty && mos7840_port->open) tty_wakeup(tty); tty_kref_put(tty); @@ -929,17 +906,13 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) struct moschip_port *mos7840_port; struct moschip_port *port0; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return -ENODEV; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); + if (mos7840_serial_paranoia_check(serial, __func__)) return -ENODEV; - } mos7840_port = mos7840_get_port_private(port); port0 = mos7840_get_port_private(serial->port[0]); @@ -990,20 +963,20 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) Data = 0x0; status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("Reading Spreg failed"); + dev_dbg(&port->dev, "Reading Spreg failed\n"); return -1; } Data |= 0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed"); + dev_dbg(&port->dev, "writing Spreg failed\n"); return -1; } Data &= ~0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed"); + dev_dbg(&port->dev, "writing Spreg failed\n"); return -1; } /* End of block to be checked */ @@ -1012,7 +985,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data); if (status < 0) { - dbg("Reading Controlreg failed"); + dev_dbg(&port->dev, "Reading Controlreg failed\n"); return -1; } Data |= 0x08; /* Driver done bit */ @@ -1020,7 +993,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); if (status < 0) { - dbg("writing Controlreg failed"); + dev_dbg(&port->dev, "writing Controlreg failed\n"); return -1; } /* do register settings here */ @@ -1031,21 +1004,21 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) Data = 0x00; status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (status < 0) { - dbg("disabling interrupts failed"); + dev_dbg(&port->dev, "disabling interrupts failed\n"); return -1; } /* Set FIFO_CONTROL_REGISTER to the default value */ Data = 0x00; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); + dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n"); return -1; } Data = 0xcf; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); + dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n"); return -1; } @@ -1142,12 +1115,12 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the * * structures were not set up at that time.) */ - dbg("port number is %d", port->number); - dbg("serial number is %d", port->serial->minor); - dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress); - dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress); - dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress); - dbg("port's number in the device is %d", mos7840_port->port_num); + dev_dbg(&port->dev, "port number is %d\n", port->number); + dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor); + dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress); + dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress); + dev_dbg(&port->dev, "port's number in the device is %d\n", mos7840_port->port_num); mos7840_port->read_urb = port->read_urb; /* set up our bulk in urb */ @@ -1171,8 +1144,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) mos7840_bulk_in_callback, mos7840_port); } - dbg("mos7840_open: bulkin endpoint is %d", - port->bulk_in_endpointAddress); + dev_dbg(&port->dev, "%s: bulkin endpoint is %d\n", __func__, port->bulk_in_endpointAddress); mos7840_port->read_urb_busy = true; response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); if (response) { @@ -1197,9 +1169,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) mos7840_port->icount.tx = 0; mos7840_port->icount.rx = 0; - dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", - serial, mos7840_port, port); - return 0; } @@ -1221,10 +1190,8 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return 0; - } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) @@ -1238,7 +1205,7 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) } } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -1256,16 +1223,12 @@ static void mos7840_close(struct usb_serial_port *port) int j; __u16 Data; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); + if (!serial) return; - } mos7840_port = mos7840_get_port_private(port); port0 = mos7840_get_port_private(serial->port[0]); @@ -1291,27 +1254,26 @@ static void mos7840_close(struct usb_serial_port *port) * and interrupt read if they exists */ if (serial->dev) { if (mos7840_port->write_urb) { - dbg("%s", "Shutdown bulk write"); + dev_dbg(&port->dev, "%s", "Shutdown bulk write\n"); usb_kill_urb(mos7840_port->write_urb); } if (mos7840_port->read_urb) { - dbg("%s", "Shutdown bulk read"); + dev_dbg(&port->dev, "%s", "Shutdown bulk read\n"); usb_kill_urb(mos7840_port->read_urb); mos7840_port->read_urb_busy = false; } if ((&mos7840_port->control_urb)) { - dbg("%s", "Shutdown control read"); + dev_dbg(&port->dev, "%s", "Shutdown control read\n"); /*/ usb_kill_urb (mos7840_port->control_urb); */ } } /* if(mos7840_port->ctrl_buf != NULL) */ /* kfree(mos7840_port->ctrl_buf); */ port0->open_ports--; - dbg("mos7840_num_open_ports in close%d:in port%d", - port0->open_ports, port->number); + dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number); if (port0->open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { - dbg("%s", "Shutdown interrupt_in_urb"); + dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n"); usb_kill_urb(serial->port[0]->interrupt_in_urb); } } @@ -1363,7 +1325,7 @@ static void mos7840_block_until_chase_response(struct tty_struct *tty, /* No activity.. count down section */ wait--; if (wait == 0) { - dbg("%s - TIMEOUT", __func__); + dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__); return; } else { /* Reset timeout value back to seconds */ @@ -1384,16 +1346,12 @@ static void mos7840_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7840_port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); + if (!serial) return; - } mos7840_port = mos7840_get_port_private(port); @@ -1411,8 +1369,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state) /* FIXME: no locking on shadowLCR anywhere in driver */ mos7840_port->shadowLCR = data; - dbg("mcs7840_break mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, mos7840_port->shadowLCR); } @@ -1433,17 +1390,12 @@ static int mos7840_write_room(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - dbg("%s", " mos7840_write_room:leaving ..........."); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); + if (mos7840_port == NULL) return -1; - } spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { @@ -1453,7 +1405,7 @@ static int mos7840_write_room(struct tty_struct *tty) spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1; - dbg("%s - returns %d", __func__, room); + dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -1486,9 +1438,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, Data = 0x00; status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); mos7840_port->shadowLCR = Data; - dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data); - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data); + dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); /* Data = 0x03; */ /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */ @@ -1501,34 +1452,27 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */ Data = 0x00; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data); - dbg("mos7840_write:DLL value is %x", Data); + dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data); Data = 0x0; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data); - dbg("mos7840_write:DLM value is %x", Data); + dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data); Data = Data & ~SERIAL_LCR_DLAB; - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR); status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); #endif - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); + if (mos7840_serial_paranoia_check(serial, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_port is NULL"); + if (mos7840_port == NULL) return -1; - } /* try to find a free urb in the list */ urb = NULL; @@ -1538,14 +1482,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, if (!mos7840_port->busy[i]) { mos7840_port->busy[i] = 1; urb = mos7840_port->write_urb_pool[i]; - dbg("URB:%d", i); + dev_dbg(&port->dev, "URB:%d\n", i); break; } } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); if (urb == NULL) { - dbg("%s - no more free urbs", __func__); + dev_dbg(&port->dev, "%s - no more free urbs\n", __func__); goto exit; } @@ -1585,7 +1529,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, } data1 = urb->transfer_buffer; - dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); + dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); /* Turn on LED */ if (mos7840_port->has_led && !mos7840_port->led_flag) { @@ -1608,7 +1552,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, bytes_sent = transfer_size; mos7840_port->icount.tx += transfer_size; smp_wmb(); - dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx); + dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); exit: return bytes_sent; @@ -1626,12 +1570,8 @@ static void mos7840_throttle(struct tty_struct *tty) struct moschip_port *mos7840_port; int status; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - - dbg("- port %d", port->number); mos7840_port = mos7840_get_port_private(port); @@ -1639,7 +1579,7 @@ static void mos7840_throttle(struct tty_struct *tty) return; if (!mos7840_port->open) { - dbg("%s", "port not opened"); + dev_dbg(&port->dev, "%s", "port not opened\n"); return; } @@ -1672,16 +1612,14 @@ static void mos7840_unthrottle(struct tty_struct *tty) int status; struct moschip_port *mos7840_port = mos7840_get_port_private(port); - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } if (mos7840_port == NULL) return; if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -1726,7 +1664,7 @@ static int mos7840_tiocmget(struct tty_struct *tty) | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); - dbg("%s - 0x%04X", __func__, result); + dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result); return result; } @@ -1764,7 +1702,7 @@ static int mos7840_tiocmset(struct tty_struct *tty, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed"); + dev_dbg(&port->dev, "setting MODEM_CONTROL_REGISTER Failed\n"); return status; } @@ -1776,10 +1714,11 @@ static int mos7840_tiocmset(struct tty_struct *tty, * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ -static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, +static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port, + int baudRate, int *divisor, __u16 *clk_sel_val) { - dbg("%s - %d", __func__, baudRate); + dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate); if (baudRate <= 115200) { *divisor = 115200 / baudRate; @@ -1832,11 +1771,11 @@ static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, custom++; *divisor = custom; - dbg(" Baud %d = %d", baudrate, custom); + dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom); return 0; } - dbg("%s", " Baud calculation Failed..."); + dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n"); return -1; #endif } @@ -1860,21 +1799,17 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, if (mos7840_port == NULL) return -1; - port = (struct usb_serial_port *)mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + port = mos7840_port->port; + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(port->serial, __func__)) return -1; - } number = mos7840_port->port->number - mos7840_port->port->serial->minor; - dbg("%s - port = %d, baud = %d", __func__, - mos7840_port->port->number, baudRate); + dev_dbg(&port->dev, "%s - port = %d, baud = %d\n", __func__, + mos7840_port->port->number, baudRate); /* reset clk_uart_sel in spregOffset */ if (baudRate > 115200) { #ifdef HW_flow_control @@ -1885,7 +1820,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } #endif @@ -1898,7 +1833,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } #endif @@ -1908,19 +1843,19 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, if (1) { /* baudRate <= 115200) */ clk_sel_val = 0x0; Data = 0x0; - status = mos7840_calc_baud_rate_divisor(baudRate, &divisor, + status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor, &clk_sel_val); status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("reading spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n"); return -1; } Data = (Data & 0x8f) | clk_sel_val; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); + dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n"); return -1; } /* Calculate the Divisor */ @@ -1936,11 +1871,11 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, /* Write the divisor */ Data = (unsigned char)(divisor & 0xff); - dbg("set_serial_baud Value to write DLL is %x", Data); + dev_dbg(&port->dev, "set_serial_baud Value to write DLL is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); Data = (unsigned char)((divisor & 0xff00) >> 8); - dbg("set_serial_baud Value to write DLM is %x", Data); + dev_dbg(&port->dev, "set_serial_baud Value to write DLM is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); /* Disable access to divisor latch */ @@ -1975,24 +1910,18 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (mos7840_port == NULL) return; - port = (struct usb_serial_port *)mos7840_port->port; + port = mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(port->serial, __func__)) return; - } serial = port->serial; - dbg("%s - port %d", __func__, mos7840_port->port->number); - if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -2027,14 +1956,14 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) { lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "%s - parity = odd\n", __func__); } else { lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "%s - parity = even\n", __func__); } } else { - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "%s - parity = none\n", __func__); } if (cflag & CMSPAR) @@ -2043,10 +1972,10 @@ static void mos7840_change_port_settings(struct tty_struct *tty, /* Change the Stop bit */ if (cflag & CSTOPB) { lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__); } else { lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__); } /* Update the LCR with the correct value */ @@ -2054,8 +1983,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty, ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7840_port->shadowLCR |= (lData | lParity | lStop); - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is %x\n", __func__, + mos7840_port->shadowLCR); /* Disable Interrupts */ Data = 0x00; mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); @@ -2096,11 +2025,11 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (!baud) { /* pick a default, any default... */ - dbg("%s", "Picked default baud..."); + dev_dbg(&port->dev, "%s", "Picked default baud...\n"); baud = 9600; } - dbg("%s - baud rate = %d", __func__, baud); + dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud); status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud); /* Enable Interrupts */ @@ -2111,15 +2040,15 @@ static void mos7840_change_port_settings(struct tty_struct *tty, mos7840_port->read_urb_busy = true; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); mos7840_port->read_urb_busy = false; } } wake_up(&mos7840_port->delta_msr_wait); mos7840_port->delta_msr_cond = 1; - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", - mos7840_port->shadowLCR); + dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__, + mos7840_port->shadowLCR); } /***************************************************************************** @@ -2137,17 +2066,13 @@ static void mos7840_set_termios(struct tty_struct *tty, struct usb_serial *serial; struct moschip_port *mos7840_port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return; - } serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Invalid Serial"); + if (mos7840_serial_paranoia_check(serial, __func__)) return; - } mos7840_port = mos7840_get_port_private(port); @@ -2155,26 +2080,26 @@ static void mos7840_set_termios(struct tty_struct *tty, return; if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } - dbg("%s", "setting termios - "); + dev_dbg(&port->dev, "%s", "setting termios - \n"); cflag = tty->termios.c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); - dbg("%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); + dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, + old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); + dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); /* change the port settings to the new ones specified */ mos7840_change_port_settings(tty, mos7840_port, old_termios); if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!!!"); + dev_dbg(&port->dev, "%s", "URB KILLED !!!!!\n"); return; } @@ -2182,7 +2107,7 @@ static void mos7840_set_termios(struct tty_struct *tty, mos7840_port->read_urb_busy = true; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", + dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status); mos7840_port->read_urb_busy = false; } @@ -2207,10 +2132,8 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, unsigned int result = 0; count = mos7840_chars_in_buffer(tty); - if (count == 0) { - dbg("%s -- Empty", __func__); + if (count == 0) result = TIOCSER_TEMT; - } if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -2273,8 +2196,8 @@ static int mos7840_get_icount(struct tty_struct *tty, icount->brk = cnow.brk; icount->buf_overrun = cnow.buf_overrun; - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); + dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, + icount->rx, icount->tx); return 0; } @@ -2293,35 +2216,33 @@ static int mos7840_ioctl(struct tty_struct *tty, struct async_icount cnow; struct async_icount cprev; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); + if (mos7840_port_paranoia_check(port, __func__)) return -1; - } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return -1; - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); switch (cmd) { /* return number of bytes available */ case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return mos7840_get_lsr_info(tty, argp); case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return mos7840_get_serial_info(mos7840_port, argp); case TIOCSSERIAL: - dbg("%s (%d) TIOCSSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__); break; case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); cprev = mos7840_port->icount; while (1) { /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ @@ -2437,11 +2358,6 @@ static int mos7840_startup(struct usb_serial *serial) int i, status; __u16 Data; - if (!serial) { - dbg("%s", "Invalid Handler"); - return -1; - } - dev = serial->dev; /* we set up the pointers to the endpoints in the mos7840_open * @@ -2449,7 +2365,7 @@ static int mos7840_startup(struct usb_serial *serial) /* set up port private structures */ for (i = 0; i < serial->num_ports; ++i) { - dbg ("mos7840_startup: configuring port %d............", i); + dev_dbg(&dev->dev, "mos7840_startup: configuring port %d............\n", i); mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); if (mos7840_port == NULL) { dev_err(&dev->dev, "%s - Out of memory\n", __func__); @@ -2470,10 +2386,10 @@ static int mos7840_startup(struct usb_serial *serial) * usb-serial.c:get_free_serial() and cannot therefore be used * to index device instances */ mos7840_port->port_num = i + 1; - dbg ("serial->port[i]->number = %d", serial->port[i]->number); - dbg ("serial->port[i]->serial->minor = %d", serial->port[i]->serial->minor); - dbg ("mos7840_port->port_num = %d", mos7840_port->port_num); - dbg ("serial->minor = %d", serial->minor); + dev_dbg(&dev->dev, "serial->port[i]->number = %d\n", serial->port[i]->number); + dev_dbg(&dev->dev, "serial->port[i]->serial->minor = %d\n", serial->port[i]->serial->minor); + dev_dbg(&dev->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num); + dev_dbg(&dev->dev, "serial->minor = %d\n", serial->minor); if (mos7840_port->port_num == 1) { mos7840_port->SpRegOffset = 0x0; @@ -2500,18 +2416,17 @@ static int mos7840_startup(struct usb_serial *serial) mos7840_port->ControlRegOffset = 0xd; mos7840_port->DcrRegOffset = 0x1c; } - mos7840_dump_serial_port(mos7840_port); + mos7840_dump_serial_port(serial->port[i], mos7840_port); mos7840_set_port_private(serial->port[i], mos7840_port); /* enable rx_disable bit in control register */ status = mos7840_get_reg_sync(serial->port[i], mos7840_port->ControlRegOffset, &Data); if (status < 0) { - dbg("Reading ControlReg failed status-0x%x", status); + dev_dbg(&dev->dev, "Reading ControlReg failed status-0x%x\n", status); break; } else - dbg("ControlReg Reading success val is %x, status%d", - Data, status); + dev_dbg(&dev->dev, "ControlReg Reading success val is %x, status%d\n", Data, status); Data |= 0x08; /* setting driver done bit */ Data |= 0x04; /* sp1_bit to have cts change reflect in modem status reg */ @@ -2520,11 +2435,10 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], mos7840_port->ControlRegOffset, Data); if (status < 0) { - dbg("Writing ControlReg failed(rx_disable) status-0x%x", status); + dev_dbg(&dev->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status); break; } else - dbg("ControlReg Writing success(rx_disable) status%d", - status); + dev_dbg(&dev->dev, "ControlReg Writing success(rx_disable) status%d\n", status); /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 and 0x24 in DCR3 */ @@ -2532,61 +2446,57 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 0), Data); if (status < 0) { - dbg("Writing DCR0 failed status-0x%x", status); + dev_dbg(&dev->dev, "Writing DCR0 failed status-0x%x\n", status); break; } else - dbg("DCR0 Writing success status%d", status); + dev_dbg(&dev->dev, "DCR0 Writing success status%d\n", status); Data = 0x05; status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 1), Data); if (status < 0) { - dbg("Writing DCR1 failed status-0x%x", status); + dev_dbg(&dev->dev, "Writing DCR1 failed status-0x%x\n", status); break; } else - dbg("DCR1 Writing success status%d", status); + dev_dbg(&dev->dev, "DCR1 Writing success status%d\n", status); Data = 0x24; status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 2), Data); if (status < 0) { - dbg("Writing DCR2 failed status-0x%x", status); + dev_dbg(&dev->dev, "Writing DCR2 failed status-0x%x\n", status); break; } else - dbg("DCR2 Writing success status%d", status); + dev_dbg(&dev->dev, "DCR2 Writing success status%d\n", status); /* write values in clkstart0x0 and clkmulti 0x20 */ Data = 0x0; status = mos7840_set_reg_sync(serial->port[i], CLK_START_VALUE_REGISTER, Data); if (status < 0) { - dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status); + dev_dbg(&dev->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); break; } else - dbg("CLK_START_VALUE_REGISTER Writing success status%d", status); + dev_dbg(&dev->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status); Data = 0x20; status = mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER, Data); if (status < 0) { - dbg("Writing CLK_MULTI_REGISTER failed status-0x%x", - status); + dev_dbg(&dev->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status); goto error; } else - dbg("CLK_MULTI_REGISTER Writing success status%d", - status); + dev_dbg(&dev->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status); /* write value 0x0 to scratchpad register */ Data = 0x00; status = mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER, Data); if (status < 0) { - dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", - status); + dev_dbg(&dev->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status); break; } else - dbg("SCRATCH_PAD_REGISTER Writing success status%d", - status); + dev_dbg(&dev->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status); /* Zero Length flag register */ if ((mos7840_port->port_num != 1) @@ -2596,31 +2506,25 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], (__u16) (ZLP_REG1 + ((__u16)mos7840_port->port_num)), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num))); + dev_dbg(&dev->dev, "ZLIP offset %x\n", + (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num))); if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 2, status); + dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 2, status); break; } else - dbg("ZLP_REG%d Writing success status%d", - i + 2, status); + dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 2, status); } else { Data = 0xff; status = mos7840_set_reg_sync(serial->port[i], (__u16) (ZLP_REG1 + ((__u16)mos7840_port->port_num) - 0x1), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num) - 0x1)); + dev_dbg(&dev->dev, "ZLIP offset %x\n", + (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 1, status); + dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 1, status); break; } else - dbg("ZLP_REG%d Writing success status%d", - i + 1, status); + dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 1, status); } mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -2661,16 +2565,15 @@ static int mos7840_startup(struct usb_serial *serial) MODEM_CONTROL_REGISTER, 0x0300); } } - dbg ("mos7840_startup: all ports configured..........."); /* Zero Length flag enable */ Data = 0x0f; status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); if (status < 0) { - dbg("Writing ZLP_REG5 failed status-0x%x", status); + dev_dbg(&dev->dev, "Writing ZLP_REG5 failed status-0x%x\n", status); goto error; } else - dbg("ZLP_REG5 Writing success status%d", status); + dev_dbg(&dev->dev, "ZLP_REG5 Writing success status%d\n", status); /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2700,11 +2603,6 @@ static void mos7840_disconnect(struct usb_serial *serial) unsigned long flags; struct moschip_port *mos7840_port; - if (!serial) { - dbg("%s", "Invalid Handler"); - return; - } - /* check for the ports to be closed,close the ports and disconnect */ /* free private structure allocated for serial port * @@ -2712,7 +2610,6 @@ static void mos7840_disconnect(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg ("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { spin_lock_irqsave(&mos7840_port->pool_lock, flags); mos7840_port->zombie = 1; @@ -2732,11 +2629,6 @@ static void mos7840_release(struct usb_serial *serial) int i; struct moschip_port *mos7840_port; - if (!serial) { - dbg("%s", "Invalid Handler"); - return; - } - /* check for the ports to be closed,close the ports and disconnect */ /* free private structure allocated for serial port * @@ -2744,7 +2636,6 @@ static void mos7840_release(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { if (mos7840_port->has_led) { /* Turn off LED */ @@ -2801,6 +2692,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index d95452c..1566f8f 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -21,8 +21,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ @@ -55,8 +53,7 @@ static void navman_read_int_callback(struct urb *urb) goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); tty = tty_port_tty_get(&port->port); if (tty && urb->actual_length) { @@ -123,6 +120,3 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 6f3d705..6def58b 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -23,8 +23,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static bool debug; - /* * Version Information */ @@ -164,31 +162,21 @@ static void omninet_read_bulk_callback(struct urb *urb) struct omninet_header *header = (struct omninet_header *) &data[0]; int status = urb->status; int result; - int i; if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n", + __func__, status); return; } - if (debug && header->oh_xxx != 0x30) { - if (urb->actual_length) { - printk(KERN_DEBUG "%s: omninet_read %d: ", - __FILE__, header->oh_len); - for (i = 0; i < (header->oh_len + - OMNINET_HEADERLEN); i++) - printk("%.2x ", data[i]); - printk("\n"); - } - } - if (urb->actual_length && header->oh_len) { struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, + if (tty) { + tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, header->oh_len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } } /* Continue trying to always read */ @@ -212,12 +200,12 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, int result; if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dbg("%s - already writing", __func__); + dev_dbg(&port->dev, "%s - already writing\n", __func__); return 0; } @@ -226,8 +214,8 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - wport->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, + wport->write_urb->transfer_buffer); header->oh_seq = od->od_outseq++; header->oh_len = count; @@ -261,7 +249,7 @@ static int omninet_write_room(struct tty_struct *tty) if (test_bit(0, &wport->write_urbs_free)) room = wport->bulk_out_size - OMNINET_HEADERLEN; - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -275,8 +263,8 @@ static void omninet_write_bulk_callback(struct urb *urb) set_bit(0, &port->write_urbs_free); if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", + __func__, status); return; } @@ -304,6 +292,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 02cb1b7..41b1647 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -32,8 +32,6 @@ * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ #define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x065a, 0x0009) }, { }, @@ -78,17 +76,16 @@ static void opticon_read_bulk_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&priv->udev->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&priv->udev->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); if (urb->actual_length > 2) { data_length = urb->actual_length - 2; @@ -229,8 +226,8 @@ static void opticon_write_control_callback(struct urb *urb) kfree(urb->setup_packet); if (status) - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&priv->udev->dev, "%s - nonzero write bulk status received: %d\n", + __func__, status); spin_lock_irqsave(&priv->lock, flags); --priv->outstanding_urbs; @@ -253,7 +250,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT) { spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); return 0; } priv->outstanding_urbs++; @@ -276,7 +273,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, memcpy(buffer, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); + usb_serial_debug_data(&port->dev, __func__, count, buffer); /* The conncected devices do not have a bulk write endpoint, * to transmit data to de barcode device the control endpoint is used */ @@ -338,7 +335,7 @@ static int opticon_write_room(struct tty_struct *tty) spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); return 0; } spin_unlock_irqrestore(&priv->lock, flags); @@ -394,7 +391,7 @@ static int opticon_tiocmget(struct tty_struct *tty) result |= TIOCM_CTS; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - %x", __func__, result); + dev_dbg(&port->dev, "%s - %x\n", __func__, result); return result; } @@ -466,7 +463,7 @@ static int opticon_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct opticon_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: @@ -612,6 +609,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5ce88d1..30cff03 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -870,7 +870,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, @@ -1257,8 +1258,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &option_1port_device, NULL }; -static bool debug; - struct option_private { u8 bInterfaceNumber; }; @@ -1369,18 +1368,19 @@ static void option_instat_callback(struct urb *urb) { int err; int status = urb->status; - struct usb_serial_port *port = urb->context; + struct usb_serial_port *port = urb->context; + struct device *dev = &port->dev; struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); + dev_dbg(dev, "%s: urb %p port %p has data %p\n", __func__, urb, port, portdata); if (status == 0) { struct usb_ctrlrequest *req_pkt = (struct usb_ctrlrequest *)urb->transfer_buffer; if (!req_pkt) { - dbg("%s: NULL req_pkt", __func__); + dev_dbg(dev, "%s: NULL req_pkt\n", __func__); return; } if ((req_pkt->bRequestType == 0xA1) && @@ -1390,7 +1390,7 @@ static void option_instat_callback(struct urb *urb) urb->transfer_buffer + sizeof(struct usb_ctrlrequest)); - dbg("%s: signal x%x", __func__, signals); + dev_dbg(dev, "%s: signal x%x\n", __func__, signals); old_dcd_state = portdata->dcd_state; portdata->cts_state = 1; @@ -1406,17 +1406,17 @@ static void option_instat_callback(struct urb *urb) tty_kref_put(tty); } } else { - dbg("%s: type %x req %x", __func__, + dev_dbg(dev, "%s: type %x req %x\n", __func__, req_pkt->bRequestType, req_pkt->bRequest); } } else - dev_err(&port->dev, "%s: error %d\n", __func__, status); + dev_err(dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { err = usb_submit_urb(urb, GFP_ATOMIC); if (err) - dbg("%s: resubmit intr urb failed. (%d)", + dev_dbg(dev, "%s: resubmit intr urb failed. (%d)\n", __func__, err); } } @@ -1450,6 +1450,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 9f55556..933241f 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -66,8 +66,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static bool debug; - /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) #define OTI6858_REQ_T_GET_STATUS 0x01 @@ -256,11 +254,11 @@ static void setup_line(struct work_struct *work) priv->setup_done = 1; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } } @@ -310,11 +308,11 @@ static void send_data(struct work_struct *work) if (count == 0) { priv->flags.write_urb_in_use = 0; - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); } return; } @@ -325,8 +323,8 @@ static void send_data(struct work_struct *work) port->write_urb->transfer_buffer_length = count; result = usb_submit_urb(port->write_urb, GFP_NOIO); if (result != 0) { - dev_err_console(port, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err_console(port, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); priv->flags.write_urb_in_use = 0; } @@ -420,10 +418,8 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - if (!tty) { - dbg("%s(): no tty structures", __func__); + if (!tty) return; - } cflag = tty->termios.c_cflag; @@ -560,11 +556,11 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); kfree(buf); - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); + dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", + __func__, result); oti6858_close(port); return result; } @@ -586,14 +582,14 @@ static void oti6858_close(struct usb_serial_port *port) kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); - dbg("%s(): after buf_clear()", __func__); + dev_dbg(&port->dev, "%s(): after buf_clear()\n", __func__); /* cancel scheduled setup */ cancel_delayed_work_sync(&priv->delayed_setup_work); cancel_delayed_work_sync(&priv->delayed_write_work); /* shutdown our urbs */ - dbg("%s(): shutting down urbs", __func__); + dev_dbg(&port->dev, "%s(): shutting down urbs\n", __func__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); @@ -607,8 +603,8 @@ static int oti6858_tiocmset(struct tty_struct *tty, unsigned long flags; u8 control; - dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", - __func__, port->number, set, clear); + dev_dbg(&port->dev, "%s(set = 0x%08x, clear = 0x%08x)\n", + __func__, set, clear); /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); @@ -655,7 +651,7 @@ static int oti6858_tiocmget(struct tty_struct *tty) if ((pin_state & PIN_DCD) != 0) result |= TIOCM_CD; - dbg("%s() = 0x%08x", __func__, result); + dev_dbg(&port->dev, "%s() = 0x%08x\n", __func__, result); return result; } @@ -700,15 +696,14 @@ static int oti6858_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", - __func__, port->number, cmd, arg); + dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg); switch (cmd) { case TIOCMIWAIT: - dbg("%s(): TIOCMIWAIT", __func__); + dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__); return wait_modem_info(port, arg); default: - dbg("%s(): 0x%04x not supported", __func__, cmd); + dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd); break; } return -ENOIOCTLCMD; @@ -738,12 +733,12 @@ static void oti6858_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s(): nonzero urb status received: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): nonzero urb status received: %d\n", + __func__, status); break; } @@ -759,8 +754,7 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } @@ -774,8 +768,7 @@ static void oti6858_read_int_callback(struct urb *urb) priv->transient = 4; priv->setup_done = 0; resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); + dev_dbg(&port->dev, "%s(): scheduling setup_line()\n", __func__); schedule_delayed_work(&priv->delayed_setup_work, 0); } } @@ -826,7 +819,7 @@ static void oti6858_read_int_callback(struct urb *urb) if (resubmit) { int result; -/* dbg("%s(): submitting interrupt urb", __func__); */ +/* dev_dbg(&urb->dev->dev, "%s(): submitting interrupt urb\n", __func__); */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result != 0) { dev_err(&urb->dev->dev, @@ -851,7 +844,7 @@ static void oti6858_read_bulk_callback(struct urb *urb) spin_unlock_irqrestore(&priv->lock, flags); if (status != 0) { - dbg("%s(): unable to handle the error, exiting", __func__); + dev_dbg(&urb->dev->dev, "%s(): unable to handle the error, exiting\n", __func__); return; } @@ -885,15 +878,13 @@ static void oti6858_write_bulk_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); + dev_dbg(&urb->dev->dev, "%s(): urb shutting down with status: %d\n", __func__, status); priv->flags.write_urb_in_use = 0; return; default: /* error in the urb, so we have to resubmit it */ - dbg("%s(): nonzero write bulk status received: %d", - __func__, status); - dbg("%s(): overflow in write", __func__); + dev_dbg(&urb->dev->dev, "%s(): nonzero write bulk status received: %d\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s(): overflow in write\n", __func__); port->write_urb->transfer_buffer_length = 1; result = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -908,7 +899,7 @@ static void oti6858_write_bulk_callback(struct urb *urb) priv->flags.write_urb_in_use = 0; /* schedule the interrupt urb if we are still open */ - dbg("%s(): submitting interrupt urb", __func__); + dev_dbg(&port->dev, "%s(): submitting interrupt urb\n", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result != 0) { dev_err(&port->dev, "%s(): failed submitting int urb," @@ -922,7 +913,3 @@ MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); MODULE_VERSION(OTI6858_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable debug output"); - diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 2b9108a..892ebdc7 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -36,8 +36,6 @@ */ #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, @@ -741,7 +739,7 @@ static void pl2303_read_int_callback(struct urb *urb) goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); pl2303_update_line_status(port, data, actual_length); @@ -839,7 +837,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index a4edc7e..9b1b96f 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -36,8 +36,6 @@ #define UTSTARCOM_PRODUCT_UM175_V1 0x3712 #define UTSTARCOM_PRODUCT_UM175_V2 0x3714 #define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715 -#define PANTECH_PRODUCT_UML190_VZW 0x3716 -#define PANTECH_PRODUCT_UML290_VZW 0x3718 /* CMOTECH devices */ #define CMOTECH_VENDOR_ID 0x16d8 @@ -68,11 +66,9 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) }, /* NMEA */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */ + { USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index bfd5077..c3ddb65 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -22,8 +22,6 @@ #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" -static bool debug; - #define DEVICE_G1K(v, p) \ USB_DEVICE(v, p), .driver_info = 1 @@ -305,6 +303,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL v2"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 7df9cdb..2cdfdcc 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -27,8 +27,6 @@ #include <linux/serial_reg.h> #include <linux/uaccess.h> -static bool debug; - /* default urb timeout for usb operations */ #define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT @@ -1089,7 +1087,7 @@ static int qt2_write(struct tty_struct *tty, data = write_urb->transfer_buffer; spin_lock_irqsave(&port_priv->urb_lock, flags); if (port_priv->urb_in_use == true) { - printk(KERN_INFO "qt2_write - urb is in use\n"); + dev_err(&port->dev, "qt2_write - urb is in use\n"); goto write_out; } @@ -1146,6 +1144,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 36e9d9f..c949ce6 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -62,6 +62,7 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/errno.h> @@ -81,11 +82,9 @@ #define CONFIG_USB_SERIAL_SAFE_PADDED 0 #endif -static bool debug; static bool safe = 1; static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED; -#define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB Safe Encapsulated Serial" @@ -100,9 +99,6 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - module_param(safe, bool, 0); MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); @@ -315,13 +311,9 @@ static int __init safe_init(void) { int i; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - /* if we have vendor / product parameters patch them into id list */ if (vendor || product) { - printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n", - vendor, product); + pr_info("vendor: %x product: %x\n", vendor, product); for (i = 0; i < ARRAY_SIZE(id_table); i++) { if (!id_table[i].idVendor && !id_table[i].idProduct) { diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index b14ebbd..01d882c 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -46,7 +46,6 @@ allocations > PAGE_SIZE and the number of packets in a page is an integer 512 is the largest possible packet on EHCI */ -static bool debug; static bool nmea; /* Used in interface blacklisting */ @@ -518,7 +517,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, memcpy(buffer, buf, writesize); - usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer); + usb_serial_debug_data(&port->dev, __func__, writesize, buffer); usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, @@ -595,8 +594,8 @@ static void sierra_indat_callback(struct urb *urb) tty_flip_buffer_push(tty); tty_kref_put(tty); - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(&port->dev, __func__, + urb->actual_length, data); } } else { dev_dbg(&port->dev, "%s: empty read urb" @@ -765,7 +764,6 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); - /* debug */ dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__, dir == USB_DIR_IN ? 'i' : 'o', urb, buf); } else { @@ -1082,6 +1080,3 @@ MODULE_LICENSE("GPL"); module_param(nmea, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(nmea, "NMEA streaming"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index ab68a4d..9716efe 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -33,8 +33,6 @@ #define DRIVER_VERSION "v0.10" #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" -static bool debug; - #define SPCP8x5_007_VID 0x04FC #define SPCP8x5_007_PID 0x0201 #define SPCP8x5_008_VID 0x04fc @@ -665,6 +663,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index cf2d30c..015810b 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -46,8 +46,6 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -static bool debug; - /* Version Information */ #define DRIVER_VERSION "v0.1" #define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver" @@ -135,7 +133,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, int result; if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); + dev_dbg(&dev->dev, "%s - DTR|RTS not being set|cleared\n", __func__); return 0; /* no change */ } @@ -148,7 +146,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, result = ssu100_setregister(dev, 0, UART_MCR, urb_value); if (result < 0) - dbg("%s Error from MODEM_CTRL urb", __func__); + dev_dbg(&dev->dev, "%s Error from MODEM_CTRL urb\n", __func__); return result; } @@ -164,7 +162,7 @@ static int ssu100_initdevice(struct usb_device *dev) result = ssu100_getdevice(dev, data); if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result); goto out; } @@ -172,25 +170,25 @@ static int ssu100_initdevice(struct usb_device *dev) result = ssu100_setdevice(dev, data); if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result); goto out; } result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0); if (result < 0) { - dbg("%s - set prebuffer level failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - set prebuffer level failed %i\n", __func__, result); goto out; } result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0); if (result < 0) { - dbg("%s - set ATFprebuffer level failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - set ATFprebuffer level failed %i\n", __func__, result); goto out; } result = ssu100_getdevice(dev, data); if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result); goto out; } @@ -201,7 +199,7 @@ static int ssu100_initdevice(struct usb_device *dev) result = ssu100_setdevice(dev, data); if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); + dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result); goto out; } @@ -249,7 +247,7 @@ static void ssu100_set_termios(struct tty_struct *tty, if (!baud) baud = 9600; - dbg("%s - got baud = %d\n", __func__, baud); + dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud); divisor = MAX_BAUD_RATE / baud; @@ -261,7 +259,7 @@ static void ssu100_set_termios(struct tty_struct *tty, result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value); if (result < 0) - dbg("%s - set uart failed", __func__); + dev_dbg(&port->dev, "%s - set uart failed\n", __func__); if (cflag & CRTSCTS) result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, @@ -270,7 +268,7 @@ static void ssu100_set_termios(struct tty_struct *tty, result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, 0, 0); if (result < 0) - dbg("%s - set HW flow control failed", __func__); + dev_dbg(&port->dev, "%s - set HW flow control failed\n", __func__); if (I_IXOFF(tty) || I_IXON(tty)) { u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty))); @@ -282,7 +280,7 @@ static void ssu100_set_termios(struct tty_struct *tty, 0, 0); if (result < 0) - dbg("%s - set SW flow control failed", __func__); + dev_dbg(&port->dev, "%s - set SW flow control failed\n", __func__); } @@ -304,7 +302,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) QT_TRANSFER_IN, 0x01, 0, data, 2, 300); if (result < 0) { - dbg("%s - open failed %i", __func__, result); + dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result); kfree(data); return result; } @@ -319,7 +317,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) /* set to 9600 */ result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300); if (result < 0) - dbg("%s - set uart failed", __func__); + dev_dbg(&port->dev, "%s - set uart failed\n", __func__); if (tty) ssu100_set_termios(tty, port, &tty->termios); @@ -423,7 +421,7 @@ static int ssu100_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s cmd 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCGSERIAL: @@ -437,7 +435,7 @@ static int ssu100_ioctl(struct tty_struct *tty, break; } - dbg("%s arg not supported", __func__); + dev_dbg(&port->dev, "%s arg not supported\n", __func__); return -ENOIOCTLCMD; } @@ -668,6 +666,3 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index e53d2aa..701fffa 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -20,8 +20,6 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static bool debug; - static const struct usb_device_id id_table[] = { { USB_DEVICE(0x05e0, 0x0600) }, { }, @@ -71,8 +69,7 @@ static void symbol_int_callback(struct urb *urb) goto exit; } - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); if (urb->actual_length > 1) { data_length = urb->actual_length - 1; @@ -292,6 +289,3 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index f502a16..6f49392 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -40,7 +40,6 @@ /* Defines */ -#define TI_DRIVER_VERSION "v0.10" #define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>" #define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" @@ -141,8 +140,8 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, static int ti_command_in_sync(struct ti_device *tdev, __u8 command, __u16 moduleid, __u16 value, __u8 *data, int size); -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte); +static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, + unsigned long addr, __u8 mask, __u8 byte); static int ti_download_firmware(struct ti_device *tdev); @@ -150,7 +149,6 @@ static int ti_download_firmware(struct ti_device *tdev); /* Data */ /* module parameters */ -static bool debug; static int closing_wait = TI_DEFAULT_CLOSING_WAIT; static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; static unsigned int vendor_3410_count; @@ -277,7 +275,6 @@ static struct usb_serial_driver * const serial_drivers[] = { MODULE_AUTHOR(TI_DRIVER_AUTHOR); MODULE_DESCRIPTION(TI_DRIVER_DESC); -MODULE_VERSION(TI_DRIVER_VERSION); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("ti_3410.fw"); @@ -288,9 +285,6 @@ MODULE_FIRMWARE("mts_edge.fw"); MODULE_FIRMWARE("mts_mt9234mu.fw"); MODULE_FIRMWARE("mts_mt9234zba.fw"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes"); - module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain in close, in .01 secs, default is 4000"); @@ -316,7 +310,6 @@ MODULE_DEVICE_TABLE(usb, ti_id_table_combined); static int __init ti_init(void) { int i, j, c; - int ret; /* insert extra vendor and product ids */ c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1; @@ -339,11 +332,7 @@ static int __init ti_init(void) ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } - ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined); - if (ret == 0) - printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":" - TI_DRIVER_DESC "\n"); - return ret; + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined); } static void __exit ti_exit(void) @@ -364,10 +353,11 @@ static int ti_startup(struct usb_serial *serial) int i; - dbg("%s - product 0x%4X, num configurations %d, configuration value %d", - __func__, le16_to_cpu(dev->descriptor.idProduct), - dev->descriptor.bNumConfigurations, - dev->actconfig->desc.bConfigurationValue); + dev_dbg(&dev->dev, + "%s - product 0x%4X, num configurations %d, configuration value %d", + __func__, le16_to_cpu(dev->descriptor.idProduct), + dev->descriptor.bNumConfigurations, + dev->actconfig->desc.bConfigurationValue); /* create device structure */ tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); @@ -382,8 +372,8 @@ static int ti_startup(struct usb_serial *serial) /* determine device type */ if (usb_match_id(serial->interface, ti_id_table_3410)) tdev->td_is_3410 = 1; - dbg("%s - device type is %s", __func__, - tdev->td_is_3410 ? "3410" : "5052"); + dev_dbg(&dev->dev, "%s - device type is %s\n", __func__, + tdev->td_is_3410 ? "3410" : "5052"); /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { @@ -501,20 +491,17 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) /* start interrupt urb the first time a port is opened on this device */ if (tdev->td_open_port_count == 0) { - dbg("%s - start interrupt in urb", __func__); + dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__); urb = tdev->td_serial->port[0]->interrupt_in_urb; if (!urb) { - dev_err(&port->dev, "%s - no interrupt urb\n", - __func__); + dev_err(&port->dev, "%s - no interrupt urb\n", __func__); status = -EINVAL; goto release_lock; } urb->context = tdev; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { - dev_err(&port->dev, - "%s - submit interrupt urb failed, %d\n", - __func__, status); + dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __func__, status); goto release_lock; } } @@ -522,16 +509,16 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - dbg("%s - sending TI_OPEN_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", - __func__, status); + __func__, status); goto unlink_int_urb; } - dbg("%s - sending TI_START_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_START_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -540,7 +527,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dbg("%s - sending TI_PURGE_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_PURGE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_PURGE_PORT, (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); if (status) { @@ -564,7 +551,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - dbg("%s - sending TI_OPEN_PORT (2)", __func__); + dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { @@ -573,7 +560,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dbg("%s - sending TI_START_PORT (2)", __func__); + dev_dbg(&port->dev, "%s - sending TI_START_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -583,7 +570,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) } /* start read urb */ - dbg("%s - start read urb", __func__); + dev_dbg(&port->dev, "%s - start read urb\n", __func__); urb = port->read_urb; if (!urb) { dev_err(&port->dev, "%s - no read urb\n", __func__); @@ -609,7 +596,7 @@ unlink_int_urb: usb_kill_urb(port->serial->port[0]->interrupt_in_urb); release_lock: mutex_unlock(&tdev->td_open_close_lock); - dbg("%s - exit %d", __func__, status); + dev_dbg(&port->dev, "%s - exit %d\n", __func__, status); return status; } @@ -637,7 +624,7 @@ static void ti_close(struct usb_serial_port *port) port_number = port->number - port->serial->minor; - dbg("%s - sending TI_CLOSE_PORT", __func__); + dev_dbg(&port->dev, "%s - sending TI_CLOSE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_CLOSE_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) @@ -664,7 +651,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, struct ti_port *tport = usb_get_serial_port_data(port); if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } @@ -693,7 +680,7 @@ static int ti_write_room(struct tty_struct *tty) room = kfifo_avail(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -712,7 +699,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -755,8 +742,7 @@ static int ti_get_icount(struct tty_struct *tty, struct ti_port *tport = usb_get_serial_port_data(port); struct async_icount cnow = tport->tp_icount; - dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, + dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__, cnow.rx, cnow.tx); icount->cts = cnow.cts; @@ -782,22 +768,22 @@ static int ti_ioctl(struct tty_struct *tty, struct async_icount cnow; struct async_icount cprev; - dbg("%s - port %d, cmd = 0x%04X", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd); if (tport == NULL) return -ENODEV; switch (cmd) { case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return ti_get_serial_info(tport, (struct serial_struct __user *)arg); case TIOCSSERIAL: - dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__); return ti_set_serial_info(tty, tport, (struct serial_struct __user *)arg); case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); cprev = tport->tp_icount; while (1) { interruptible_sleep_on(&tport->tp_msr_wait); @@ -834,9 +820,9 @@ static void ti_set_termios(struct tty_struct *tty, cflag = tty->termios.c_cflag; iflag = tty->termios.c_iflag; - dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag); - dbg("%s - old clfag %08x, old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); + dev_dbg(&port->dev, "%s - cflag %08x, iflag %08x\n", __func__, cflag, iflag); + dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__, + old_termios->c_cflag, old_termios->c_iflag); if (tport == NULL) return; @@ -926,8 +912,11 @@ static void ti_set_termios(struct tty_struct *tty, if ((cflag & CBAUD) != B0) tty_encode_baud_rate(tty, baud, baud); - dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", - __func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); + dev_dbg(&port->dev, + "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", + __func__, baud, config->wBaudRate, config->wFlags, + config->bDataBits, config->bParity, config->bStopBits, + config->cXon, config->cXoff, config->bUartMode); cpu_to_be16s(&config->wBaudRate); cpu_to_be16s(&config->wFlags); @@ -979,7 +968,7 @@ static int ti_tiocmget(struct tty_struct *tty) | ((msr & TI_MSR_RI) ? TIOCM_RI : 0) | ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0); - dbg("%s - 0x%04X", __func__, result); + dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result); return result; } @@ -1024,19 +1013,19 @@ static void ti_break(struct tty_struct *tty, int break_state) struct ti_port *tport = usb_get_serial_port_data(port); int status; - dbg("%s - state = %d", __func__, break_state); + dev_dbg(&port->dev, "%s - state = %d\n", __func__, break_state); if (tport == NULL) return; ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0); - status = ti_write_byte(tport->tp_tdev, + status = ti_write_byte(port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); if (status) - dbg("%s - error setting break, %d", __func__, status); + dev_dbg(&port->dev, "%s - error setting break, %d\n", __func__, status); } @@ -1061,18 +1050,17 @@ static void ti_interrupt_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); tdev->td_urb_error = 1; return; default: - dev_err(dev, "%s - nonzero urb status, %d\n", - __func__, status); + dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); tdev->td_urb_error = 1; goto exit; } if (length != 2) { - dbg("%s - bad packet size, %d", __func__, length); + dev_dbg(dev, "%s - bad packet size, %d\n", __func__, length); goto exit; } @@ -1084,8 +1072,8 @@ static void ti_interrupt_callback(struct urb *urb) port_number = TI_GET_PORT_FROM_CODE(data[0]); function = TI_GET_FUNC_FROM_CODE(data[0]); - dbg("%s - port_number %d, function %d, data 0x%02X", - __func__, port_number, function, data[1]); + dev_dbg(dev, "%s - port_number %d, function %d, data 0x%02X\n", + __func__, port_number, function, data[1]); if (port_number >= serial->num_ports) { dev_err(dev, "%s - bad port number, %d\n", @@ -1102,12 +1090,12 @@ static void ti_interrupt_callback(struct urb *urb) switch (function) { case TI_CODE_DATA_ERROR: dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", - __func__, port_number, data[1]); + __func__, port_number, data[1]); break; case TI_CODE_MODEM_STATUS: msr = data[1]; - dbg("%s - port %d, msr 0x%02X", __func__, port_number, msr); + dev_dbg(dev, "%s - port %d, msr 0x%02X\n", __func__, port_number, msr); ti_handle_new_msr(tport, msr); break; @@ -1140,7 +1128,7 @@ static void ti_bulk_in_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; wake_up_interruptible(&tport->tp_write_wait); return; @@ -1162,11 +1150,11 @@ static void ti_bulk_in_callback(struct urb *urb) tty = tty_port_tty_get(&port->port); if (tty) { if (urb->actual_length) { - usb_serial_debug_data(debug, dev, __func__, - urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(dev, __func__, urb->actual_length, + urb->transfer_buffer); if (!tport->tp_is_open) - dbg("%s - port closed, dropping data", + dev_dbg(dev, "%s - port closed, dropping data\n", __func__); else ti_recv(&urb->dev->dev, tty, @@ -1208,7 +1196,7 @@ static void ti_bulk_out_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; wake_up_interruptible(&tport->tp_write_wait); return; @@ -1268,8 +1256,8 @@ static void ti_send(struct ti_port *tport) spin_unlock_irqrestore(&tport->tp_lock, flags); - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, count, + port->write_urb->transfer_buffer); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, @@ -1307,7 +1295,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) unsigned long flags; int status; - status = ti_write_byte(tport->tp_tdev, + status = ti_write_byte(tport->tp_port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_MCR, TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr); @@ -1344,7 +1332,7 @@ static int ti_get_lsr(struct ti_port *tport) goto free_data; } - dbg("%s - lsr 0x%02X", __func__, data->bLSR); + dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR); tport->tp_lsr = data->bLSR; @@ -1401,7 +1389,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) struct tty_struct *tty; unsigned long flags; - dbg("%s - msr 0x%02X", __func__, msr); + dev_dbg(&tport->tp_port->dev, "%s - msr 0x%02X\n", __func__, msr); if (msr & TI_MSR_DELTA_MASK) { spin_lock_irqsave(&tport->tp_lock, flags); @@ -1560,21 +1548,21 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, } -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte) +static int ti_write_byte(struct usb_serial_port *port, + struct ti_device *tdev, unsigned long addr, + __u8 mask, __u8 byte) { int status; unsigned int size; struct ti_write_data_bytes *data; - struct device *dev = &tdev->td_serial->dev->dev; - dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X", - __func__, addr, mask, byte); + dev_dbg(&port->dev, "%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X\n", __func__, + addr, mask, byte); size = sizeof(struct ti_write_data_bytes) + 2; data = kmalloc(size, GFP_KERNEL); if (!data) { - dev_err(dev, "%s - out of memory\n", __func__); + dev_err(&port->dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -1590,7 +1578,7 @@ static int ti_write_byte(struct ti_device *tdev, unsigned long addr, (__u8 *)data, size); if (status < 0) - dev_err(dev, "%s - failed, %d\n", __func__, status); + dev_err(&port->dev, "%s - failed, %d\n", __func__, status); kfree(data); @@ -1615,7 +1603,7 @@ static int ti_do_download(struct usb_device *dev, int pipe, - sizeof(struct ti_firmware_header))); header->bCheckSum = cs; - dbg("%s - downloading firmware", __func__); + dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__); for (pos = 0; pos < size; pos += done) { len = min(size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE); status = usb_bulk_msg(dev, pipe, buffer + pos, len, @@ -1691,7 +1679,7 @@ static int ti_download_firmware(struct ti_device *tdev) status = ti_do_download(dev, pipe, buffer, fw_p->size); kfree(buffer); } else { - dbg("%s ENOMEM\n", __func__); + dev_dbg(&dev->dev, "%s ENOMEM\n", __func__); status = -ENOMEM; } release_firmware(fw_p); @@ -1701,7 +1689,7 @@ static int ti_download_firmware(struct ti_device *tdev) return status; } - dbg("%s - download successful", __func__); + dev_dbg(&dev->dev, "%s - download successful\n", __func__); return 0; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index aa4b0d7..73b8e05 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -17,6 +17,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -37,10 +39,7 @@ #include <linux/kfifo.h> #include "pl2303.h" -/* - * Version Information - */ -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" #define DRIVER_DESC "USB Serial Driver core" /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead @@ -50,7 +49,6 @@ drivers depend on it. */ -static bool debug; /* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; static DEFINE_MUTEX(table_lock); @@ -87,7 +85,7 @@ static struct usb_serial *get_free_serial(struct usb_serial *serial, unsigned int i, j; int good_spot; - dbg("%s %d", __func__, num_ports); + dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports); *minor = 0; mutex_lock(&table_lock); @@ -107,7 +105,7 @@ static struct usb_serial *get_free_serial(struct usb_serial *serial, *minor = i; j = 0; - dbg("%s - minor base = %d", __func__, *minor); + dev_dbg(&serial->interface->dev, "%s - minor base = %d\n", __func__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) { serial_table[i] = serial; serial->port[j++]->number = i; @@ -123,8 +121,6 @@ static void return_serial(struct usb_serial *serial) { int i; - dbg("%s", __func__); - mutex_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) serial_table[serial->minor + i] = NULL; @@ -139,8 +135,6 @@ static void destroy_serial(struct kref *kref) serial = to_usb_serial(kref); - dbg("%s - %s", __func__, serial->type->description); - /* return the minor range that this device had */ if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); @@ -191,8 +185,6 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) struct usb_serial_port *port; int retval = -ENODEV; - dbg("%s", __func__); - serial = usb_serial_get_by_index(idx); if (!serial) return retval; @@ -256,7 +248,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); return tty_port_open(&port->port, tty, filp); } @@ -287,14 +279,16 @@ static void serial_down(struct tty_port *tport) static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); tty_port_hangup(&port->port); } static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); tty_port_close(&port->port, tty, filp); } @@ -319,7 +313,7 @@ static void serial_cleanup(struct tty_struct *tty) if (port->port.console) return; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); tty->driver_data = NULL; @@ -344,7 +338,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf, if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); + dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__, + port->number, count); /* pass on to the driver specific version of this function */ retval = port->serial->type->write(tty, port, buf, count); @@ -357,7 +352,8 @@ exit: static int serial_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* pass on to the driver specific version of this function */ return port->serial->type->write_room(tty); } @@ -365,7 +361,8 @@ static int serial_write_room(struct tty_struct *tty) static int serial_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* if the device was unplugged then any remaining characters fell out of the connector ;) */ @@ -378,7 +375,8 @@ static int serial_chars_in_buffer(struct tty_struct *tty) static void serial_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* pass on to the driver specific version of this function */ if (port->serial->type->throttle) @@ -388,7 +386,8 @@ static void serial_throttle(struct tty_struct *tty) static void serial_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* pass on to the driver specific version of this function */ if (port->serial->type->unthrottle) @@ -401,7 +400,8 @@ static int serial_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; int retval = -ENODEV; - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); + dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__, + port->number, cmd); /* pass on to the driver specific version of this function if it is available */ @@ -415,7 +415,8 @@ static int serial_ioctl(struct tty_struct *tty, static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* pass on to the driver specific version of this function if it is available */ @@ -429,7 +430,7 @@ static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); /* pass on to the driver specific version of this function if it is available */ @@ -444,7 +445,6 @@ static int serial_proc_show(struct seq_file *m, void *v) int i; char tmp[40]; - dbg("%s", __func__); seq_puts(m, "usbserinfo:1.0 driver:2.0\n"); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial = usb_serial_get_by_index(i); @@ -489,7 +489,7 @@ static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); if (port->serial->type->tiocmget) return port->serial->type->tiocmget(tty); @@ -501,7 +501,7 @@ static int serial_tiocmset(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); if (port->serial->type->tiocmset) return port->serial->type->tiocmset(tty, set, clear); @@ -513,7 +513,7 @@ static int serial_get_icount(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); @@ -537,12 +537,12 @@ static void usb_serial_port_work(struct work_struct *work) container_of(work, struct usb_serial_port, work); struct tty_struct *tty; - dbg("%s - port %d", __func__, port->number); - tty = tty_port_tty_get(&port->port); if (!tty) return; + dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + tty_wakeup(tty); tty_kref_put(tty); } @@ -575,7 +575,7 @@ static void port_release(struct device *dev) struct usb_serial_port *port = to_usb_serial_port(dev); int i; - dbg ("%s - %s", __func__, dev_name(dev)); + dev_dbg(dev, "%s\n", __func__); /* * Stop all the traffic before cancelling the work, so that @@ -644,12 +644,12 @@ static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, id = usb_match_id(intf, drv->id_table); if (id) { - dbg("static descriptor matches"); + dev_dbg(&intf->dev, "static descriptor matches\n"); goto exit; } id = match_dynamic_id(intf, drv); if (id) - dbg("dynamic descriptor matches"); + dev_dbg(&intf->dev, "dynamic descriptor matches\n"); exit: return id; } @@ -703,6 +703,7 @@ static const struct tty_port_operations serial_port_ops = { static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { + struct device *ddev = &interface->dev; struct usb_device *dev = interface_to_usbdev(interface); struct usb_serial *serial = NULL; struct usb_serial_port *port; @@ -729,13 +730,13 @@ static int usb_serial_probe(struct usb_interface *interface, type = search_serial_device(interface); if (!type) { mutex_unlock(&table_lock); - dbg("none matched"); + dev_dbg(ddev, "none matched\n"); return -ENODEV; } if (!try_module_get(type->driver.owner)) { mutex_unlock(&table_lock); - dev_err(&interface->dev, "module get failed, exiting\n"); + dev_err(ddev, "module get failed, exiting\n"); return -EIO; } mutex_unlock(&table_lock); @@ -743,7 +744,7 @@ static int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { module_put(type->driver.owner); - dev_err(&interface->dev, "%s - out of memory\n", __func__); + dev_err(ddev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -755,7 +756,7 @@ static int usb_serial_probe(struct usb_interface *interface, retval = type->probe(serial, id); if (retval) { - dbg("sub driver rejected device"); + dev_dbg(ddev, "sub driver rejected device\n"); usb_serial_put(serial); module_put(type->driver.owner); return retval; @@ -770,28 +771,28 @@ static int usb_serial_probe(struct usb_interface *interface, if (usb_endpoint_is_bulk_in(endpoint)) { /* we found a bulk in endpoint */ - dbg("found bulk in on endpoint %d", i); + dev_dbg(ddev, "found bulk in on endpoint %d\n", i); bulk_in_endpoint[num_bulk_in] = endpoint; ++num_bulk_in; } if (usb_endpoint_is_bulk_out(endpoint)) { /* we found a bulk out endpoint */ - dbg("found bulk out on endpoint %d", i); + dev_dbg(ddev, "found bulk out on endpoint %d\n", i); bulk_out_endpoint[num_bulk_out] = endpoint; ++num_bulk_out; } if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ - dbg("found interrupt in on endpoint %d", i); + dev_dbg(ddev, "found interrupt in on endpoint %d\n", i); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } if (usb_endpoint_is_int_out(endpoint)) { /* we found an interrupt out endpoint */ - dbg("found interrupt out on endpoint %d", i); + dev_dbg(ddev, "found interrupt out on endpoint %d\n", i); interrupt_out_endpoint[num_interrupt_out] = endpoint; ++num_interrupt_out; } @@ -815,7 +816,7 @@ static int usb_serial_probe(struct usb_interface *interface, endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint)) { /* we found a interrupt in endpoint */ - dbg("found interrupt in for Prolific device on separate interface"); + dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } @@ -827,7 +828,7 @@ static int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { - dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); + dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); usb_serial_put(serial); module_put(type->driver.owner); return -ENODEV; @@ -840,14 +841,13 @@ static int usb_serial_probe(struct usb_interface *interface, if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { - dev_err(&interface->dev, - "Generic device with no bulk out, not allowed.\n"); + dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); usb_serial_put(serial); module_put(type->driver.owner); return -EIO; } - dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); - dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); + dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); + dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); } #endif if (!num_ports) { @@ -865,8 +865,7 @@ static int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_out = num_interrupt_out; /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", - type->description); + dev_info(ddev, "%s converter detected\n", type->description); /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here because some devices have more @@ -877,8 +876,7 @@ static int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; - dbg("%s - setting up %d port structures for this device", - __func__, max_endpoints); + dev_dbg(ddev, "setting up %d port structures for this device", max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); if (!port) @@ -911,15 +909,13 @@ static int usb_serial_probe(struct usb_interface *interface, set_bit(j, &port->read_urbs_free); port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); if (!port->read_urbs[j]) { - dev_err(&interface->dev, - "No free urbs available\n"); + dev_err(ddev, "No free urbs available\n"); goto probe_error; } port->bulk_in_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); if (!port->bulk_in_buffers[j]) { - dev_err(&interface->dev, - "Couldn't allocate bulk_in_buffer\n"); + dev_err(ddev, "Couldn't allocate bulk_in_buffer\n"); goto probe_error; } usb_fill_bulk_urb(port->read_urbs[j], dev, @@ -949,15 +945,13 @@ static int usb_serial_probe(struct usb_interface *interface, set_bit(j, &port->write_urbs_free); port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); if (!port->write_urbs[j]) { - dev_err(&interface->dev, - "No free urbs available\n"); + dev_err(ddev, "No free urbs available\n"); goto probe_error; } port->bulk_out_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); if (!port->bulk_out_buffers[j]) { - dev_err(&interface->dev, - "Couldn't allocate bulk_out_buffer\n"); + dev_err(ddev, "Couldn't allocate bulk_out_buffer\n"); goto probe_error; } usb_fill_bulk_urb(port->write_urbs[j], dev, @@ -978,8 +972,7 @@ static int usb_serial_probe(struct usb_interface *interface, port = serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->interrupt_in_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); + dev_err(ddev, "No free urbs available\n"); goto probe_error; } buffer_size = usb_endpoint_maxp(endpoint); @@ -988,8 +981,7 @@ static int usb_serial_probe(struct usb_interface *interface, port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!port->interrupt_in_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_in_buffer\n"); + dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n"); goto probe_error; } usb_fill_int_urb(port->interrupt_in_urb, dev, @@ -1000,7 +992,7 @@ static int usb_serial_probe(struct usb_interface *interface, endpoint->bInterval); } } else if (num_interrupt_in) { - dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined"); + dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n"); } if (serial->type->write_int_callback) { @@ -1009,8 +1001,7 @@ static int usb_serial_probe(struct usb_interface *interface, port = serial->port[i]; port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->interrupt_out_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); + dev_err(ddev, "No free urbs available\n"); goto probe_error; } buffer_size = usb_endpoint_maxp(endpoint); @@ -1020,8 +1011,7 @@ static int usb_serial_probe(struct usb_interface *interface, port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!port->interrupt_out_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_out_buffer\n"); + dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n"); goto probe_error; } usb_fill_int_urb(port->interrupt_out_urb, dev, @@ -1032,7 +1022,7 @@ static int usb_serial_probe(struct usb_interface *interface, endpoint->bInterval); } } else if (num_interrupt_out) { - dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); + dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n"); } usb_set_intfdata(interface, serial); @@ -1060,7 +1050,7 @@ static int usb_serial_probe(struct usb_interface *interface, serial->disconnected = 1; if (get_free_serial(serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); + dev_err(ddev, "No more free serial devices\n"); goto probe_error; } serial->minor = minor; @@ -1069,18 +1059,17 @@ static int usb_serial_probe(struct usb_interface *interface, for (i = 0; i < num_ports; ++i) { port = serial->port[i]; dev_set_name(&port->dev, "ttyUSB%d", port->number); - dbg ("%s - registering %s", __func__, dev_name(&port->dev)); + dev_dbg(ddev, "registering %s", dev_name(&port->dev)); device_enable_async_suspend(&port->dev); retval = device_add(&port->dev); if (retval) - dev_err(&port->dev, "Error registering port device, " - "continuing\n"); + dev_err(ddev, "Error registering port device, continuing\n"); } serial->disconnected = 0; - usb_serial_console_init(debug, minor); + usb_serial_console_init(minor); exit: module_put(type->driver.owner); return 0; @@ -1099,7 +1088,6 @@ static void usb_serial_disconnect(struct usb_interface *interface) struct usb_serial_port *port; usb_serial_console_disconnect(serial); - dbg("%s", __func__); mutex_lock(&serial->disc_mutex); /* must set a flag, to signal subdrivers */ @@ -1234,8 +1222,7 @@ static int __init usb_serial_init(void) result = bus_register(&usb_serial_bus_type); if (result) { - printk(KERN_ERR "usb-serial: %s - registering bus driver " - "failed\n", __func__); + pr_err("%s - registering bus driver failed\n", __func__); goto exit_bus; } @@ -1255,29 +1242,24 @@ static int __init usb_serial_init(void) tty_set_operations(usb_serial_tty_driver, &serial_ops); result = tty_register_driver(usb_serial_tty_driver); if (result) { - printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n", - __func__); + pr_err("%s - tty_register_driver failed\n", __func__); goto exit_reg_driver; } /* register the USB driver */ result = usb_register(&usb_serial_driver); if (result < 0) { - printk(KERN_ERR "usb-serial: %s - usb_register failed\n", - __func__); + pr_err("%s - usb_register failed\n", __func__); goto exit_tty; } /* register the generic driver, if we should */ - result = usb_serial_generic_register(debug); + result = usb_serial_generic_register(); if (result < 0) { - printk(KERN_ERR "usb-serial: %s - registering generic " - "driver failed\n", __func__); + pr_err("%s - registering generic driver failed\n", __func__); goto exit_generic; } - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return result; exit_generic: @@ -1290,8 +1272,7 @@ exit_reg_driver: bus_unregister(&usb_serial_bus_type); exit_bus: - printk(KERN_ERR "usb-serial: %s - returning with error %d\n", - __func__, result); + pr_err("%s - returning with error %d\n", __func__, result); put_tty_driver(usb_serial_tty_driver); return result; } @@ -1317,7 +1298,7 @@ module_exit(usb_serial_exit); do { \ if (!type->function) { \ type->function = usb_serial_generic_##function; \ - dbg("Had to override the " #function \ + pr_debug("Had to override the " #function \ " usb serial operation with the generic one.");\ } \ } while (0) @@ -1360,12 +1341,10 @@ static int usb_serial_register(struct usb_serial_driver *driver) retval = usb_serial_bus_register(driver); if (retval) { - printk(KERN_ERR "usb-serial: problem %d when registering " - "driver %s\n", retval, driver->description); + pr_err("problem %d when registering driver %s\n", retval, driver->description); list_del(&driver->driver_list); } else - printk(KERN_INFO "USB Serial support registered for %s\n", - driver->description); + pr_info("USB Serial support registered for %s\n", driver->description); mutex_unlock(&table_lock); return retval; @@ -1373,8 +1352,7 @@ static int usb_serial_register(struct usb_serial_driver *driver) static void usb_serial_deregister(struct usb_serial_driver *device) { - printk(KERN_INFO "USB Serial deregistering driver %s\n", - device->description); + pr_info("USB Serial deregistering driver %s\n", device->description); mutex_lock(&table_lock); list_del(&device->driver_list); usb_serial_bus_deregister(device); @@ -1425,9 +1403,10 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[] /* we only set the reset_resume field if the serial_driver has one */ for (sd = serial_drivers; *sd; ++sd) { - if ((*sd)->reset_resume) + if ((*sd)->reset_resume) { udriver->reset_resume = usb_serial_reset_resume; break; + } } rc = usb_register(udriver); @@ -1477,6 +1456,3 @@ EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 72b678d..e42aa39 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -37,8 +37,6 @@ #include <linux/serial.h> #include "usb-wwan.h" -static bool debug; - void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; @@ -178,7 +176,7 @@ int usb_wwan_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dbg("%s cmd 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCGSERIAL: @@ -191,7 +189,7 @@ int usb_wwan_ioctl(struct tty_struct *tty, break; } - dbg("%s arg not supported", __func__); + dev_dbg(&port->dev, "%s arg not supported\n", __func__); return -ENOIOCTLCMD; } @@ -212,7 +210,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, portdata = usb_get_serial_port_data(port); intfdata = port->serial->private; - dbg("%s: write (%d chars)", __func__, count); + dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count); i = 0; left = count; @@ -229,8 +227,8 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, usb_unlink_urb(this_urb); continue; } - dbg("%s: endpoint %d buf %d", __func__, - usb_pipeendpoint(this_urb->pipe), i); + dev_dbg(&port->dev, "%s: endpoint %d buf %d\n", __func__, + usb_pipeendpoint(this_urb->pipe), i); err = usb_autopm_get_interface_async(port->serial->interface); if (err < 0) @@ -249,8 +247,9 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, spin_unlock_irqrestore(&intfdata->susp_lock, flags); err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err) { - dbg("usb_submit_urb %p (write bulk) failed " - "(%d)", this_urb, err); + dev_dbg(&port->dev, + "usb_submit_urb %p (write bulk) failed (%d)\n", + this_urb, err); clear_bit(i, &portdata->out_busy); spin_lock_irqsave(&intfdata->susp_lock, flags); intfdata->in_flight--; @@ -267,7 +266,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, } count -= left; - dbg("%s: wrote (did %d)", __func__, count); + dev_dbg(&port->dev, "%s: wrote (did %d)\n", __func__, count); return count; } EXPORT_SYMBOL(usb_wwan_write); @@ -278,15 +277,17 @@ static void usb_wwan_indat_callback(struct urb *urb) int endpoint; struct usb_serial_port *port; struct tty_struct *tty; + struct device *dev; unsigned char *data = urb->transfer_buffer; int status = urb->status; endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; + dev = &port->dev; if (status) { - dbg("%s: nonzero status: %d on endpoint %02x.", - __func__, status, endpoint); + dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n", + __func__, status, endpoint); } else { tty = tty_port_tty_get(&port->port); if (tty) { @@ -295,7 +296,7 @@ static void usb_wwan_indat_callback(struct urb *urb) urb->actual_length); tty_flip_buffer_push(tty); } else - dbg("%s: empty read urb received", __func__); + dev_dbg(dev, "%s: empty read urb received\n", __func__); tty_kref_put(tty); } @@ -303,8 +304,7 @@ static void usb_wwan_indat_callback(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { if (err != -EPERM) { - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); + dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err); /* busy also in error unless we are killed */ usb_mark_last_busy(port->serial->dev); } @@ -356,7 +356,7 @@ int usb_wwan_write_room(struct tty_struct *tty) data_len += OUT_BUFLEN; } - dbg("%s: %d", __func__, data_len); + dev_dbg(&port->dev, "%s: %d\n", __func__, data_len); return data_len; } EXPORT_SYMBOL(usb_wwan_write_room); @@ -378,7 +378,7 @@ int usb_wwan_chars_in_buffer(struct tty_struct *tty) if (this_urb && test_bit(i, &portdata->out_busy)) data_len += this_urb->transfer_buffer_length; } - dbg("%s: %d", __func__, data_len); + dev_dbg(&port->dev, "%s: %d\n", __func__, data_len); return data_len; } EXPORT_SYMBOL(usb_wwan_chars_in_buffer); @@ -401,8 +401,8 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) continue; err = usb_submit_urb(urb, GFP_KERNEL); if (err) { - dbg("%s: submit urb %d failed (%d) %d", - __func__, i, err, urb->transfer_buffer_length); + dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n", + __func__, i, err, urb->transfer_buffer_length); } } @@ -458,7 +458,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ if (urb == NULL) { - dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); + dev_dbg(&serial->interface->dev, + "%s: alloc for endpoint %d failed.\n", __func__, + endpoint); return NULL; } @@ -522,8 +524,8 @@ int usb_wwan_startup(struct usb_serial *serial) port = serial->port[i]; portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); if (!portdata) { - dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", - __func__, i); + dev_dbg(&port->dev, "%s: kmalloc for usb_wwan_port_private (%d) failed!.\n", + __func__, i); return 1; } init_usb_anchor(&portdata->delayed); @@ -548,7 +550,8 @@ int usb_wwan_startup(struct usb_serial *serial) continue; err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (err) - dbg("%s: submit irq_in urb failed %d", __func__, err); + dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n", + __func__, err); } usb_wwan_setup_urbs(serial); return 0; @@ -683,11 +686,11 @@ int usb_wwan_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; if (!port->interrupt_in_urb) { - dbg("%s: No interrupt URB for port %d", __func__, i); + dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__); continue; } err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("Submitted interrupt URB for port %d (result %d)", i, err); + dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err); if (err < 0) { dev_err(&port->dev, "%s: Error %d for interrupt URB\n", __func__, err); @@ -733,6 +736,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index f253c91..1129aa7 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -51,9 +51,6 @@ static int palm_os_3_probe(struct usb_serial *serial, static int palm_os_4_probe(struct usb_serial *serial, const struct usb_device_id *id); -/* Parameters that may be passed into the module. */ -static bool debug; - static struct usb_device_id id_table [] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), .driver_info = (kernel_ulong_t)&palm_os_3_probe }, @@ -310,8 +307,8 @@ static void visor_read_int_callback(struct urb *urb) * Rumor has it this endpoint is used to notify when data * is ready to be read from the bulk ones. */ - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + urb->transfer_buffer); exit: result = usb_submit_urb(urb, GFP_ATOMIC); @@ -443,8 +440,7 @@ static int palm_os_4_probe(struct usb_serial *serial, dev_err(dev, "%s - error %d getting connection info\n", __func__, retval); else - usb_serial_debug_data(debug, &serial->dev->dev, __func__, - retval, transfer_buffer); + usb_serial_debug_data(dev, __func__, retval, transfer_buffer); kfree(transfer_buffer); return 0; @@ -625,6 +621,3 @@ module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index b36077d..346c7ef 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -32,12 +32,9 @@ #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/usb/serial.h> -#include <linux/firmware.h> -#include <linux/ihex.h> +#include <linux/usb/ezusb.h> #include "whiteheat.h" /* WhiteHEAT specific commands */ -static bool debug; - #ifndef CMSPAR #define CMSPAR 0 #endif @@ -195,84 +192,15 @@ static int firm_report_tx_done(struct usb_serial_port *port); static int whiteheat_firmware_download(struct usb_serial *serial, const struct usb_device_id *id) { - int response, ret = -ENOENT; - const struct firmware *loader_fw = NULL, *firmware_fw = NULL; - const struct ihex_binrec *record; + int response; - if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat.fw\" failed\n", __func__); - goto out; - } - if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat_loader.fw\" failed\n", - __func__); - goto out; + response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat_loader.fw"); + if (response >= 0) { + response = ezusb_fx1_ihex_firmware_download(serial->dev, "whiteheat.fw"); + if (response >= 0) + return 0; } - ret = 0; - response = ezusb_set_reset (serial, 1); - - record = (const struct ihex_binrec *)loader_fw->data; - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for loader (%d %04X %p %d)\n", - __func__, response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - - response = ezusb_set_reset(serial, 0); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) - record = ihex_next_binrec(record); - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa3); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for first firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for second firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - ret = 0; - response = ezusb_set_reset (serial, 0); - out: - release_firmware(loader_fw); - release_firmware(firmware_fw); - return ret; + return -ENOENT; } @@ -533,7 +461,7 @@ static int whiteheat_ioctl(struct tty_struct *tty, struct serial_struct serstruct; void __user *user_arg = (void __user *)arg; - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); + dev_dbg(&port->dev, "%s - cmd 0x%.4x\n", __func__, cmd); switch (cmd) { case TIOCGSERIAL: @@ -580,7 +508,7 @@ static void command_port_write_callback(struct urb *urb) int status = urb->status; if (status) { - dbg("nonzero urb status: %d", status); + dev_dbg(&urb->dev->dev, "nonzero urb status: %d\n", status); return; } } @@ -596,19 +524,18 @@ static void command_port_read_callback(struct urb *urb) command_info = usb_get_serial_port_data(command_port); if (!command_info) { - dbg("%s - command_info is NULL, exiting.", __func__); + dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__); return; } if (status) { - dbg("%s - nonzero urb status: %d", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status); if (status != -ENOENT) command_info->command_finished = WHITEHEAT_CMD_FAILURE; wake_up(&command_info->wait_command); return; } - usb_serial_debug_data(debug, &command_port->dev, - __func__, urb->actual_length, data); + usb_serial_debug_data(&command_port->dev, __func__, urb->actual_length, data); if (data[0] == WHITEHEAT_CMD_COMPLETE) { command_info->command_finished = WHITEHEAT_CMD_COMPLETE; @@ -619,19 +546,19 @@ static void command_port_read_callback(struct urb *urb) } else if (data[0] == WHITEHEAT_EVENT) { /* These are unsolicited reports from the firmware, hence no waiting command to wakeup */ - dbg("%s - event received", __func__); + dev_dbg(&urb->dev->dev, "%s - event received\n", __func__); } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1); command_info->command_finished = WHITEHEAT_CMD_COMPLETE; wake_up(&command_info->wait_command); } else - dbg("%s - bad reply from firmware", __func__); + dev_dbg(&urb->dev->dev, "%s - bad reply from firmware\n", __func__); /* Continue trying to always read */ result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC); if (result) - dbg("%s - failed resubmitting read urb, error %d", + dev_dbg(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result); } @@ -645,11 +572,12 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; struct whiteheat_private *info; + struct device *dev = &port->dev; __u8 *transfer_buffer; int retval = 0; int t; - dbg("%s - command %d", __func__, command); + dev_dbg(dev, "%s - command %d\n", __func__, command); command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); @@ -662,7 +590,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, command_port->write_urb->transfer_buffer_length = datasize + 1; retval = usb_submit_urb(command_port->write_urb, GFP_NOIO); if (retval) { - dbg("%s - submit urb failed", __func__); + dev_dbg(dev, "%s - submit urb failed\n", __func__); goto exit; } @@ -673,19 +601,19 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, usb_kill_urb(command_port->write_urb); if (command_info->command_finished == false) { - dbg("%s - command timed out.", __func__); + dev_dbg(dev, "%s - command timed out.\n", __func__); retval = -ETIMEDOUT; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) { - dbg("%s - command failed.", __func__); + dev_dbg(dev, "%s - command failed.\n", __func__); retval = -EIO; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) { - dbg("%s - command completed.", __func__); + dev_dbg(dev, "%s - command completed.\n", __func__); switch (command) { case WHITEHEAT_GET_DTR_RTS: info = usb_get_serial_port_data(port); @@ -723,6 +651,7 @@ static int firm_close(struct usb_serial_port *port) static void firm_setup_port(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct device *dev = &port->dev; struct whiteheat_port_settings port_settings; unsigned int cflag = tty->termios.c_cflag; @@ -736,7 +665,7 @@ static void firm_setup_port(struct tty_struct *tty) default: case CS8: port_settings.bits = 8; break; } - dbg("%s - data bits = %d", __func__, port_settings.bits); + dev_dbg(dev, "%s - data bits = %d\n", __func__, port_settings.bits); /* determine the parity */ if (cflag & PARENB) @@ -752,14 +681,14 @@ static void firm_setup_port(struct tty_struct *tty) port_settings.parity = WHITEHEAT_PAR_EVEN; else port_settings.parity = WHITEHEAT_PAR_NONE; - dbg("%s - parity = %c", __func__, port_settings.parity); + dev_dbg(dev, "%s - parity = %c\n", __func__, port_settings.parity); /* figure out the stop bits requested */ if (cflag & CSTOPB) port_settings.stop = 2; else port_settings.stop = 1; - dbg("%s - stop bits = %d", __func__, port_settings.stop); + dev_dbg(dev, "%s - stop bits = %d\n", __func__, port_settings.stop); /* figure out the flow control settings */ if (cflag & CRTSCTS) @@ -767,7 +696,7 @@ static void firm_setup_port(struct tty_struct *tty) WHITEHEAT_HFLOW_RTS); else port_settings.hflow = WHITEHEAT_HFLOW_NONE; - dbg("%s - hardware flow control = %s %s %s %s", __func__, + dev_dbg(dev, "%s - hardware flow control = %s %s %s %s\n", __func__, (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "", @@ -778,16 +707,15 @@ static void firm_setup_port(struct tty_struct *tty) port_settings.sflow = WHITEHEAT_SFLOW_RXTX; else port_settings.sflow = WHITEHEAT_SFLOW_NONE; - dbg("%s - software flow control = %c", __func__, port_settings.sflow); + dev_dbg(dev, "%s - software flow control = %c\n", __func__, port_settings.sflow); port_settings.xon = START_CHAR(tty); port_settings.xoff = STOP_CHAR(tty); - dbg("%s - XON = %2x, XOFF = %2x", - __func__, port_settings.xon, port_settings.xoff); + dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ port_settings.baud = tty_get_baud_rate(tty); - dbg("%s - baud rate = %d", __func__, port_settings.baud); + dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud); /* fixme: should set validated settings */ tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud); @@ -918,6 +846,3 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("whiteheat.fw"); MODULE_FIRMWARE("whiteheat_loader.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c new file mode 100644 index 0000000..39ee737 --- /dev/null +++ b/drivers/usb/serial/zte_ev.c @@ -0,0 +1,307 @@ +/* + * ZTE_EV USB serial driver + * + * Copyright (C) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org> + * Copyright (C) 2012 Linux Foundation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This driver is based on code found in a ZTE_ENV patch that modified + * the usb-serial generic driver. Comments were left in that I think + * show the commands used to talk to the device, but I am not sure. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define MAX_SETUP_DATA_SIZE 32 + +static void debug_data(struct device *dev, const char *function, int len, + const unsigned char *data, int result) +{ + dev_dbg(dev, "result = %d\n", result); + if (result == len) + dev_dbg(dev, "%s - length = %d, data = %*ph\n", function, + len, len, data); +} + +static int zte_ev_usb_serial_open(struct tty_struct *tty, + struct usb_serial_port *port) +{ + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; + int result = 0; + int len; + unsigned char *buf; + + if (port->number != 0) + return -ENODEV; + + buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* send 1st ctl cmd(CTL 21 22 01 00 00 00 00 00) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0001, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 2st cmd and recieve data */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 25.1.0(5) + * 16.0 DI 00 96 00 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 3 cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0 + * 16.0 DO 80 25 00 00 00 00 08 .%..... 30.2.0 + */ + len = 0x0007; + buf[0] = 0x80; + buf[1] = 0x25; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 4 cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 5 cmd */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0 + * 16.0 DI 80 25 00 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 6 cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 34.1.0 + * 16.0 DO 80 25 00 00 00 00 08 + */ + len = 0x0007; + buf[0] = 0x80; + buf[1] = 0x25; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + kfree(buf); + + return usb_serial_generic_open(tty, port); +} + +/* + * CTL 21 22 02 00 00 00 00 00 CLASS 338.1.0 + * + * 16.1 DI a1 20 00 00 00 00 02 00 02 00 . ........ 340.1.0 + * 16.0 CTL 21 22 03 00 00 00 00 00 CLASS 341.1.0 + * + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 346.1.0(3) + * 16.0 DI 00 08 07 00 00 00 08 ....... 346.2.0 + * + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 349.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 349.2.0 + * + * 16.0 CTL 21 22 03 00 00 00 00 00 CLASS 350.1.0(2) + * + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 352.1.0 + * 16.0 DI 00 c2 01 00 00 00 08 ....... 352.2.0 + * + * 16.1 DI a1 20 00 00 00 00 02 00 02 00 . ........ 353.1.0 + * + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 354.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 354.2.0 + * + * 16.0 CTL 21 22 03 00 00 00 00 00 +*/ + +static void zte_ev_usb_serial_close(struct usb_serial_port *port) +{ + struct usb_device *udev = port->serial->dev; + struct device *dev = &port->dev; + int result = 0; + int len; + unsigned char *buf; + + if (port->number != 0) + return; + + buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); + if (!buf) + return; + + /* send 1st ctl cmd(CTL 21 22 02 00 00 00 00 00) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0002, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 2st ctl cmd(CTL 21 22 03 00 00 00 00 00 ) */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 3st cmd and recieve data */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 25.1.0(5) + * 16.0 DI 00 08 07 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 4 cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 .%..... 30.2.0 + */ + len = 0x0007; + buf[0] = 0x00; + buf[1] = 0xc2; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 5 cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + /* send 6 cmd */ + /* + * 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0 + * 16.0 DI 00 c2 01 00 00 00 08 + */ + len = 0x0007; + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x21, 0xa1, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 7 cmd */ + /* + * 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 354.1.0 + * 16.0 DO 00 c2 01 00 00 00 08 ....... 354.2.0 + */ + len = 0x0007; + buf[0] = 0x00; + buf[1] = 0xc2; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x20, 0x21, + 0x0000, 0x0000, buf, len, + HZ * USB_CTRL_GET_TIMEOUT); + debug_data(dev, __func__, len, buf, result); + + /* send 8 cmd */ + /* + * 16.0 CTL 21 22 03 00 00 00 00 00 + */ + len = 0; + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x22, 0x21, + 0x0003, 0x0000, NULL, len, + HZ * USB_CTRL_GET_TIMEOUT); + dev_dbg(dev, "result = %d\n", result); + + kfree(buf); + + usb_serial_generic_close(port); +} + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x19d2, 0xffff) }, /* AC8700 */ + { USB_DEVICE(0x19d2, 0xfffe) }, + { USB_DEVICE(0x19d2, 0xfffd) }, /* MG880 */ + { USB_DEVICE(0x05C6, 0x3197) }, + { USB_DEVICE(0x05C6, 0x6000) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_serial_driver zio_device = { + .driver = { + .owner = THIS_MODULE, + .name = "zte_ev", + }, + .id_table = id_table, + .num_ports = 1, + .open = zte_ev_usb_serial_open, + .close = zte_ev_usb_serial_close, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &zio_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 7691c86..0ae7bb6 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -213,17 +213,3 @@ config USB_UAS say 'Y' or 'M' here and the kernel will use the right driver. If you compile this driver as a module, it will be named uas. - -config USB_LIBUSUAL - bool "The shared table of common (or usual) storage devices" - depends on USB - help - This module contains a table of common (or usual) devices - for usb-storage and ub drivers, and allows to switch binding - of these devices without rebuilding modules. - - Typical syntax of /etc/modprobe.d/*conf is: - - options libusual bias="ub" - - If unsure, say N. diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 82e6416..4cd5548 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -12,16 +12,9 @@ obj-$(CONFIG_USB_STORAGE) += usb-storage.o usb-storage-y := scsiglue.o protocol.o transport.o usb.o usb-storage-y += initializers.o sierra_ms.o option_ms.o - +usb-storage-y += usual-tables.o usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o -ifeq ($(CONFIG_USB_LIBUSUAL),) - usb-storage-y += usual-tables.o -else - obj-$(CONFIG_USB) += usb-libusual.o - usb-libusual-y := libusual.o usual-tables.o -endif - obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o obj-$(CONFIG_USB_STORAGE_DATAFAB) += ums-datafab.o diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index bab8c8f..be5564c 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -137,7 +137,7 @@ static int init_alauda(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id alauda_usb_ids[] = { # include "unusual_alauda.h" diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index 5fe451d..070b5c0 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -41,7 +41,7 @@ MODULE_LICENSE("GPL"); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id cypress_usb_ids[] = { # include "unusual_cypress.h" diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 35e9c51..494fee5 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -86,7 +86,7 @@ static int datafab_determine_lun(struct us_data *us, vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id datafab_usb_ids[] = { # include "unusual_datafab.h" diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index b28f2ad..118b134 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -29,9 +29,21 @@ #include "protocol.h" #include "debug.h" +#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin" +#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin" +#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin" +#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin" +#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin" +#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin" + MODULE_DESCRIPTION("Driver for ENE UB6250 reader"); MODULE_LICENSE("GPL"); - +MODULE_FIRMWARE(SD_INIT1_FIRMWARE); +MODULE_FIRMWARE(SD_INIT2_FIRMWARE); +MODULE_FIRMWARE(SD_RW_FIRMWARE); +MODULE_FIRMWARE(MS_INIT_FIRMWARE); +MODULE_FIRMWARE(MSP_RW_FIRMWARE); +MODULE_FIRMWARE(MS_RW_FIRMWARE); /* * The table of devices @@ -40,7 +52,7 @@ MODULE_LICENSE("GPL"); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags)} static struct usb_device_id ene_ub6250_usb_ids[] = { # include "unusual_ene_ub6250.h" @@ -1883,28 +1895,28 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) /* For SD */ case SD_INIT1_PATTERN: US_DEBUGP("SD_INIT1_PATTERN\n"); - fw_name = "ene-ub6250/sd_init1.bin"; + fw_name = SD_INIT1_FIRMWARE; break; case SD_INIT2_PATTERN: US_DEBUGP("SD_INIT2_PATTERN\n"); - fw_name = "ene-ub6250/sd_init2.bin"; + fw_name = SD_INIT2_FIRMWARE; break; case SD_RW_PATTERN: - US_DEBUGP("SD_RDWR_PATTERN\n"); - fw_name = "ene-ub6250/sd_rdwr.bin"; + US_DEBUGP("SD_RW_PATTERN\n"); + fw_name = SD_RW_FIRMWARE; break; /* For MS */ case MS_INIT_PATTERN: US_DEBUGP("MS_INIT_PATTERN\n"); - fw_name = "ene-ub6250/ms_init.bin"; + fw_name = MS_INIT_FIRMWARE; break; case MSP_RW_PATTERN: US_DEBUGP("MSP_RW_PATTERN\n"); - fw_name = "ene-ub6250/msp_rdwr.bin"; + fw_name = MSP_RW_FIRMWARE; break; case MS_RW_PATTERN: US_DEBUGP("MS_RW_PATTERN\n"); - fw_name = "ene-ub6250/ms_rdwr.bin"; + fw_name = MS_RW_FIRMWARE; break; default: US_DEBUGP("----------- Unknown PATTERN ----------\n"); diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 042cf9e..e6df087 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -117,7 +117,7 @@ static int init_freecom(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id freecom_usb_ids[] = { # include "unusual_freecom.h" diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 31fa24e..ecea478 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -74,7 +74,7 @@ static int isd200_Initialization(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id isd200_usb_ids[] = { # include "unusual_isd200.h" @@ -83,7 +83,6 @@ static struct usb_device_id isd200_usb_ids[] = { MODULE_DEVICE_TABLE(usb, isd200_usb_ids); #undef UNUSUAL_DEV -#undef USUAL_DEV /* * The flags table @@ -105,8 +104,6 @@ static struct us_unusual_dev isd200_unusual_dev_list[] = { }; #undef UNUSUAL_DEV -#undef USUAL_DEV - /* Timeout defines (in Seconds) */ diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index e3b9738..ddc7878 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -69,7 +69,7 @@ MODULE_LICENSE("GPL"); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id jumpshot_usb_ids[] = { # include "unusual_jumpshot.h" diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index a8708ea..f085ffb 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -57,7 +57,7 @@ static int rio_karma_init(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id karma_usb_ids[] = { # include "unusual_karma.h" diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c deleted file mode 100644 index fe3ffe1..0000000 --- a/drivers/usb/storage/libusual.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * libusual - * - * The libusual contains the table of devices common for ub and usb-storage. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb_usual.h> -#include <linux/vmalloc.h> -#include <linux/kthread.h> -#include <linux/mutex.h> - -/* - */ -#define USU_MOD_FL_THREAD 1 /* Thread is running */ -#define USU_MOD_FL_PRESENT 2 /* The module is loaded */ - -struct mod_status { - unsigned long fls; -}; - -static struct mod_status stat[3]; -static DEFINE_SPINLOCK(usu_lock); - -/* - */ -#define USB_US_DEFAULT_BIAS USB_US_TYPE_STOR -static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS); - -#define BIAS_NAME_SIZE (sizeof("usb-storage")) -static const char *bias_names[3] = { "none", "usb-storage", "ub" }; - -static DEFINE_MUTEX(usu_probe_mutex); -static DECLARE_COMPLETION(usu_end_notify); -static atomic_t total_threads = ATOMIC_INIT(0); - -static int usu_probe_thread(void *arg); - -/* - * @type: the module type as an integer - */ -void usb_usual_set_present(int type) -{ - struct mod_status *st; - unsigned long flags; - - if (type <= 0 || type >= 3) - return; - st = &stat[type]; - spin_lock_irqsave(&usu_lock, flags); - st->fls |= USU_MOD_FL_PRESENT; - spin_unlock_irqrestore(&usu_lock, flags); -} -EXPORT_SYMBOL_GPL(usb_usual_set_present); - -void usb_usual_clear_present(int type) -{ - struct mod_status *st; - unsigned long flags; - - if (type <= 0 || type >= 3) - return; - st = &stat[type]; - spin_lock_irqsave(&usu_lock, flags); - st->fls &= ~USU_MOD_FL_PRESENT; - spin_unlock_irqrestore(&usu_lock, flags); -} -EXPORT_SYMBOL_GPL(usb_usual_clear_present); - -/* - * Match the calling driver type against the table. - * Returns: 0 if the device matches. - */ -int usb_usual_check_type(const struct usb_device_id *id, int caller_type) -{ - int id_type = USB_US_TYPE(id->driver_info); - - if (caller_type <= 0 || caller_type >= 3) - return -EINVAL; - - /* Drivers grab fixed assignment devices */ - if (id_type == caller_type) - return 0; - /* Drivers grab devices biased to them */ - if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias)) - return 0; - return -ENODEV; -} -EXPORT_SYMBOL_GPL(usb_usual_check_type); - -/* - */ -static int usu_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int rc; - unsigned long type; - struct task_struct* task; - unsigned long flags; - - type = USB_US_TYPE(id->driver_info); - if (type == 0) - type = atomic_read(&usu_bias); - - spin_lock_irqsave(&usu_lock, flags); - if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) { - spin_unlock_irqrestore(&usu_lock, flags); - return -ENXIO; - } - stat[type].fls |= USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - - task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - printk(KERN_WARNING "libusual: " - "Unable to start the thread for %s: %d\n", - bias_names[type], rc); - spin_lock_irqsave(&usu_lock, flags); - stat[type].fls &= ~USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - return rc; /* Not being -ENXIO causes a message printed */ - } - atomic_inc(&total_threads); - - return -ENXIO; -} - -static void usu_disconnect(struct usb_interface *intf) -{ - ; /* We should not be here. */ -} - -static struct usb_driver usu_driver = { - .name = "libusual", - .probe = usu_probe, - .disconnect = usu_disconnect, - .id_table = usb_storage_usb_ids, -}; - -/* - * A whole new thread for a purpose of request_module seems quite stupid. - * The request_module forks once inside again. However, if we attempt - * to load a storage module from our own modprobe thread, that module - * references our symbols, which cannot be resolved until our module is - * initialized. I wish there was a way to wait for the end of initialization. - * The module notifier reports MODULE_STATE_COMING only. - * So, we wait until module->init ends as the next best thing. - */ -static int usu_probe_thread(void *arg) -{ - int type = (unsigned long) arg; - struct mod_status *st = &stat[type]; - int rc; - unsigned long flags; - - mutex_lock(&usu_probe_mutex); - rc = request_module(bias_names[type]); - spin_lock_irqsave(&usu_lock, flags); - if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) { - /* - * This should not happen, but let us keep tabs on it. - */ - printk(KERN_NOTICE "libusual: " - "modprobe for %s succeeded, but module is not present\n", - bias_names[type]); - } - st->fls &= ~USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - mutex_unlock(&usu_probe_mutex); - - complete_and_exit(&usu_end_notify, 0); -} - -/* - */ -static int __init usb_usual_init(void) -{ - int rc; - - mutex_lock(&usu_probe_mutex); - rc = usb_register(&usu_driver); - mutex_unlock(&usu_probe_mutex); - return rc; -} - -static void __exit usb_usual_exit(void) -{ - /* - * We do not check for any drivers present, because - * they keep us pinned with symbol references. - */ - - usb_deregister(&usu_driver); - - while (atomic_read(&total_threads) > 0) { - wait_for_completion(&usu_end_notify); - atomic_dec(&total_threads); - } -} - -/* - * Validate and accept the bias parameter. - */ -static int usu_set_bias(const char *bias_s, struct kernel_param *kp) -{ - int i; - int len; - int bias_n = 0; - - len = strlen(bias_s); - if (len == 0) - return -EDOM; - if (bias_s[len-1] == '\n') - --len; - - for (i = 1; i < 3; i++) { - if (strncmp(bias_s, bias_names[i], len) == 0) { - bias_n = i; - break; - } - } - if (bias_n == 0) - return -EINVAL; - - atomic_set(&usu_bias, bias_n); - return 0; -} - -static int usu_get_bias(char *buffer, struct kernel_param *kp) -{ - return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)])); -} - -module_init(usb_usual_init); -module_exit(usb_usual_exit); - -module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR); -__MODULE_PARM_TYPE(bias, "string"); -MODULE_PARM_DESC(bias, "Bias to usb-storage or ub"); - -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 886567a..cb79de6 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -67,7 +67,7 @@ struct usb_onetouch { vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id onetouch_usb_ids[] = { # include "unusual_onetouch.h" diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 63cf282..d36446d 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -172,7 +172,7 @@ static int init_realtek_cr(struct us_data *us); initFunction, flags) \ {\ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24)\ + .driver_info = (flags) \ } static const struct usb_device_id realtek_cr_ids[] = { diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 3252a62..7bd54e0 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -69,7 +69,7 @@ static int usb_stor_sddr09_init(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id sddr09_usb_ids[] = { # include "unusual_sddr09.h" diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index c144078..d278c5a 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -46,7 +46,7 @@ MODULE_LICENSE("GPL"); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id sddr55_usb_ids[] = { # include "unusual_sddr55.h" diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index fa1ceeb..daf2fc5 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -168,7 +168,7 @@ static int init_usbat_flash(struct us_data *us); vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } + .driver_info = (flags) } static struct usb_device_id usbat_usb_ids[] = { # include "unusual_usbat.h" diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 37539c8..17e3695 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -130,14 +130,13 @@ int sierra_ms_init(struct us_data *us) struct swoc_info *swocInfo; struct usb_device *udev; struct Scsi_Host *sh; - struct scsi_device *sd; retries = 3; result = 0; udev = us->pusb_dev; sh = us_to_host(us); - sd = scsi_get_host_dev(sh); + scsi_get_host_dev(sh); US_DEBUGP("SWIMS: sierra_ms_init called\n"); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c70109e..c0543c8 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1331,7 +1331,7 @@ int usb_stor_port_reset(struct us_data *us) int result; /*for these devices we must use the class specific method */ - if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS) + if (us->pusb_dev->quirks & USB_QUIRK_RESET) return -EPERM; result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 638cd64..98b98ee 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -41,6 +41,7 @@ struct sense_iu_old { struct uas_dev_info { struct usb_interface *intf; struct usb_device *udev; + struct usb_anchor cmd_urbs; struct usb_anchor sense_urbs; struct usb_anchor data_urbs; int qdepth, resetting; @@ -49,6 +50,7 @@ struct uas_dev_info { unsigned use_streams:1; unsigned uas_sense_old:1; struct scsi_cmnd *cmnd; + spinlock_t lock; }; enum { @@ -63,13 +65,13 @@ enum { DATA_IN_URB_INFLIGHT = (1 << 9), DATA_OUT_URB_INFLIGHT = (1 << 10), COMMAND_COMPLETED = (1 << 11), + COMMAND_ABORTED = (1 << 12), }; /* Overrides scsi_pointer */ struct uas_cmd_info { unsigned int state; unsigned int stream; - unsigned int aborted; struct urb *cmd_urb; struct urb *data_in_urb; struct urb *data_out_urb; @@ -90,6 +92,7 @@ static void uas_do_work(struct work_struct *work) struct uas_cmd_info *cmdinfo; struct uas_cmd_info *temp; struct list_head list; + unsigned long flags; int err; spin_lock_irq(&uas_work_lock); @@ -100,7 +103,10 @@ static void uas_do_work(struct work_struct *work) struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp); - err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); + struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; + spin_lock_irqsave(&devinfo->lock, flags); + err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); + spin_unlock_irqrestore(&devinfo->lock, flags); if (err) { list_del(&cmdinfo->list); spin_lock_irq(&uas_work_lock); @@ -162,7 +168,7 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller) struct uas_cmd_info *ci = (void *)&cmnd->SCp; scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:" - "%s%s%s%s%s%s%s%s%s%s%s\n", + "%s%s%s%s%s%s%s%s%s%s%s%s\n", caller, cmnd, cmnd->request->tag, (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", @@ -174,13 +180,16 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller) (ci->state & COMMAND_INFLIGHT) ? " CMD" : "", (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "", (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "", - (ci->state & COMMAND_COMPLETED) ? " done" : ""); + (ci->state & COMMAND_COMPLETED) ? " done" : "", + (ci->state & COMMAND_ABORTED) ? " abort" : ""); } static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) { struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; + WARN_ON(!spin_is_locked(&devinfo->lock)); if (cmdinfo->state & (COMMAND_INFLIGHT | DATA_IN_URB_INFLIGHT | DATA_OUT_URB_INFLIGHT)) @@ -189,6 +198,10 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) cmdinfo->state |= COMMAND_COMPLETED; usb_free_urb(cmdinfo->data_in_urb); usb_free_urb(cmdinfo->data_out_urb); + if (cmdinfo->state & COMMAND_ABORTED) { + scmd_printk(KERN_INFO, cmnd, "abort completed\n"); + cmnd->result = DID_ABORT << 16; + } cmnd->scsi_done(cmnd); return 0; } @@ -216,6 +229,7 @@ static void uas_stat_cmplt(struct urb *urb) struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; struct scsi_cmnd *cmnd; struct uas_cmd_info *cmdinfo; + unsigned long flags; u16 tag; if (urb->status) { @@ -229,20 +243,24 @@ static void uas_stat_cmplt(struct urb *urb) return; } + spin_lock_irqsave(&devinfo->lock, flags); tag = be16_to_cpup(&iu->tag) - 1; if (tag == 0) cmnd = devinfo->cmnd; else cmnd = scsi_host_find_tag(shost, tag - 1); + if (!cmnd) { - if (iu->iu_id != IU_ID_RESPONSE) { - usb_free_urb(urb); - return; + if (iu->iu_id == IU_ID_RESPONSE) { + /* store results for uas_eh_task_mgmt() */ + memcpy(&devinfo->response, iu, sizeof(devinfo->response)); } - } else { - cmdinfo = (void *)&cmnd->SCp; + usb_free_urb(urb); + spin_unlock_irqrestore(&devinfo->lock, flags); + return; } + cmdinfo = (void *)&cmnd->SCp; switch (iu->iu_id) { case IU_ID_STATUS: if (devinfo->cmnd == cmnd) @@ -256,10 +274,16 @@ static void uas_stat_cmplt(struct urb *urb) uas_sense(urb, cmnd); if (cmnd->result != 0) { /* cancel data transfers on error */ - if (cmdinfo->state & DATA_IN_URB_INFLIGHT) + if (cmdinfo->state & DATA_IN_URB_INFLIGHT) { + spin_unlock_irqrestore(&devinfo->lock, flags); usb_unlink_urb(cmdinfo->data_in_urb); - if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) + spin_lock_irqsave(&devinfo->lock, flags); + } + if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) { + spin_unlock_irqrestore(&devinfo->lock, flags); usb_unlink_urb(cmdinfo->data_out_urb); + spin_lock_irqsave(&devinfo->lock, flags); + } } cmdinfo->state &= ~COMMAND_INFLIGHT; uas_try_complete(cmnd, __func__); @@ -270,23 +294,23 @@ static void uas_stat_cmplt(struct urb *urb) case IU_ID_WRITE_READY: uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); break; - case IU_ID_RESPONSE: - /* store results for uas_eh_task_mgmt() */ - memcpy(&devinfo->response, iu, sizeof(devinfo->response)); - break; default: scmd_printk(KERN_ERR, cmnd, "Bogus IU (%d) received on status pipe\n", iu->iu_id); } usb_free_urb(urb); + spin_unlock_irqrestore(&devinfo->lock, flags); } static void uas_data_cmplt(struct urb *urb) { struct scsi_cmnd *cmnd = urb->context; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; struct scsi_data_buffer *sdb = NULL; + unsigned long flags; + spin_lock_irqsave(&devinfo->lock, flags); if (cmdinfo->data_in_urb == urb) { sdb = scsi_in(cmnd); cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; @@ -301,10 +325,8 @@ static void uas_data_cmplt(struct urb *urb) } else { sdb->resid = sdb->length - urb->actual_length; } - if (cmdinfo->aborted) { - return; - } uas_try_complete(cmnd, __func__); + spin_unlock_irqrestore(&devinfo->lock, flags); } static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, @@ -431,6 +453,7 @@ static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp, err = usb_submit_urb(urb, gfp); if (err) goto err; + usb_anchor_urb(urb, &devinfo->cmd_urbs); return 0; @@ -470,6 +493,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; int err; + WARN_ON(!spin_is_locked(&devinfo->lock)); if (cmdinfo->state & SUBMIT_STATUS_URB) { err = uas_submit_sense_urb(cmnd->device->host, gfp, cmdinfo->stream); @@ -521,18 +545,22 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, if (cmdinfo->state & ALLOC_CMD_URB) { cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd, - cmdinfo->stream); + cmdinfo->stream); if (!cmdinfo->cmd_urb) return SCSI_MLQUEUE_DEVICE_BUSY; cmdinfo->state &= ~ALLOC_CMD_URB; } if (cmdinfo->state & SUBMIT_CMD_URB) { + usb_get_urb(cmdinfo->cmd_urb); if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) { scmd_printk(KERN_INFO, cmnd, "cmd urb submission failure\n"); return SCSI_MLQUEUE_DEVICE_BUSY; } + usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs); + usb_put_urb(cmdinfo->cmd_urb); + cmdinfo->cmd_urb = NULL; cmdinfo->state &= ~SUBMIT_CMD_URB; cmdinfo->state |= COMMAND_INFLIGHT; } @@ -546,12 +574,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, struct scsi_device *sdev = cmnd->device; struct uas_dev_info *devinfo = sdev->hostdata; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + unsigned long flags; int err; BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); - if (devinfo->cmnd) + spin_lock_irqsave(&devinfo->lock, flags); + if (devinfo->cmnd) { + spin_unlock_irqrestore(&devinfo->lock, flags); return SCSI_MLQUEUE_DEVICE_BUSY; + } if (blk_rq_tagged(cmnd->request)) { cmdinfo->stream = cmnd->request->tag + 2; @@ -564,7 +596,6 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; - cmdinfo->aborted = 0; switch (cmnd->sc_data_direction) { case DMA_FROM_DEVICE: @@ -587,6 +618,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, if (err) { /* If we did nothing, give up now */ if (cmdinfo->state & SUBMIT_STATUS_URB) { + spin_unlock_irqrestore(&devinfo->lock, flags); return SCSI_MLQUEUE_DEVICE_BUSY; } spin_lock(&uas_work_lock); @@ -595,6 +627,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, schedule_work(&uas_work); } + spin_unlock_irqrestore(&devinfo->lock, flags); return 0; } @@ -605,22 +638,28 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, { struct Scsi_Host *shost = cmnd->device->host; struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; - u16 tag = 9999; /* FIXME */ + u16 tag = devinfo->qdepth - 1; + unsigned long flags; + spin_lock_irqsave(&devinfo->lock, flags); memset(&devinfo->response, 0, sizeof(devinfo->response)); - if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) { + if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) { shost_printk(KERN_INFO, shost, "%s: %s: submit sense urb failed\n", __func__, fname); + spin_unlock_irqrestore(&devinfo->lock, flags); return FAILED; } - if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) { + if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) { shost_printk(KERN_INFO, shost, "%s: %s: submit task mgmt urb failed\n", __func__, fname); + spin_unlock_irqrestore(&devinfo->lock, flags); return FAILED; } - if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) { + spin_unlock_irqrestore(&devinfo->lock, flags); + + if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) { shost_printk(KERN_INFO, shost, "%s: %s timed out\n", __func__, fname); return FAILED; @@ -643,15 +682,15 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) { struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; + unsigned long flags; int ret; uas_log_cmd_state(cmnd, __func__); - cmdinfo->aborted = 1; + spin_lock_irqsave(&devinfo->lock, flags); + cmdinfo->state |= COMMAND_ABORTED; + spin_unlock_irqrestore(&devinfo->lock, flags); ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK); - if (cmdinfo->state & DATA_IN_URB_INFLIGHT) - usb_kill_urb(cmdinfo->data_in_urb); - if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) - usb_kill_urb(cmdinfo->data_out_urb); return ret; } @@ -670,6 +709,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) int err; devinfo->resetting = 1; + usb_kill_anchored_urbs(&devinfo->cmd_urbs); usb_kill_anchored_urbs(&devinfo->sense_urbs); usb_kill_anchored_urbs(&devinfo->data_urbs); err = usb_reset_device(udev); @@ -694,7 +734,7 @@ static int uas_slave_configure(struct scsi_device *sdev) { struct uas_dev_info *devinfo = sdev->hostdata; scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, devinfo->qdepth - 2); + scsi_activate_tcq(sdev, devinfo->qdepth - 3); return 0; } @@ -868,11 +908,13 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) devinfo->intf = intf; devinfo->udev = udev; devinfo->resetting = 0; + init_usb_anchor(&devinfo->cmd_urbs); init_usb_anchor(&devinfo->sense_urbs); init_usb_anchor(&devinfo->data_urbs); + spin_lock_init(&devinfo->lock); uas_configure_endpoints(devinfo); - result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); + result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3); if (result) goto free; @@ -913,6 +955,7 @@ static void uas_disconnect(struct usb_interface *intf) struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; scsi_remove_host(shost); + usb_kill_anchored_urbs(&devinfo->cmd_urbs); usb_kill_anchored_urbs(&devinfo->sense_urbs); usb_kill_anchored_urbs(&devinfo->data_urbs); uas_free_streams(devinfo); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 62a31be..779cd95 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2038,25 +2038,25 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), /* Control/Bulk transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_CB, USB_US_TYPE_STOR), +USUAL_DEV(USB_SC_RBC, USB_PR_CB), +USUAL_DEV(USB_SC_8020, USB_PR_CB), +USUAL_DEV(USB_SC_QIC, USB_PR_CB), +USUAL_DEV(USB_SC_UFI, USB_PR_CB), +USUAL_DEV(USB_SC_8070, USB_PR_CB), +USUAL_DEV(USB_SC_SCSI, USB_PR_CB), /* Control/Bulk/Interrupt transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_CBI, USB_US_TYPE_STOR), +USUAL_DEV(USB_SC_RBC, USB_PR_CBI), +USUAL_DEV(USB_SC_8020, USB_PR_CBI), +USUAL_DEV(USB_SC_QIC, USB_PR_CBI), +USUAL_DEV(USB_SC_UFI, USB_PR_CBI), +USUAL_DEV(USB_SC_8070, USB_PR_CBI), +USUAL_DEV(USB_SC_SCSI, USB_PR_CBI), /* Bulk-only transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0), +USUAL_DEV(USB_SC_RBC, USB_PR_BULK), +USUAL_DEV(USB_SC_8020, USB_PR_BULK), +USUAL_DEV(USB_SC_QIC, USB_PR_BULK), +USUAL_DEV(USB_SC_UFI, USB_PR_BULK), +USUAL_DEV(USB_SC_8070, USB_PR_BULK), +USUAL_DEV(USB_SC_SCSI, USB_PR_BULK), diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index d012fe4..12aa726 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -114,7 +114,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); #define COMPLIANT_DEV UNUSUAL_DEV -#define USUAL_DEV(use_protocol, use_transport, use_type) \ +#define USUAL_DEV(use_protocol, use_transport) \ { \ .useProtocol = use_protocol, \ .useTransport = use_transport, \ @@ -126,7 +126,7 @@ static struct us_unusual_dev us_unusual_dev_list[] = { }; static struct us_unusual_dev for_dynamic_ids = - USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0); + USUAL_DEV(USB_SC_SCSI, USB_PR_BULK); #undef UNUSUAL_DEV #undef COMPLIANT_DEV @@ -564,7 +564,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id, us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ? idesc->bInterfaceProtocol : unusual_dev->useTransport; - us->fflags = USB_US_ORIG_FLAGS(id->driver_info); + us->fflags = id->driver_info; adjust_quirks(us); if (us->fflags & US_FL_IGNORE_DEVICE) { @@ -1041,13 +1041,10 @@ static int storage_probe(struct usb_interface *intf, int size; /* - * If libusual is configured, let it decide whether a standard - * device should be handled by usb-storage or by ub. * If the device isn't standard (is handled by a subdriver * module) then don't accept it. */ - if (usb_usual_check_type(id, USB_US_TYPE_STOR) || - usb_usual_ignore_device(intf)) + if (usb_usual_ignore_device(intf)) return -ENXIO; /* @@ -1105,10 +1102,8 @@ static int __init usb_stor_init(void) /* register the driver, return usb_register return code if error */ retval = usb_register(&usb_storage_driver); - if (retval == 0) { + if (retval == 0) pr_info("USB Mass Storage support registered.\n"); - usb_usual_set_present(USB_US_TYPE_STOR); - } return retval; } @@ -1122,8 +1117,6 @@ static void __exit usb_stor_exit(void) */ US_DEBUGP("-- calling usb_deregister()\n"); usb_deregister(&usb_storage_driver) ; - - usb_usual_clear_present(USB_US_TYPE_STOR); } module_init(usb_stor_init); diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index b969279..b78a526 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c @@ -34,31 +34,23 @@ vendorName, productName, useProtocol, useTransport, \ initFunction, flags) \ { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -#define USUAL_DEV(useProto, useTrans, useType) \ -{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \ - .driver_info = ((useType)<<24) } +#define COMPLIANT_DEV UNUSUAL_DEV + +#define USUAL_DEV(useProto, useTrans) \ +{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) } struct usb_device_id usb_storage_usb_ids[] = { # include "unusual_devs.h" { } /* Terminating entry */ }; -EXPORT_SYMBOL_GPL(usb_storage_usb_ids); - MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids); #undef UNUSUAL_DEV #undef COMPLIANT_DEV #undef USUAL_DEV - /* * The table of devices to ignore */ @@ -95,7 +87,6 @@ static struct ignore_entry ignore_ids[] = { #undef UNUSUAL_DEV - /* Return an error if a device is in the ignore_ids list */ int usb_usual_ignore_device(struct usb_interface *intf) { @@ -115,4 +106,3 @@ int usb_usual_ignore_device(struct usb_interface *intf) } return 0; } -EXPORT_SYMBOL_GPL(usb_usual_ignore_device); diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index f29fdd7..8bf1976 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -2,8 +2,7 @@ # Wireless USB Core configuration # config USB_WUSB - tristate "Enable Wireless USB extensions (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Enable Wireless USB extensions" depends on USB depends on PCI depends on UWB diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index fa810a8..dd88441 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -202,7 +202,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, { int result, bytes, secd_size; struct device *dev = &usb_dev->dev; - struct usb_security_descriptor *secd; + struct usb_security_descriptor *secd, *new_secd; const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; const void *itr, *top; char buf[64]; @@ -221,11 +221,12 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, goto out; } secd_size = le16_to_cpu(secd->wTotalLength); - secd = krealloc(secd, secd_size, GFP_KERNEL); - if (secd == NULL) { + new_secd = krealloc(secd, secd_size, GFP_KERNEL); + if (new_secd == NULL) { dev_err(dev, "Can't allocate space for security descriptors\n"); goto out; } + secd = new_secd; result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, 0, secd, secd_size); if (result < secd_size) { diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c index 9e4a924..a09b65e 100644 --- a/drivers/usb/wusbcore/wa-hc.c +++ b/drivers/usb/wusbcore/wa-hc.c @@ -46,8 +46,10 @@ int wa_create(struct wahc *wa, struct usb_interface *iface) wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd); wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL); - if (wa->xfer_result == NULL) + if (wa->xfer_result == NULL) { + result = -ENOMEM; goto error_xfer_result_alloc; + } result = wa_nep_create(wa, iface); if (result < 0) { dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n", diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index d80bea5..a4a3cab 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_XEN_PVHVM) += platform-pci.o obj-$(CONFIG_XEN_TMEM) += tmem.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pcpu.o -obj-$(CONFIG_XEN_DOM0) += pci.o acpi.o +obj-$(CONFIG_XEN_DOM0) += pci.o dbgp.o acpi.o obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o diff --git a/drivers/xen/dbgp.c b/drivers/xen/dbgp.c new file mode 100644 index 0000000..42569c7 --- /dev/null +++ b/drivers/xen/dbgp.c @@ -0,0 +1,48 @@ +#include <linux/pci.h> +#include <linux/usb.h> +#include <linux/usb/ehci_def.h> +#include <linux/usb/hcd.h> +#include <asm/xen/hypercall.h> +#include <xen/interface/physdev.h> +#include <xen/xen.h> + +static int xen_dbgp_op(struct usb_hcd *hcd, int op) +{ + const struct device *ctrlr = hcd_to_bus(hcd)->controller; + struct physdev_dbgp_op dbgp; + + if (!xen_initial_domain()) + return 0; + + dbgp.op = op; + +#ifdef CONFIG_PCI + if (ctrlr->bus == &pci_bus_type) { + const struct pci_dev *pdev = to_pci_dev(ctrlr); + + dbgp.u.pci.seg = pci_domain_nr(pdev->bus); + dbgp.u.pci.bus = pdev->bus->number; + dbgp.u.pci.devfn = pdev->devfn; + dbgp.bus = PHYSDEVOP_DBGP_BUS_PCI; + } else +#endif + dbgp.bus = PHYSDEVOP_DBGP_BUS_UNKNOWN; + + return HYPERVISOR_physdev_op(PHYSDEVOP_dbgp_op, &dbgp); +} + +int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return xen_dbgp_op(hcd, PHYSDEVOP_DBGP_RESET_PREPARE); +} + +int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_op(hcd, PHYSDEVOP_DBGP_RESET_DONE); +} + +#ifndef CONFIG_EARLY_PRINTK_DBGP +#include <linux/export.h> +EXPORT_SYMBOL_GPL(xen_dbgp_reset_prep); +EXPORT_SYMBOL_GPL(xen_dbgp_external_startup); +#endif diff --git a/include/linux/bcd.h b/include/linux/bcd.h index 22ea563..18fff11 100644 --- a/include/linux/bcd.h +++ b/include/linux/bcd.h @@ -3,7 +3,20 @@ #include <linux/compiler.h> -unsigned bcd2bin(unsigned char val) __attribute_const__; -unsigned char bin2bcd(unsigned val) __attribute_const__; +#define bcd2bin(x) \ + (__builtin_constant_p((u8 )(x)) ? \ + const_bcd2bin(x) : \ + _bcd2bin(x)) + +#define bin2bcd(x) \ + (__builtin_constant_p((u8 )(x)) ? \ + const_bin2bcd(x) : \ + _bin2bcd(x)) + +#define const_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10) +#define const_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10) + +unsigned _bcd2bin(unsigned char val) __attribute_const__; +unsigned char _bin2bcd(unsigned val) __attribute_const__; #endif /* _BCD_H */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 15be561..a82296a 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -19,9 +19,11 @@ #define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI PHY CLK to become stable - 10ms*/ +#define FSL_USB_PHY_CLK_TIMEOUT 10000 /* uSec */ #define FSL_USB_VER_OLD 0 #define FSL_USB_VER_1_6 1 #define FSL_USB_VER_2_2 2 +#define FSL_USB_VER_2_4 3 #include <linux/types.h> diff --git a/include/linux/usb.h b/include/linux/usb.h index 30d1ae3..07915a3 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -384,6 +384,13 @@ enum usb_device_removable { USB_DEVICE_FIXED, }; +enum usb_port_connect_type { + USB_PORT_CONNECT_TYPE_UNKNOWN = 0, + USB_PORT_CONNECT_TYPE_HOT_PLUG, + USB_PORT_CONNECT_TYPE_HARD_WIRED, + USB_PORT_NOT_USED, +}; + /* * USB 3.0 Link Power Management (LPM) parameters. * @@ -469,7 +476,6 @@ struct usb3_lpm_parameters { * access from userspace * @usbfs_dentry: usbfs dentry entry for the device * @maxchild: number of ports if hub - * @children: child devices - USB devices that are attached to this hub * @quirks: quirks of the whole device * @urbnum: number of URBs submitted for the whole device * @active_duration: total time device is not suspended @@ -543,7 +549,6 @@ struct usb_device { struct list_head filelist; int maxchild; - struct usb_device **children; u32 quirks; atomic_t urbnum; @@ -572,6 +577,19 @@ static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf) extern struct usb_device *usb_get_dev(struct usb_device *dev); extern void usb_put_dev(struct usb_device *dev); +extern struct usb_device *usb_hub_find_child(struct usb_device *hdev, + int port1); + +/** + * usb_hub_for_each_child - iterate over all child devices on the hub + * @hdev: USB device belonging to the usb hub + * @port1: portnum associated with child device + * @child: child device pointer + */ +#define usb_hub_for_each_child(hdev, port1, child) \ + for (port1 = 1, child = usb_hub_find_child(hdev, port1); \ + port1 <= hdev->maxchild; \ + child = usb_hub_find_child(hdev, ++port1)) /* USB device locking */ #define usb_lock_device(udev) device_lock(&(udev)->dev) @@ -584,6 +602,16 @@ extern int usb_lock_device_for_reset(struct usb_device *udev, extern int usb_reset_device(struct usb_device *dev); extern void usb_queue_reset_device(struct usb_interface *dev); +#ifdef CONFIG_ACPI +extern int usb_acpi_set_power_state(struct usb_device *hdev, int index, + bool enable); +extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index); +#else +static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index, + bool enable) { return 0; } +static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index) + { return true; } +#endif /* USB autosuspend and autoresume */ #ifdef CONFIG_USB_SUSPEND diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index b6c2863..7692dc6 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -236,8 +236,8 @@ struct usb_hub_descriptor { struct { __u8 bHubHdrDecLat; - __u16 wHubDelay; - __u16 DeviceRemovable; + __le16 wHubDelay; + __le16 DeviceRemovable; } __attribute__ ((packed)) ss; } u; } __attribute__ ((packed)); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9d8c3b6..f8dda06 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -34,6 +34,8 @@ * the composite model the host can use both functions at the same time. */ +#include <linux/bcd.h> +#include <linux/version.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -46,6 +48,9 @@ */ #define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ +/* big enough to hold our biggest descriptor */ +#define USB_COMP_EP0_BUFSIZ 1024 + struct usb_configuration; /** @@ -245,24 +250,31 @@ int usb_add_config(struct usb_composite_dev *, void usb_remove_config(struct usb_composite_dev *, struct usb_configuration *); +/* predefined index for usb_composite_driver */ +enum { + USB_GADGET_MANUFACTURER_IDX = 0, + USB_GADGET_PRODUCT_IDX, + USB_GADGET_SERIAL_IDX, + USB_GADGET_FIRST_AVAIL_IDX, +}; + /** * struct usb_composite_driver - groups configurations into a gadget * @name: For diagnostics, identifies the driver. - * @iProduct: Used as iProduct override if @dev->iProduct is not set. - * If NULL value of @name is taken. - * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is - * not set. If NULL a default "<system> <release> with <udc>" value - * will be used. - * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is - * not set. * @dev: Template descriptor for the device, including default device * identifiers. - * @strings: tables of strings, keyed by identifiers assigned during bind() - * and language IDs provided in control requests + * @strings: tables of strings, keyed by identifiers assigned during @bind + * and language IDs provided in control requests. Note: The first entries + * are predefined. The first entry that may be used is + * USB_GADGET_FIRST_AVAIL_IDX * @max_speed: Highest speed the driver supports. * @needs_serial: set to 1 if the gadget needs userspace to provide * a serial number. If one is not provided, warning will be printed. - * @unbind: Reverses bind; called as a side effect of unregistering + * @bind: (REQUIRED) Used to allocate resources that are shared across the + * whole device, such as string IDs, and add its configurations using + * @usb_add_config(). This may fail by returning a negative errno + * value; it should return zero on successful initialization. + * @unbind: Reverses @bind; called as a side effect of unregistering * this driver. * @disconnect: optional driver disconnect method * @suspend: Notifies when the host stops sending USB traffic, @@ -271,9 +283,9 @@ void usb_remove_config(struct usb_composite_dev *, * before function notifications * * Devices default to reporting self powered operation. Devices which rely - * on bus powered operation should report this in their @bind() method. + * on bus powered operation should report this in their @bind method. * - * Before returning from bind, various fields in the template descriptor + * Before returning from @bind, various fields in the template descriptor * may be overridden. These include the idVendor/idProduct/bcdDevice values * normally to bind the appropriate host side driver, and the three strings * (iManufacturer, iProduct, iSerialNumber) normally used to provide user @@ -283,14 +295,12 @@ void usb_remove_config(struct usb_composite_dev *, */ struct usb_composite_driver { const char *name; - const char *iProduct; - const char *iManufacturer; - const char *iSerialNumber; const struct usb_device_descriptor *dev; struct usb_gadget_strings **strings; enum usb_device_speed max_speed; unsigned needs_serial:1; + int (*bind)(struct usb_composite_dev *cdev); int (*unbind)(struct usb_composite_dev *); void (*disconnect)(struct usb_composite_dev *); @@ -298,10 +308,10 @@ struct usb_composite_driver { /* global suspend hooks */ void (*suspend)(struct usb_composite_dev *); void (*resume)(struct usb_composite_dev *); + struct usb_gadget_driver gadget_driver; }; -extern int usb_composite_probe(struct usb_composite_driver *driver, - int (*bind)(struct usb_composite_dev *cdev)); +extern int usb_composite_probe(struct usb_composite_driver *driver); extern void usb_composite_unregister(struct usb_composite_driver *driver); extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); @@ -310,7 +320,6 @@ extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); * struct usb_composite_device - represents one composite usb gadget * @gadget: read-only, abstracts the gadget's usb peripheral controller * @req: used for control responses; buffer is pre-allocated - * @bufsiz: size of buffer pre-allocated in @req * @config: the currently active configuration * * One of these devices is allocated and initialized before the @@ -341,7 +350,6 @@ extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); struct usb_composite_dev { struct usb_gadget *gadget; struct usb_request *req; - unsigned bufsiz; struct usb_configuration *config; @@ -352,9 +360,7 @@ struct usb_composite_dev { struct list_head configs; struct usb_composite_driver *driver; u8 next_string_id; - u8 manufacturer_override; - u8 product_override; - u8 serial_override; + char *def_manufacturer; /* the gadget driver won't enable the data pullup * while the deactivation count is nonzero. @@ -375,6 +381,53 @@ extern int usb_string_ids_tab(struct usb_composite_dev *c, struct usb_string *str); extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); +/* + * Some systems will need runtime overrides for the product identifiers + * published in the device descriptor, either numbers or strings or both. + * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). + */ +struct usb_composite_overwrite { + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + char *serial_number; + char *manufacturer; + char *product; +}; +#define USB_GADGET_COMPOSITE_OPTIONS() \ + static struct usb_composite_overwrite coverwrite; \ + \ + module_param_named(idVendor, coverwrite.idVendor, ushort, S_IRUGO); \ + MODULE_PARM_DESC(idVendor, "USB Vendor ID"); \ + \ + module_param_named(idProduct, coverwrite.idProduct, ushort, S_IRUGO); \ + MODULE_PARM_DESC(idProduct, "USB Product ID"); \ + \ + module_param_named(bcdDevice, coverwrite.bcdDevice, ushort, S_IRUGO); \ + MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); \ + \ + module_param_named(iSerialNumber, coverwrite.serial_number, charp, \ + S_IRUGO); \ + MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); \ + \ + module_param_named(iManufacturer, coverwrite.manufacturer, charp, \ + S_IRUGO); \ + MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); \ + \ + module_param_named(iProduct, coverwrite.product, charp, S_IRUGO); \ + MODULE_PARM_DESC(iProduct, "USB Product string") + +void usb_composite_overwrite_options(struct usb_composite_dev *cdev, + struct usb_composite_overwrite *covr); + +static inline u16 get_default_bcdDevice(void) +{ + u16 bcdDevice; + + bcdDevice = bin2bcd((LINUX_VERSION_CODE >> 16 & 0xff)) << 8; + bcdDevice |= bin2bcd((LINUX_VERSION_CODE >> 8 & 0xff)); + return bcdDevice; +} /* messaging utils */ #define DBG(d, fmt, args...) \ diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index de4b9ed..daec99a 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -171,18 +171,18 @@ struct ehci_regs { #define USBMODE_CM_HC (3<<0) /* host controller mode */ #define USBMODE_CM_IDLE (0<<0) /* idle state */ - u32 reserved4[7]; + u32 reserved4[6]; /* Moorestown has some non-standard registers, partially due to the fact that * its EHCI controller has both TT and LPM support. HOSTPCx are extensions to * PORTSCx */ /* HOSTPC: offset 0x84 */ - u32 hostpc[0]; /* HOSTPC extension */ + u32 hostpc[1]; /* HOSTPC extension */ #define HOSTPC_PHCD (1<<22) /* Phy clock disable */ #define HOSTPC_PSPD (3<<25) /* Port speed detection */ - u32 reserved5[17]; + u32 reserved5[16]; /* USBMODE_EX: offset 0xc8 */ u32 usbmode_ex; /* USB Device mode extension */ @@ -221,18 +221,35 @@ extern int __init early_dbgp_init(char *s); extern struct console early_dbgp_console; #endif /* CONFIG_EARLY_PRINTK_DBGP */ +struct usb_hcd; + +#ifdef CONFIG_XEN_DOM0 +extern int xen_dbgp_reset_prep(struct usb_hcd *); +extern int xen_dbgp_external_startup(struct usb_hcd *); +#else +static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return 1; /* Shouldn't this be 0? */ +} + +static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return -1; +} +#endif + #ifdef CONFIG_EARLY_PRINTK_DBGP /* Call backs from ehci host driver to ehci debug driver */ -extern int dbgp_external_startup(void); -extern int dbgp_reset_prep(void); +extern int dbgp_external_startup(struct usb_hcd *); +extern int dbgp_reset_prep(struct usb_hcd *hcd); #else -static inline int dbgp_reset_prep(void) +static inline int dbgp_reset_prep(struct usb_hcd *hcd) { - return 1; + return xen_dbgp_reset_prep(hcd); } -static inline int dbgp_external_startup(void) +static inline int dbgp_external_startup(struct usb_hcd *hcd) { - return -1; + return xen_dbgp_external_startup(hcd); } #endif diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h index 1894f42..c9d09f8 100644 --- a/include/linux/usb/ehci_pdriver.h +++ b/include/linux/usb/ehci_pdriver.h @@ -41,6 +41,14 @@ struct usb_ehci_pdata { unsigned big_endian_mmio:1; unsigned port_power_on:1; unsigned port_power_off:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); + /* Turn off all power and clocks */ + void (*power_off)(struct platform_device *pdev); + /* Turn on only VBUS suspend power and hotplug detection, + * turn off everything else */ + void (*power_suspend)(struct platform_device *pdev); }; #endif /* __USB_CORE_EHCI_PDRIVER_H */ diff --git a/include/linux/usb/ezusb.h b/include/linux/usb/ezusb.h new file mode 100644 index 0000000..fc618d8 --- /dev/null +++ b/include/linux/usb/ezusb.h @@ -0,0 +1,16 @@ +#ifndef __EZUSB_H +#define __EZUSB_H + + +extern int ezusb_writememory(struct usb_device *dev, int address, + unsigned char *data, int length, __u8 bRequest); + +extern int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit); +extern int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit); + +extern int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, + const char *firmware_path); +extern int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, + const char *firmware_path); + +#endif /* __EZUSB_H */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 9517466..5b6e508 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -474,7 +474,8 @@ struct usb_gadget_ops { /* Those two are deprecated */ int (*start)(struct usb_gadget_driver *, - int (*bind)(struct usb_gadget *)); + int (*bind)(struct usb_gadget *, + struct usb_gadget_driver *driver)); int (*stop)(struct usb_gadget_driver *); }; @@ -502,6 +503,8 @@ struct usb_gadget_ops { * @name: Identifies the controller hardware type. Used in diagnostics * and sometimes configuration. * @dev: Driver model state for this abstract device. + * @out_epnum: last used out ep number + * @in_epnum: last used in ep number * * Gadgets have a mostly-portable "gadget driver" implementing device * functions, handling all usb configurations and interfaces. Gadget @@ -536,6 +539,8 @@ struct usb_gadget { unsigned a_alt_hnp_support:1; const char *name; struct device dev; + unsigned out_epnum; + unsigned in_epnum; }; static inline void set_gadget_data(struct usb_gadget *gadget, void *data) @@ -558,14 +563,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) */ static inline int gadget_is_dualspeed(struct usb_gadget *g) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* runtime test would check "g->max_speed" ... that might be - * useful to work around hardware bugs, but is mostly pointless - */ - return 1; -#else - return 0; -#endif + return g->max_speed >= USB_SPEED_HIGH; } /** @@ -575,15 +573,7 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g) */ static inline int gadget_is_superspeed(struct usb_gadget *g) { -#ifdef CONFIG_USB_GADGET_SUPERSPEED - /* - * runtime test would check "g->max_speed" ... that might be - * useful to work around hardware bugs, but is mostly pointless - */ - return 1; -#else - return 0; -#endif + return g->max_speed >= USB_SPEED_SUPER; } /** @@ -781,6 +771,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) * when the host is disconnected. May be called in_interrupt; this * may not sleep. Some devices can't detect disconnect, so this might * not be called except as part of controller shutdown. + * @bind: the driver's bind callback * @unbind: Invoked when the driver is unbound from a gadget, * usually from rmmod (after a disconnect is reported). * Called in a context that permits sleeping. @@ -835,6 +826,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) struct usb_gadget_driver { char *function; enum usb_device_speed max_speed; + int (*bind)(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); void (*unbind)(struct usb_gadget *); int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); @@ -860,7 +853,6 @@ struct usb_gadget_driver { /** * usb_gadget_probe_driver - probe a gadget driver * @driver: the driver being registered - * @bind: the driver's bind callback * Context: can sleep * * Call this in your gadget driver's module initialization function, @@ -869,8 +861,7 @@ struct usb_gadget_driver { * registration call returns. It's expected that the @bind() function will * be in init sections. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); +int usb_gadget_probe_driver(struct usb_gadget_driver *driver); /** * usb_gadget_unregister_driver - unregister a gadget driver diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index c5fdb14..608050b 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -135,8 +135,8 @@ struct usb_hcd { unsigned int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ - u64 rsrc_start; /* memory/io resource start */ - u64 rsrc_len; /* memory/io resource length */ + resource_size_t rsrc_start; /* memory/io resource start */ + resource_size_t rsrc_len; /* memory/io resource length */ unsigned power_budget; /* in mA, 0 = no limit */ /* bandwidth_mutex should be taken before adding or removing diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h new file mode 100644 index 0000000..28884c7 --- /dev/null +++ b/include/linux/usb/nop-usb-xceiv.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_USB_NOP_XCEIV_H +#define __LINUX_USB_NOP_XCEIV_H + +#include <linux/usb/otg.h> + +struct nop_usb_xceiv_platform_data { + enum usb_phy_type type; +}; + +#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +/* sometimes transceivers are accessed only through e.g. ULPI */ +extern void usb_nop_xceiv_register(void); +extern void usb_nop_xceiv_unregister(void); +#else +static inline void usb_nop_xceiv_register(void) +{ +} + +static inline void usb_nop_xceiv_unregister(void) +{ +} +#endif + +#endif /* __LINUX_USB_NOP_XCEIV_H */ diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h index 2808f2a..74e7755 100644 --- a/include/linux/usb/ohci_pdriver.h +++ b/include/linux/usb/ohci_pdriver.h @@ -33,6 +33,14 @@ struct usb_ohci_pdata { unsigned big_endian_desc:1; unsigned big_endian_mmio:1; unsigned no_big_frame_no:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); + /* Turn off all power and clocks */ + void (*power_off)(struct platform_device *pdev); + /* Turn on only VBUS suspend power and hotplug detection, + * turn off everything else */ + void (*power_suspend)(struct platform_device *pdev); }; #endif /* __USB_CORE_OHCI_PDRIVER_H */ diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h new file mode 100644 index 0000000..0ea17f8 --- /dev/null +++ b/include/linux/usb/omap_usb.h @@ -0,0 +1,46 @@ +/* + * omap_usb.h -- omap usb2 phy header file + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I <kishon@ti.com> + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_OMAP_USB2_H +#define __DRIVERS_OMAP_USB2_H + +#include <linux/usb/otg.h> + +struct omap_usb { + struct usb_phy phy; + struct phy_companion *comparator; + struct device *dev; + u32 __iomem *control_dev; + struct clk *wkupclk; + u8 is_suspended:1; +}; + +#define PHY_PD 0x1 + +#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy) + +#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE) +extern int omap_usb2_set_comparator(struct phy_companion *comparator); +#else +static inline int omap_usb2_set_comparator(struct phy_companion *comparator) +{ + return -ENODEV; +} +#endif + +#endif /* __DRIVERS_OMAP_USB_H */ diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 45824be..e8a5fe8 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -9,56 +9,7 @@ #ifndef __LINUX_USB_OTG_H #define __LINUX_USB_OTG_H -#include <linux/notifier.h> - -/* OTG defines lots of enumeration states before device reset */ -enum usb_otg_state { - OTG_STATE_UNDEFINED = 0, - - /* single-role peripheral, and dual-role default-b */ - OTG_STATE_B_IDLE, - OTG_STATE_B_SRP_INIT, - OTG_STATE_B_PERIPHERAL, - - /* extra dual-role default-b states */ - OTG_STATE_B_WAIT_ACON, - OTG_STATE_B_HOST, - - /* dual-role default-a */ - OTG_STATE_A_IDLE, - OTG_STATE_A_WAIT_VRISE, - OTG_STATE_A_WAIT_BCON, - OTG_STATE_A_HOST, - OTG_STATE_A_SUSPEND, - OTG_STATE_A_PERIPHERAL, - OTG_STATE_A_WAIT_VFALL, - OTG_STATE_A_VBUS_ERR, -}; - -enum usb_phy_events { - USB_EVENT_NONE, /* no events or cable disconnected */ - USB_EVENT_VBUS, /* vbus valid event */ - USB_EVENT_ID, /* id was grounded */ - USB_EVENT_CHARGER, /* usb dedicated charger */ - USB_EVENT_ENUMERATED, /* gadget driver enumerated */ -}; - -/* associate a type with PHY */ -enum usb_phy_type { - USB_PHY_TYPE_UNDEFINED, - USB_PHY_TYPE_USB2, - USB_PHY_TYPE_USB3, -}; - -struct usb_phy; - -/* for transceivers connected thru an ULPI interface, the user must - * provide access ops - */ -struct usb_phy_io_ops { - int (*read)(struct usb_phy *x, u32 reg); - int (*write)(struct usb_phy *x, u32 val, u32 reg); -}; +#include <linux/usb/phy.h> struct usb_otg { u8 default_a; @@ -85,134 +36,9 @@ struct usb_otg { }; -/* - * the otg driver needs to interact with both device side and host side - * usb controllers. it decides which controller is active at a given - * moment, using the transceiver, ID signal, HNP and sometimes static - * configuration information (including "board isn't wired for otg"). - */ -struct usb_phy { - struct device *dev; - const char *label; - unsigned int flags; - - enum usb_phy_type type; - enum usb_otg_state state; - enum usb_phy_events last_event; - - struct usb_otg *otg; - - struct device *io_dev; - struct usb_phy_io_ops *io_ops; - void __iomem *io_priv; - - /* for notification of usb_phy_events */ - struct atomic_notifier_head notifier; - - /* to pass extra port status to the root hub */ - u16 port_status; - u16 port_change; - - /* to support controllers that have multiple transceivers */ - struct list_head head; - - /* initialize/shutdown the OTG controller */ - int (*init)(struct usb_phy *x); - void (*shutdown)(struct usb_phy *x); - - /* effective for B devices, ignored for A-peripheral */ - int (*set_power)(struct usb_phy *x, - unsigned mA); - - /* for non-OTG B devices: set transceiver into suspend mode */ - int (*set_suspend)(struct usb_phy *x, - int suspend); - - /* notify phy connect status change */ - int (*notify_connect)(struct usb_phy *x, int port); - int (*notify_disconnect)(struct usb_phy *x, int port); -}; - - -/* for board-specific init logic */ -extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); -extern void usb_remove_phy(struct usb_phy *); - -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) -/* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_nop_xceiv_register(void); -extern void usb_nop_xceiv_unregister(void); -#else -static inline void usb_nop_xceiv_register(void) -{ -} - -static inline void usb_nop_xceiv_unregister(void) -{ -} -#endif - -/* helpers for direct access thru low-level io interface */ -static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) -{ - if (x->io_ops && x->io_ops->read) - return x->io_ops->read(x, reg); - - return -EINVAL; -} - -static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) -{ - if (x->io_ops && x->io_ops->write) - return x->io_ops->write(x, val, reg); - - return -EINVAL; -} - -static inline int -usb_phy_init(struct usb_phy *x) -{ - if (x->init) - return x->init(x); - - return 0; -} - -static inline void -usb_phy_shutdown(struct usb_phy *x) -{ - if (x->shutdown) - x->shutdown(x); -} - -/* for usb host and peripheral controller drivers */ #ifdef CONFIG_USB_OTG_UTILS -extern struct usb_phy *usb_get_phy(enum usb_phy_type type); -extern struct usb_phy *devm_usb_get_phy(struct device *dev, - enum usb_phy_type type); -extern void usb_put_phy(struct usb_phy *); -extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern const char *otg_state_string(enum usb_otg_state state); #else -static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) -{ - return NULL; -} - -static inline struct usb_phy *devm_usb_get_phy(struct device *dev, - enum usb_phy_type type) -{ - return NULL; -} - -static inline void usb_put_phy(struct usb_phy *x) -{ -} - -static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) -{ -} - static inline const char *otg_state_string(enum usb_otg_state state) { return NULL; @@ -262,42 +88,6 @@ otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph) } static inline int -usb_phy_set_power(struct usb_phy *x, unsigned mA) -{ - if (x && x->set_power) - return x->set_power(x, mA); - return 0; -} - -/* Context: can sleep */ -static inline int -usb_phy_set_suspend(struct usb_phy *x, int suspend) -{ - if (x->set_suspend != NULL) - return x->set_suspend(x, suspend); - else - return 0; -} - -static inline int -usb_phy_notify_connect(struct usb_phy *x, int port) -{ - if (x->notify_connect) - return x->notify_connect(x, port); - else - return 0; -} - -static inline int -usb_phy_notify_disconnect(struct usb_phy *x, int port) -{ - if (x->notify_disconnect) - return x->notify_disconnect(x, port); - else - return 0; -} - -static inline int otg_start_srp(struct usb_otg *otg) { if (otg && otg->start_srp) @@ -306,31 +96,7 @@ otg_start_srp(struct usb_otg *otg) return -ENOTSUPP; } -/* notifiers */ -static inline int -usb_register_notifier(struct usb_phy *x, struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&x->notifier, nb); -} - -static inline void -usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb) -{ - atomic_notifier_chain_unregister(&x->notifier, nb); -} - /* for OTG controller drivers (and maybe other stuff) */ extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num); -static inline const char *usb_phy_type_string(enum usb_phy_type type) -{ - switch (type) { - case USB_PHY_TYPE_USB2: - return "USB2 PHY"; - case USB_PHY_TYPE_USB3: - return "USB3 PHY"; - default: - return "UNKNOWN PHY TYPE"; - } -} #endif /* __LINUX_USB_OTG_H */ diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h new file mode 100644 index 0000000..06b5bae --- /dev/null +++ b/include/linux/usb/phy.h @@ -0,0 +1,233 @@ +/* USB OTG (On The Go) defines */ +/* + * + * These APIs may be used between USB controllers. USB device drivers + * (for either host or peripheral roles) don't use these calls; they + * continue to use just usb_device and usb_gadget. + */ + +#ifndef __LINUX_USB_PHY_H +#define __LINUX_USB_PHY_H + +#include <linux/notifier.h> + +enum usb_phy_events { + USB_EVENT_NONE, /* no events or cable disconnected */ + USB_EVENT_VBUS, /* vbus valid event */ + USB_EVENT_ID, /* id was grounded */ + USB_EVENT_CHARGER, /* usb dedicated charger */ + USB_EVENT_ENUMERATED, /* gadget driver enumerated */ +}; + +/* associate a type with PHY */ +enum usb_phy_type { + USB_PHY_TYPE_UNDEFINED, + USB_PHY_TYPE_USB2, + USB_PHY_TYPE_USB3, +}; + +/* OTG defines lots of enumeration states before device reset */ +enum usb_otg_state { + OTG_STATE_UNDEFINED = 0, + + /* single-role peripheral, and dual-role default-b */ + OTG_STATE_B_IDLE, + OTG_STATE_B_SRP_INIT, + OTG_STATE_B_PERIPHERAL, + + /* extra dual-role default-b states */ + OTG_STATE_B_WAIT_ACON, + OTG_STATE_B_HOST, + + /* dual-role default-a */ + OTG_STATE_A_IDLE, + OTG_STATE_A_WAIT_VRISE, + OTG_STATE_A_WAIT_BCON, + OTG_STATE_A_HOST, + OTG_STATE_A_SUSPEND, + OTG_STATE_A_PERIPHERAL, + OTG_STATE_A_WAIT_VFALL, + OTG_STATE_A_VBUS_ERR, +}; + +struct usb_phy; +struct usb_otg; + +/* for transceivers connected thru an ULPI interface, the user must + * provide access ops + */ +struct usb_phy_io_ops { + int (*read)(struct usb_phy *x, u32 reg); + int (*write)(struct usb_phy *x, u32 val, u32 reg); +}; + +struct usb_phy { + struct device *dev; + const char *label; + unsigned int flags; + + enum usb_phy_type type; + enum usb_otg_state state; + enum usb_phy_events last_event; + + struct usb_otg *otg; + + struct device *io_dev; + struct usb_phy_io_ops *io_ops; + void __iomem *io_priv; + + /* for notification of usb_phy_events */ + struct atomic_notifier_head notifier; + + /* to pass extra port status to the root hub */ + u16 port_status; + u16 port_change; + + /* to support controllers that have multiple transceivers */ + struct list_head head; + + /* initialize/shutdown the OTG controller */ + int (*init)(struct usb_phy *x); + void (*shutdown)(struct usb_phy *x); + + /* effective for B devices, ignored for A-peripheral */ + int (*set_power)(struct usb_phy *x, + unsigned mA); + + /* for non-OTG B devices: set transceiver into suspend mode */ + int (*set_suspend)(struct usb_phy *x, + int suspend); + + /* notify phy connect status change */ + int (*notify_connect)(struct usb_phy *x, int port); + int (*notify_disconnect)(struct usb_phy *x, int port); +}; + + +/* for board-specific init logic */ +extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); +extern void usb_remove_phy(struct usb_phy *); + +/* helpers for direct access thru low-level io interface */ +static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) +{ + if (x->io_ops && x->io_ops->read) + return x->io_ops->read(x, reg); + + return -EINVAL; +} + +static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) +{ + if (x->io_ops && x->io_ops->write) + return x->io_ops->write(x, val, reg); + + return -EINVAL; +} + +static inline int +usb_phy_init(struct usb_phy *x) +{ + if (x->init) + return x->init(x); + + return 0; +} + +static inline void +usb_phy_shutdown(struct usb_phy *x) +{ + if (x->shutdown) + x->shutdown(x); +} + +/* for usb host and peripheral controller drivers */ +#ifdef CONFIG_USB_OTG_UTILS +extern struct usb_phy *usb_get_phy(enum usb_phy_type type); +extern struct usb_phy *devm_usb_get_phy(struct device *dev, + enum usb_phy_type type); +extern void usb_put_phy(struct usb_phy *); +extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); +#else +static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) +{ + return NULL; +} + +static inline struct usb_phy *devm_usb_get_phy(struct device *dev, + enum usb_phy_type type) +{ + return NULL; +} + +static inline void usb_put_phy(struct usb_phy *x) +{ +} + +static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) +{ +} + +#endif + +static inline int +usb_phy_set_power(struct usb_phy *x, unsigned mA) +{ + if (x && x->set_power) + return x->set_power(x, mA); + return 0; +} + +/* Context: can sleep */ +static inline int +usb_phy_set_suspend(struct usb_phy *x, int suspend) +{ + if (x->set_suspend != NULL) + return x->set_suspend(x, suspend); + else + return 0; +} + +static inline int +usb_phy_notify_connect(struct usb_phy *x, int port) +{ + if (x->notify_connect) + return x->notify_connect(x, port); + else + return 0; +} + +static inline int +usb_phy_notify_disconnect(struct usb_phy *x, int port) +{ + if (x->notify_disconnect) + return x->notify_disconnect(x, port); + else + return 0; +} + +/* notifiers */ +static inline int +usb_register_notifier(struct usb_phy *x, struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&x->notifier, nb); +} + +static inline void +usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb) +{ + atomic_notifier_chain_unregister(&x->notifier, nb); +} + +static inline const char *usb_phy_type_string(enum usb_phy_type type) +{ + switch (type) { + case USB_PHY_TYPE_USB2: + return "USB2 PHY"; + case USB_PHY_TYPE_USB3: + return "USB3 PHY"; + default: + return "UNKNOWN PHY TYPE"; + } +} +#endif /* __LINUX_USB_PHY_H */ diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h new file mode 100644 index 0000000..edd2ec2 --- /dev/null +++ b/include/linux/usb/phy_companion.h @@ -0,0 +1,34 @@ +/* + * phy-companion.h -- phy companion to indicate the comparator part of PHY + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I <kishon@ti.com> + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_PHY_COMPANION_H +#define __DRIVERS_PHY_COMPANION_H + +#include <linux/usb/otg.h> + +/* phy_companion to take care of VBUS, ID and srp capabilities */ +struct phy_companion { + + /* effective for A-peripheral, ignored for B devices */ + int (*set_vbus)(struct phy_companion *x, bool enabled); + + /* for B devices only: start session with A-Host */ + int (*start_srp)(struct phy_companion *x); +}; + +#endif /* __DRIVERS_PHY_COMPANION_H */ diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 3e93de7..52f944d 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -19,8 +19,8 @@ /* device can't handle its Configuration or Interface strings */ #define USB_QUIRK_CONFIG_INTF_STRINGS 0x00000008 -/*device will morph if reset, don't use reset for handling errors */ -#define USB_QUIRK_RESET_MORPHS 0x00000010 +/* device can't be reset(e.g morph devices), don't use reset */ +#define USB_QUIRK_RESET 0x00000010 /* device has more interface descriptions than the bNumInterfaces count, and can't handle talking to these interfaces */ diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 86c0b45..ef9be7e 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -301,17 +301,13 @@ extern void usb_serial_port_softint(struct usb_serial_port *port); extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message); extern int usb_serial_resume(struct usb_interface *intf); -extern int ezusb_writememory(struct usb_serial *serial, int address, - unsigned char *data, int length, __u8 bRequest); -extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit); - /* USB Serial console functions */ #ifdef CONFIG_USB_SERIAL_CONSOLE -extern void usb_serial_console_init(int debug, int minor); +extern void usb_serial_console_init(int minor); extern void usb_serial_console_exit(void); extern void usb_serial_console_disconnect(struct usb_serial *serial); #else -static inline void usb_serial_console_init(int debug, int minor) { } +static inline void usb_serial_console_init(int minor) { } static inline void usb_serial_console_exit(void) { } static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} #endif @@ -333,7 +329,7 @@ extern void usb_serial_generic_throttle(struct tty_struct *tty); extern void usb_serial_generic_unthrottle(struct tty_struct *tty); extern void usb_serial_generic_disconnect(struct usb_serial *serial); extern void usb_serial_generic_release(struct usb_serial *serial); -extern int usb_serial_generic_register(int debug); +extern int usb_serial_generic_register(void); extern void usb_serial_generic_deregister(void); extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, gfp_t mem_flags); @@ -355,30 +351,14 @@ extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; -static inline void usb_serial_debug_data(int debug, - struct device *dev, +static inline void usb_serial_debug_data(struct device *dev, const char *function, int size, const unsigned char *data) { - int i; - - if (debug) { - dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) - printk("%.2x ", data[i]); - printk("\n"); - } + dev_dbg(dev, "%s - length = %d, data = %*ph\n", + function, size, size, data); } -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) \ -do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ -} while (0) - /* * Macro for reporting errors in write path to avoid inifinite loop * when port is used as a console. diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 935ce9f..176b1ca 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-tegra/include/mach/usb_phy.h - * * Copyright (C) 2010 Google, Inc. * * This software is licensed under the terms of the GNU General Public @@ -14,8 +12,8 @@ * */ -#ifndef __MACH_USB_PHY_H -#define __MACH_USB_PHY_H +#ifndef __TEGRA_USB_PHY_H +#define __TEGRA_USB_PHY_H #include <linux/clk.h> #include <linux/usb/otg.h> @@ -59,19 +57,17 @@ struct tegra_usb_phy { enum tegra_usb_phy_mode mode; void *config; struct usb_phy *ulpi; + struct usb_phy u_phy; + struct device *dev; }; struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); - void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy); - void tegra_usb_phy_preresume(struct tegra_usb_phy *phy); void tegra_usb_phy_postresume(struct tegra_usb_phy *phy); @@ -81,6 +77,4 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); -void tegra_usb_phy_close(struct tegra_usb_phy *phy); - -#endif /* __MACH_USB_PHY_H */ +#endif /* __TEGRA_USB_PHY_H */ diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index e84e769..bf99cd0 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -72,33 +72,9 @@ enum { US_DO_ALL_FLAGS }; #undef US_FLAG -/* - * The bias field for libusual and friends. - */ -#define USB_US_TYPE_NONE 0 -#define USB_US_TYPE_STOR 1 /* usb-storage */ -#define USB_US_TYPE_UB 2 /* ub */ - -#define USB_US_TYPE(flags) (((flags) >> 24) & 0xFF) -#define USB_US_ORIG_FLAGS(flags) ((flags) & 0x00FFFFFF) - #include <linux/usb/storage.h> -/* - */ extern int usb_usual_ignore_device(struct usb_interface *intf); extern struct usb_device_id usb_storage_usb_ids[]; -#ifdef CONFIG_USB_LIBUSUAL - -extern void usb_usual_set_present(int type); -extern void usb_usual_clear_present(int type); -extern int usb_usual_check_type(const struct usb_device_id *, int type); -#else - -#define usb_usual_set_present(t) do { } while(0) -#define usb_usual_clear_present(t) do { } while(0) -#define usb_usual_check_type(id, t) (0) -#endif /* CONFIG_USB_LIBUSUAL */ - #endif /* __LINUX_USB_USUAL_H */ diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index 3b74666..4abe28e 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -131,6 +131,19 @@ struct usbdevfs_hub_portinfo { #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 #define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 +/* USBDEVFS_DISCONNECT_CLAIM flags & struct */ + +/* disconnect-and-claim if the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 +/* disconnect-and-claim except when the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 + +struct usbdevfs_disconnect_claim { + unsigned int interface; + unsigned int flags; + char driver[USBDEVFS_MAXDRIVERNAME + 1]; +}; + #ifdef __KERNEL__ #ifdef CONFIG_COMPAT #include <linux/compat.h> @@ -211,5 +224,6 @@ struct usbdevfs_ioctl32 { #define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) #define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) +#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) #endif /* _LINUX_USBDEVICE_FS_H */ diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 9ce788d..bfa1d50 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -258,6 +258,22 @@ struct physdev_pci_device { uint8_t devfn; }; +#define PHYSDEVOP_DBGP_RESET_PREPARE 1 +#define PHYSDEVOP_DBGP_RESET_DONE 2 + +#define PHYSDEVOP_DBGP_BUS_UNKNOWN 0 +#define PHYSDEVOP_DBGP_BUS_PCI 1 + +#define PHYSDEVOP_dbgp_op 29 +struct physdev_dbgp_op { + /* IN */ + uint8_t op; + uint8_t bus; + union { + struct physdev_pci_device pci; + } u; +}; + /* * Notify that some PIRQ-bound event channels have been unmasked. * ** This command is obsolete since interface version 0x00030202 and is ** @@ -1,14 +1,14 @@ #include <linux/bcd.h> #include <linux/export.h> -unsigned bcd2bin(unsigned char val) +unsigned _bcd2bin(unsigned char val) { return (val & 0x0f) + (val >> 4) * 10; } -EXPORT_SYMBOL(bcd2bin); +EXPORT_SYMBOL(_bcd2bin); -unsigned char bin2bcd(unsigned val) +unsigned char _bin2bcd(unsigned val) { return ((val / 10) << 4) + val % 10; } -EXPORT_SYMBOL(bin2bcd); +EXPORT_SYMBOL(_bin2bcd); diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index b0adb27..68d0734 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c @@ -253,9 +253,6 @@ static int find_testdev(const char *name, const struct stat *sb, int flag) if (flag != FTW_F) return 0; - /* ignore /proc/bus/usb/{devices,drivers} */ - if (strrchr(name, '/')[1] == 'd') - return 0; fd = fopen(name, "rb"); if (!fd) { @@ -356,28 +353,8 @@ restart: static const char *usbfs_dir_find(void) { - static char usbfs_path_0[] = "/dev/usb/devices"; - static char usbfs_path_1[] = "/proc/bus/usb/devices"; static char udev_usb_path[] = "/dev/bus/usb"; - static char *const usbfs_paths[] = { - usbfs_path_0, usbfs_path_1 - }; - - static char *const * - end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths; - - char *const *it = usbfs_paths; - do { - int fd = open(*it, O_RDONLY); - close(fd); - if (fd >= 0) { - strrchr(*it, '/')[0] = '\0'; - return *it; - } - } while (++it != end); - - /* real device-nodes managed by udev */ if (access(udev_usb_path, F_OK) == 0) return udev_usb_path; @@ -489,7 +466,7 @@ usage: goto usage; if (!all && !device) { fprintf (stderr, "must specify '-a' or '-D dev', " - "or DEVICE=/proc/bus/usb/BBB/DDD in env\n"); + "or DEVICE=/dev/bus/usb/BBB/DDD in env\n"); goto usage; } |