Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (205 commits) USB: EHCI: Remove SPARC_LEON {read,write}_be definitions from ehci.h USB: UHCI: Support big endian GRUSBHC HC sparc: add {read,write}*_be routines USB: UHCI: Add support for big endian descriptors USB: UHCI: Use ACCESS_ONCE rather than using a full compiler barrier USB: UHCI: Add support for big endian mmio usb-storage: Correct adjust_quirks to include latest flags usb/isp1760: Fix possible unlink problems usb/isp1760: Move function isp1760_endpoint_disable() within file. USB: remove remaining usages of hcd->state from usbcore and fix regression usb: musb: ux500: add configuration and build options for ux500 dma usb: musb: ux500: add dma glue layer for ux500 usb: musb: ux500: add dma name for ux500 usb: musb: ux500: add ux500 specific code for gadget side usb: musb: fix compile error usb-storage: fix up the unusual_realtek device list USB: gadget: f_audio: Fix invalid dereference of initdata EHCI: don't rescan interrupt QHs needlessly OHCI: fix regression caused by nVidia shutdown workaround USB: OTG: msm: Free VCCCX regulator even if we can't set the voltage ...
This commit is contained in:
commit
c44dead70a
184 changed files with 14777 additions and 3506 deletions
|
@ -2585,6 +2585,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
bytes of sense data);
|
||||
c = FIX_CAPACITY (decrease the reported
|
||||
device capacity by one sector);
|
||||
d = NO_READ_DISC_INFO (don't use
|
||||
READ_DISC_INFO command);
|
||||
e = NO_READ_CAPACITY_16 (don't use
|
||||
READ_CAPACITY_16 command);
|
||||
h = CAPACITY_HEURISTICS (decrease the
|
||||
reported device capacity by one
|
||||
sector if the number is odd);
|
||||
|
|
|
@ -95,9 +95,11 @@ pre_reset
|
|||
|
||||
int (*pre_reset)(struct usb_interface *intf);
|
||||
|
||||
Another driver or user space is triggering a reset on the device which
|
||||
contains the interface passed as an argument. Cease IO and save any
|
||||
device state you need to restore.
|
||||
A driver or user space is triggering a reset on the device which
|
||||
contains the interface passed as an argument. Cease IO, wait for all
|
||||
outstanding URBs to complete, and save any device state you need to
|
||||
restore. No more URBs may be submitted until the post_reset method
|
||||
is called.
|
||||
|
||||
If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
|
||||
are in atomic context.
|
||||
|
|
|
@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys
|
|||
[SourceDisksFiles]
|
||||
[SourceDisksNames]
|
||||
[DeviceList]
|
||||
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
|
||||
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02
|
||||
|
||||
[DeviceList.NTamd64]
|
||||
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
|
||||
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
|
|
|
@ -18,15 +18,15 @@ DriverVer = 06/21/2006,6.0.6000.16384
|
|||
|
||||
; Decoration for x86 architecture
|
||||
[LinuxDevices.NTx86]
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
|
||||
|
||||
; Decoration for x64 architecture
|
||||
[LinuxDevices.NTamd64]
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
|
||||
|
||||
; Decoration for ia64 architecture
|
||||
[LinuxDevices.NTia64]
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
|
||||
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
|
||||
|
||||
;@@@ This is the common setting for setup
|
||||
[ControlFlags]
|
||||
|
|
|
@ -4253,7 +4253,7 @@ F: include/linux/isicom.h
|
|||
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
|
||||
M: Felipe Balbi <balbi@ti.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
T: git git://gitorious.org/usb/usb.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
|
||||
S: Maintained
|
||||
F: drivers/usb/musb/
|
||||
|
||||
|
@ -4588,6 +4588,7 @@ M: Felipe Balbi <balbi@ti.com>
|
|||
M: David Brownell <dbrownell@users.sourceforge.net>
|
||||
L: linux-usb@vger.kernel.org
|
||||
L: linux-omap@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
|
||||
S: Maintained
|
||||
F: drivers/usb/*/*omap*
|
||||
F: arch/arm/*omap*/usb*
|
||||
|
|
|
@ -170,6 +170,7 @@ config MACH_NURI
|
|||
select S3C_DEV_HSMMC3
|
||||
select S3C_DEV_I2C1
|
||||
select S3C_DEV_I2C5
|
||||
select S5P_DEV_USB_EHCI
|
||||
select EXYNOS4_SETUP_I2C1
|
||||
select EXYNOS4_SETUP_I2C5
|
||||
select EXYNOS4_SETUP_SDHCI
|
||||
|
|
|
@ -54,3 +54,5 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
|
|||
obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
|
||||
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o
|
||||
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
|
||||
|
||||
obj-$(CONFIG_USB_SUPPORT) += usb-phy.o
|
||||
|
|
|
@ -97,7 +97,12 @@ static struct map_desc exynos4_iodesc[] __initdata = {
|
|||
.pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
|
||||
.length = SZ_4K,
|
||||
.type = MT_DEVICE,
|
||||
},
|
||||
}, {
|
||||
.virtual = (unsigned long)S5P_VA_USB_HSPHY,
|
||||
.pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
|
||||
.length = SZ_4K,
|
||||
.type = MT_DEVICE,
|
||||
}
|
||||
};
|
||||
|
||||
static void exynos4_idle(void)
|
||||
|
|
|
@ -101,6 +101,9 @@
|
|||
|
||||
#define EXYNOS4_PA_SROMC 0x12570000
|
||||
|
||||
#define EXYNOS4_PA_EHCI 0x12580000
|
||||
#define EXYNOS4_PA_HSPHY 0x125B0000
|
||||
|
||||
#define EXYNOS4_PA_UART 0x13800000
|
||||
|
||||
#define EXYNOS4_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
|
||||
|
@ -143,6 +146,7 @@
|
|||
#define S5P_PA_SROMC EXYNOS4_PA_SROMC
|
||||
#define S5P_PA_SYSCON EXYNOS4_PA_SYSCON
|
||||
#define S5P_PA_TIMER EXYNOS4_PA_TIMER
|
||||
#define S5P_PA_EHCI EXYNOS4_PA_EHCI
|
||||
|
||||
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
|
||||
#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
|
||||
|
||||
#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708)
|
||||
#define S5P_USBHOST_PHY_ENABLE (1 << 0)
|
||||
|
||||
#define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4)
|
||||
#define S5P_MIPI_DPHY_ENABLE (1 << 0)
|
||||
#define S5P_MIPI_DPHY_SRESETN (1 << 1)
|
||||
|
|
64
arch/arm/mach-exynos4/include/mach/regs-usb-phy.h
Normal file
64
arch/arm/mach-exynos4/include/mach/regs-usb-phy.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_S5P_REGS_USB_PHY_H
|
||||
#define __PLAT_S5P_REGS_USB_PHY_H
|
||||
|
||||
#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S5P_VA_USB_HSPHY)
|
||||
|
||||
#define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00)
|
||||
#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
|
||||
#define PHY1_HSIC1_SLEEP (1 << 12)
|
||||
#define PHY1_HSIC1_FORCE_SUSPEND (1 << 11)
|
||||
#define PHY1_HSIC0_SLEEP (1 << 10)
|
||||
#define PHY1_HSIC0_FORCE_SUSPEND (1 << 9)
|
||||
|
||||
#define PHY1_STD_NORMAL_MASK (0x7 << 6)
|
||||
#define PHY1_STD_SLEEP (1 << 8)
|
||||
#define PHY1_STD_ANALOG_POWERDOWN (1 << 7)
|
||||
#define PHY1_STD_FORCE_SUSPEND (1 << 6)
|
||||
|
||||
#define PHY0_NORMAL_MASK (0x39 << 0)
|
||||
#define PHY0_SLEEP (1 << 5)
|
||||
#define PHY0_OTG_DISABLE (1 << 4)
|
||||
#define PHY0_ANALOG_POWERDOWN (1 << 3)
|
||||
#define PHY0_FORCE_SUSPEND (1 << 0)
|
||||
|
||||
#define EXYNOS4_PHYCLK EXYNOS4_HSOTG_PHYREG(0x04)
|
||||
#define PHY1_COMMON_ON_N (1 << 7)
|
||||
#define PHY0_COMMON_ON_N (1 << 4)
|
||||
#define PHY0_ID_PULLUP (1 << 2)
|
||||
#define CLKSEL_MASK (0x3 << 0)
|
||||
#define CLKSEL_SHIFT (0)
|
||||
#define CLKSEL_48M (0x0 << 0)
|
||||
#define CLKSEL_12M (0x2 << 0)
|
||||
#define CLKSEL_24M (0x3 << 0)
|
||||
|
||||
#define EXYNOS4_RSTCON EXYNOS4_HSOTG_PHYREG(0x08)
|
||||
#define HOST_LINK_PORT_SWRST_MASK (0xf << 6)
|
||||
#define HOST_LINK_PORT2_SWRST (1 << 9)
|
||||
#define HOST_LINK_PORT1_SWRST (1 << 8)
|
||||
#define HOST_LINK_PORT0_SWRST (1 << 7)
|
||||
#define HOST_LINK_ALL_SWRST (1 << 6)
|
||||
|
||||
#define PHY1_SWRST_MASK (0x7 << 3)
|
||||
#define PHY1_HSIC_SWRST (1 << 5)
|
||||
#define PHY1_STD_SWRST (1 << 4)
|
||||
#define PHY1_ALL_SWRST (1 << 3)
|
||||
|
||||
#define PHY0_SWRST_MASK (0x7 << 0)
|
||||
#define PHY0_PHYLINK_SWRST (1 << 2)
|
||||
#define PHY0_HLINK_SWRST (1 << 1)
|
||||
#define PHY0_SWRST (1 << 0)
|
||||
|
||||
#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34)
|
||||
#define FPENABLEN (1 << 0)
|
||||
|
||||
#endif /* __PLAT_S5P_REGS_USB_PHY_H */
|
|
@ -30,6 +30,8 @@
|
|||
#include <plat/cpu.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/sdhci.h>
|
||||
#include <plat/ehci.h>
|
||||
#include <plat/clock.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
|
||||
|
@ -262,6 +264,16 @@ static struct i2c_board_info i2c5_devs[] __initdata = {
|
|||
/* max8997, To be updated */
|
||||
};
|
||||
|
||||
/* USB EHCI */
|
||||
static struct s5p_ehci_platdata nuri_ehci_pdata;
|
||||
|
||||
static void __init nuri_ehci_init(void)
|
||||
{
|
||||
struct s5p_ehci_platdata *pdata = &nuri_ehci_pdata;
|
||||
|
||||
s5p_ehci_set_platdata(pdata);
|
||||
}
|
||||
|
||||
static struct platform_device *nuri_devices[] __initdata = {
|
||||
/* Samsung Platform Devices */
|
||||
&emmc_fixed_voltage,
|
||||
|
@ -270,6 +282,7 @@ static struct platform_device *nuri_devices[] __initdata = {
|
|||
&s3c_device_hsmmc3,
|
||||
&s3c_device_wdt,
|
||||
&s3c_device_timer[0],
|
||||
&s5p_device_ehci,
|
||||
|
||||
/* NURI Devices */
|
||||
&nuri_gpio_keys,
|
||||
|
@ -291,6 +304,9 @@ static void __init nuri_machine_init(void)
|
|||
i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
|
||||
i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
|
||||
|
||||
nuri_ehci_init();
|
||||
clk_xusbxti.rate = 24000000;
|
||||
|
||||
/* Last */
|
||||
platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
|
||||
}
|
||||
|
|
136
arch/arm/mach-exynos4/usb-phy.c
Normal file
136
arch/arm/mach-exynos4/usb-phy.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/regs-pmu.h>
|
||||
#include <mach/regs-usb-phy.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/usb-phy.h>
|
||||
|
||||
static int exynos4_usb_phy1_init(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *otg_clk;
|
||||
struct clk *xusbxti_clk;
|
||||
u32 phyclk;
|
||||
u32 rstcon;
|
||||
int err;
|
||||
|
||||
otg_clk = clk_get(&pdev->dev, "otg");
|
||||
if (IS_ERR(otg_clk)) {
|
||||
dev_err(&pdev->dev, "Failed to get otg clock\n");
|
||||
return PTR_ERR(otg_clk);
|
||||
}
|
||||
|
||||
err = clk_enable(otg_clk);
|
||||
if (err) {
|
||||
clk_put(otg_clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
|
||||
S5P_USBHOST_PHY_CONTROL);
|
||||
|
||||
/* set clock frequency for PLL */
|
||||
phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
|
||||
|
||||
xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
|
||||
if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
|
||||
switch (clk_get_rate(xusbxti_clk)) {
|
||||
case 12 * MHZ:
|
||||
phyclk |= CLKSEL_12M;
|
||||
break;
|
||||
case 24 * MHZ:
|
||||
phyclk |= CLKSEL_24M;
|
||||
break;
|
||||
default:
|
||||
case 48 * MHZ:
|
||||
/* default reference clock */
|
||||
break;
|
||||
}
|
||||
clk_put(xusbxti_clk);
|
||||
}
|
||||
|
||||
writel(phyclk, EXYNOS4_PHYCLK);
|
||||
|
||||
/* floating prevention logic: disable */
|
||||
writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON);
|
||||
|
||||
/* set to normal HSIC 0 and 1 of PHY1 */
|
||||
writel((readl(EXYNOS4_PHYPWR) & ~PHY1_HSIC_NORMAL_MASK),
|
||||
EXYNOS4_PHYPWR);
|
||||
|
||||
/* set to normal standard USB of PHY1 */
|
||||
writel((readl(EXYNOS4_PHYPWR) & ~PHY1_STD_NORMAL_MASK), EXYNOS4_PHYPWR);
|
||||
|
||||
/* reset all ports of both PHY and Link */
|
||||
rstcon = readl(EXYNOS4_RSTCON) | HOST_LINK_PORT_SWRST_MASK |
|
||||
PHY1_SWRST_MASK;
|
||||
writel(rstcon, EXYNOS4_RSTCON);
|
||||
udelay(10);
|
||||
|
||||
rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK);
|
||||
writel(rstcon, EXYNOS4_RSTCON);
|
||||
udelay(50);
|
||||
|
||||
clk_disable(otg_clk);
|
||||
clk_put(otg_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos4_usb_phy1_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *otg_clk;
|
||||
int err;
|
||||
|
||||
otg_clk = clk_get(&pdev->dev, "otg");
|
||||
if (IS_ERR(otg_clk)) {
|
||||
dev_err(&pdev->dev, "Failed to get otg clock\n");
|
||||
return PTR_ERR(otg_clk);
|
||||
}
|
||||
|
||||
err = clk_enable(otg_clk);
|
||||
if (err) {
|
||||
clk_put(otg_clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN),
|
||||
EXYNOS4_PHYPWR);
|
||||
|
||||
writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE,
|
||||
S5P_USBHOST_PHY_CONTROL);
|
||||
|
||||
clk_disable(otg_clk);
|
||||
clk_put(otg_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5p_usb_phy_init(struct platform_device *pdev, int type)
|
||||
{
|
||||
if (type == S5P_USB_PHY_HOST)
|
||||
return exynos4_usb_phy1_init(pdev);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
|
||||
{
|
||||
if (type == S5P_USB_PHY_HOST)
|
||||
return exynos4_usb_phy1_exit(pdev);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
|
@ -21,6 +21,10 @@
|
|||
/* USB host controller */
|
||||
#define S3C2410_PA_USBHOST (0x49000000)
|
||||
|
||||
/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */
|
||||
#define S3C2416_PA_HSUDC (0x49800000)
|
||||
#define S3C2416_SZ_HSUDC (SZ_4K)
|
||||
|
||||
/* DMA controller */
|
||||
#define S3C2410_PA_DMA (0x4B000000)
|
||||
#define S3C24XX_SZ_DMA SZ_1M
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
#define S3C2443_SYSID S3C2443_CLKREG(0x5C)
|
||||
#define S3C2443_PWRCFG S3C2443_CLKREG(0x60)
|
||||
#define S3C2443_RSTCON S3C2443_CLKREG(0x64)
|
||||
#define S3C2443_PHYCTRL S3C2443_CLKREG(0x80)
|
||||
#define S3C2443_PHYPWR S3C2443_CLKREG(0x84)
|
||||
#define S3C2443_URSTCON S3C2443_CLKREG(0x88)
|
||||
#define S3C2443_UCLKCON S3C2443_CLKREG(0x8C)
|
||||
|
||||
#define S3C2443_SWRST_RESET (0x533c2443)
|
||||
|
||||
|
@ -121,6 +125,27 @@
|
|||
|
||||
#define S3C2443_PWRCFG_SLEEP (1<<15)
|
||||
|
||||
#define S3C2443_PWRCFG_USBPHY (1 << 4)
|
||||
|
||||
#define S3C2443_URSTCON_FUNCRST (1 << 2)
|
||||
#define S3C2443_URSTCON_PHYRST (1 << 0)
|
||||
|
||||
#define S3C2443_PHYCTRL_CLKSEL (1 << 3)
|
||||
#define S3C2443_PHYCTRL_EXTCLK (1 << 2)
|
||||
#define S3C2443_PHYCTRL_PLLSEL (1 << 1)
|
||||
#define S3C2443_PHYCTRL_DSPORT (1 << 0)
|
||||
|
||||
#define S3C2443_PHYPWR_COMMON_ON (1 << 31)
|
||||
#define S3C2443_PHYPWR_ANALOG_PD (1 << 4)
|
||||
#define S3C2443_PHYPWR_PLL_REFCLK (1 << 3)
|
||||
#define S3C2443_PHYPWR_XO_ON (1 << 2)
|
||||
#define S3C2443_PHYPWR_PLL_PWRDN (1 << 1)
|
||||
#define S3C2443_PHYPWR_FSUSPEND (1 << 0)
|
||||
|
||||
#define S3C2443_UCLKCON_DETECT_VBUS (1 << 31)
|
||||
#define S3C2443_UCLKCON_FUNC_CLKEN (1 << 2)
|
||||
#define S3C2443_UCLKCON_TCLKEN (1 << 0)
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
static inline unsigned int
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-lcd.h>
|
||||
#include <mach/regs-s3c2443-clock.h>
|
||||
|
||||
#include <mach/idle.h>
|
||||
#include <mach/leds-gpio.h>
|
||||
|
@ -47,6 +49,7 @@
|
|||
#include <plat/cpu.h>
|
||||
#include <plat/nand.h>
|
||||
#include <plat/sdhci.h>
|
||||
#include <plat/udc.h>
|
||||
|
||||
#include <plat/regs-fb-v4.h>
|
||||
#include <plat/fb.h>
|
||||
|
@ -121,6 +124,27 @@ static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
|
|||
}
|
||||
};
|
||||
|
||||
void smdk2416_hsudc_gpio_init(void)
|
||||
{
|
||||
s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
|
||||
s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
|
||||
s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
|
||||
s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
|
||||
}
|
||||
|
||||
void smdk2416_hsudc_gpio_uninit(void)
|
||||
{
|
||||
s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
|
||||
s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
|
||||
s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
|
||||
}
|
||||
|
||||
struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
|
||||
.epnum = 9,
|
||||
.gpio_init = smdk2416_hsudc_gpio_init,
|
||||
.gpio_uninit = smdk2416_hsudc_gpio_uninit,
|
||||
};
|
||||
|
||||
struct s3c_fb_pd_win smdk2416_fb_win[] = {
|
||||
[0] = {
|
||||
/* think this is the same as the smdk6410 */
|
||||
|
@ -186,6 +210,7 @@ static struct platform_device *smdk2416_devices[] __initdata = {
|
|||
&s3c_device_i2c0,
|
||||
&s3c_device_hsmmc0,
|
||||
&s3c_device_hsmmc1,
|
||||
&s3c_device_usb_hsudc,
|
||||
};
|
||||
|
||||
static void __init smdk2416_map_io(void)
|
||||
|
@ -203,6 +228,8 @@ static void __init smdk2416_machine_init(void)
|
|||
s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
|
||||
s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
|
||||
|
||||
s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
|
||||
|
||||
gpio_request(S3C2410_GPB(4), "USBHost Power");
|
||||
gpio_direction_output(S3C2410_GPB(4), 1);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
@ -233,6 +234,46 @@ void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
|
|||
}
|
||||
}
|
||||
|
||||
/* USB High Speed 2.0 Device (Gadget) */
|
||||
static struct resource s3c_hsudc_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C2416_PA_HSUDC,
|
||||
.end = S3C2416_PA_HSUDC + S3C2416_SZ_HSUDC - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_USBD,
|
||||
.end = IRQ_USBD,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 s3c_hsudc_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device s3c_device_usb_hsudc = {
|
||||
.name = "s3c-hsudc",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c_hsudc_resource),
|
||||
.resource = s3c_hsudc_resource,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_hsudc_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
|
||||
{
|
||||
struct s3c24xx_hsudc_platdata *npd;
|
||||
|
||||
npd = kmalloc(sizeof(*npd), GFP_KERNEL);
|
||||
if (npd) {
|
||||
memcpy(npd, pd, sizeof(*npd));
|
||||
s3c_device_usb_hsudc.dev.platform_data = npd;
|
||||
} else {
|
||||
printk(KERN_ERR "no memory for udc platform data\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* IIS */
|
||||
|
||||
static struct resource s3c_iis_resource[] = {
|
||||
|
|
|
@ -37,4 +37,21 @@ struct s3c2410_udc_mach_info {
|
|||
|
||||
extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
|
||||
|
||||
/**
|
||||
* s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
|
||||
* @epnum: Number of endpoints to be instantiated by the controller driver.
|
||||
* @gpio_init: Platform specific USB related GPIO initialization.
|
||||
* @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
|
||||
*
|
||||
* Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
|
||||
* controllers.
|
||||
*/
|
||||
struct s3c24xx_hsudc_platdata {
|
||||
unsigned int epnum;
|
||||
void (*gpio_init)(void);
|
||||
void (*gpio_uninit)(void);
|
||||
};
|
||||
|
||||
extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
|
||||
|
||||
#endif /* __ASM_ARM_ARCH_UDC_H */
|
||||
|
|
|
@ -85,6 +85,11 @@ config S5P_DEV_CSIS1
|
|||
help
|
||||
Compile in platform device definitions for MIPI-CSIS channel 1
|
||||
|
||||
config S5P_DEV_USB_EHCI
|
||||
bool
|
||||
help
|
||||
Compile in platform device definition for USB EHCI
|
||||
|
||||
config S5P_SETUP_MIPIPHY
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -33,4 +33,5 @@ obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
|
|||
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
|
||||
obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
|
||||
obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
|
||||
obj-$(CONFIG_S5P_DEV_USB_EHCI) += dev-ehci.o
|
||||
obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
|
||||
|
|
57
arch/arm/plat-s5p/dev-ehci.c
Normal file
57
arch/arm/plat-s5p/dev-ehci.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/map.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/ehci.h>
|
||||
#include <plat/usb-phy.h>
|
||||
|
||||
/* USB EHCI Host Controller registration */
|
||||
static struct resource s5p_ehci_resource[] = {
|
||||
[0] = {
|
||||
.start = S5P_PA_EHCI,
|
||||
.end = S5P_PA_EHCI + SZ_256 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = IRQ_USB_HOST,
|
||||
.end = IRQ_USB_HOST,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 s5p_device_ehci_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s5p_device_ehci = {
|
||||
.name = "s5p-ehci",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s5p_ehci_resource),
|
||||
.resource = s5p_ehci_resource,
|
||||
.dev = {
|
||||
.dma_mask = &s5p_device_ehci_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
|
||||
void __init s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd)
|
||||
{
|
||||
struct s5p_ehci_platdata *npd;
|
||||
|
||||
npd = s3c_set_platdata(pd, sizeof(struct s5p_ehci_platdata),
|
||||
&s5p_device_ehci);
|
||||
|
||||
if (!npd->phy_init)
|
||||
npd->phy_init = s5p_usb_phy_init;
|
||||
if (!npd->phy_exit)
|
||||
npd->phy_exit = s5p_usb_phy_exit;
|
||||
}
|
21
arch/arm/plat-s5p/include/plat/ehci.h
Normal file
21
arch/arm/plat-s5p/include/plat/ehci.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_S5P_EHCI_H
|
||||
#define __PLAT_S5P_EHCI_H
|
||||
|
||||
struct s5p_ehci_platdata {
|
||||
int (*phy_init)(struct platform_device *pdev, int type);
|
||||
int (*phy_exit)(struct platform_device *pdev, int type);
|
||||
};
|
||||
|
||||
extern void s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd);
|
||||
|
||||
#endif /* __PLAT_S5P_EHCI_H */
|
|
@ -39,7 +39,7 @@
|
|||
#define S5P_VA_TWD S5P_VA_COREPERI(0x600)
|
||||
#define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000)
|
||||
|
||||
#define S3C_VA_USB_HSPHY S3C_ADDR(0x02900000)
|
||||
#define S5P_VA_USB_HSPHY S3C_ADDR(0x02900000)
|
||||
|
||||
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000))
|
||||
#define VA_VIC0 VA_VIC(0)
|
||||
|
|
22
arch/arm/plat-s5p/include/plat/usb-phy.h
Normal file
22
arch/arm/plat-s5p/include/plat/usb-phy.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_S5P_USB_PHY_H
|
||||
#define __PLAT_S5P_USB_PHY_H
|
||||
|
||||
enum s5p_usb_phy_type {
|
||||
S5P_USB_PHY_DEVICE,
|
||||
S5P_USB_PHY_HOST,
|
||||
};
|
||||
|
||||
extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
|
||||
extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
|
||||
|
||||
#endif /* __PLAT_S5P_REGS_USB_PHY_H */
|
|
@ -88,6 +88,7 @@ extern struct platform_device s3c64xx_device_onenand1;
|
|||
extern struct platform_device s5p_device_onenand;
|
||||
|
||||
extern struct platform_device s3c_device_usbgadget;
|
||||
extern struct platform_device s3c_device_usb_hsudc;
|
||||
extern struct platform_device s3c_device_usb_hsotg;
|
||||
|
||||
extern struct platform_device s5pv210_device_ac97;
|
||||
|
@ -142,6 +143,8 @@ extern struct platform_device s5p_device_fimc3;
|
|||
extern struct platform_device s5p_device_mipi_csis0;
|
||||
extern struct platform_device s5p_device_mipi_csis1;
|
||||
|
||||
extern struct platform_device s5p_device_ehci;
|
||||
|
||||
extern struct platform_device exynos4_device_sysmmu;
|
||||
|
||||
/* s3c2440 specific devices */
|
||||
|
|
|
@ -26,12 +26,17 @@ config ATH79_MACH_PB44
|
|||
endmenu
|
||||
|
||||
config SOC_AR71XX
|
||||
select USB_ARCH_HAS_EHCI
|
||||
select USB_ARCH_HAS_OHCI
|
||||
def_bool n
|
||||
|
||||
config SOC_AR724X
|
||||
select USB_ARCH_HAS_EHCI
|
||||
select USB_ARCH_HAS_OHCI
|
||||
def_bool n
|
||||
|
||||
config SOC_AR913X
|
||||
select USB_ARCH_HAS_EHCI
|
||||
def_bool n
|
||||
|
||||
config ATH79_DEV_AR913X_WMAC
|
||||
|
|
|
@ -64,11 +64,10 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
|
|||
obj-$(CONFIG_PARIDE) += block/paride/
|
||||
obj-$(CONFIG_TC) += tc/
|
||||
obj-$(CONFIG_UWB) += uwb/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += usb/otg/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += usb/
|
||||
obj-$(CONFIG_USB) += usb/
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
|
||||
obj-$(CONFIG_PCI) += usb/
|
||||
obj-$(CONFIG_USB_GADGET) += usb/gadget/
|
||||
obj-$(CONFIG_USB_GADGET) += usb/
|
||||
obj-$(CONFIG_SERIO) += input/serio/
|
||||
obj-$(CONFIG_GAMEPORT) += input/gameport/
|
||||
obj-$(CONFIG_INPUT) += input/
|
||||
|
|
|
@ -1775,19 +1775,37 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
|
||||
|
|
|
@ -380,19 +380,38 @@
|
|||
|
||||
#define USB_VENDOR_ID_LD 0x0f11
|
||||
#define USB_DEVICE_ID_LD_CASSY 0x1000
|
||||
#define USB_DEVICE_ID_LD_CASSY2 0x1001
|
||||
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
|
||||
#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011
|
||||
#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
|
||||
#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038
|
||||
#define USB_DEVICE_ID_LD_JWM 0x1080
|
||||
#define USB_DEVICE_ID_LD_DMMP 0x1081
|
||||
#define USB_DEVICE_ID_LD_UMIP 0x1090
|
||||
#define USB_DEVICE_ID_LD_XRAY1 0x1100
|
||||
#define USB_DEVICE_ID_LD_UMIC 0x10A0
|
||||
#define USB_DEVICE_ID_LD_UMIB 0x10B0
|
||||
#define USB_DEVICE_ID_LD_XRAY 0x1100
|
||||
#define USB_DEVICE_ID_LD_XRAY2 0x1101
|
||||
#define USB_DEVICE_ID_LD_XRAYCT 0x1110
|
||||
#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
|
||||
#define USB_DEVICE_ID_LD_MOTOR 0x1210
|
||||
#define USB_DEVICE_ID_LD_COM3LAB 0x2000
|
||||
#define USB_DEVICE_ID_LD_TELEPORT 0x2010
|
||||
#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
|
||||
#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
|
||||
#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
|
||||
#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050
|
||||
#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051
|
||||
#define USB_DEVICE_ID_LD_ABSESP 0x2060
|
||||
#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070
|
||||
#define USB_DEVICE_ID_LD_MCT 0x2080
|
||||
#define USB_DEVICE_ID_LD_HYBRID 0x2090
|
||||
#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
|
||||
|
||||
#define USB_VENDOR_ID_LOGITECH 0x046d
|
||||
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
|
||||
|
|
|
@ -65,8 +65,10 @@ config USB_ARCH_HAS_EHCI
|
|||
default y if ARCH_CNS3XXX
|
||||
default y if ARCH_VT8500
|
||||
default y if PLAT_SPEAR
|
||||
default y if PLAT_S5P
|
||||
default y if ARCH_MSM
|
||||
default y if MICROBLAZE
|
||||
default y if SPARC_LEON
|
||||
default PCI
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
|
@ -116,6 +118,8 @@ source "drivers/usb/host/Kconfig"
|
|||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/renesas_usbhs/Kconfig"
|
||||
|
||||
source "drivers/usb/class/Kconfig"
|
||||
|
||||
source "drivers/usb/storage/Kconfig"
|
||||
|
|
|
@ -22,6 +22,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
|||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
|
||||
|
||||
|
@ -45,3 +46,8 @@ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
|
|||
|
||||
obj-$(CONFIG_USB_ATM) += atm/
|
||||
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += musb/
|
||||
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += otg/
|
||||
obj-$(CONFIG_USB_GADGET) += gadget/
|
||||
|
|
|
@ -7,35 +7,12 @@
|
|||
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
|
||||
* Copyright (c) 2005 David Kubicek <dave@awk.cz>
|
||||
* Copyright (c) 2011 Johan Hovold <jhovold@gmail.com>
|
||||
*
|
||||
* USB Abstract Control Model driver for USB modems and ISDN adapters
|
||||
*
|
||||
* Sponsored by SuSE
|
||||
*
|
||||
* ChangeLog:
|
||||
* v0.9 - thorough cleaning, URBification, almost a rewrite
|
||||
* v0.10 - some more cleanups
|
||||
* v0.11 - fixed flow control, read error doesn't stop reads
|
||||
* v0.12 - added TIOCM ioctls, added break handling, made struct acm
|
||||
* kmalloced
|
||||
* v0.13 - added termios, added hangup
|
||||
* v0.14 - sized down struct acm
|
||||
* v0.15 - fixed flow control again - characters could be lost
|
||||
* v0.16 - added code for modems with swapped data and control interfaces
|
||||
* v0.17 - added new style probing
|
||||
* v0.18 - fixed new style probing for devices with more configurations
|
||||
* v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
|
||||
* v0.20 - switched to probing on interface (rather than device) class
|
||||
* v0.21 - revert to probing on device for devices with multiple configs
|
||||
* v0.22 - probe only the control interface. if usbcore doesn't choose the
|
||||
* config we want, sysadmin changes bConfigurationValue in sysfs.
|
||||
* v0.23 - use softirq for rx processing, as needed by tty layer
|
||||
* v0.24 - change probe method to evaluate CDC union descriptor
|
||||
* v0.25 - downstream tasks paralelized to maximize throughput
|
||||
* v0.26 - multiple write urbs, writesize increased
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -74,13 +51,7 @@
|
|||
#include "cdc-acm.h"
|
||||
|
||||
|
||||
#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.26"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
|
||||
|
||||
static struct usb_driver acm_driver;
|
||||
|
@ -94,12 +65,6 @@ static DEFINE_MUTEX(open_mutex);
|
|||
static const struct tty_port_operations acm_port_ops = {
|
||||
};
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define verbose 1
|
||||
#else
|
||||
#define verbose 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for ACM control messages.
|
||||
*/
|
||||
|
@ -111,8 +76,9 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value,
|
|||
request, USB_RT_ACM, value,
|
||||
acm->control->altsetting[0].desc.bInterfaceNumber,
|
||||
buf, len, 5000);
|
||||
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
|
||||
request, value, len, retval);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - rq 0x%02x, val %#x, len %#x, result %d\n",
|
||||
__func__, request, value, len, retval);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
|
@ -192,7 +158,9 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
|
|||
|
||||
rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
|
||||
if (rc < 0) {
|
||||
dbg("usb_submit_urb(write bulk) failed: %d", rc);
|
||||
dev_err(&acm->data->dev,
|
||||
"%s - usb_submit_urb(write bulk) failed: %d\n",
|
||||
__func__, rc);
|
||||
acm_write_done(acm, wb);
|
||||
}
|
||||
return rc;
|
||||
|
@ -211,7 +179,8 @@ static int acm_write_start(struct acm *acm, int wbn)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
dbg("%s susp_count: %d", __func__, acm->susp_count);
|
||||
dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
|
||||
acm->susp_count);
|
||||
usb_autopm_get_interface_async(acm->control);
|
||||
if (acm->susp_count) {
|
||||
if (!acm->delayed_wb)
|
||||
|
@ -287,10 +256,14 @@ static void acm_ctrl_irq(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(&acm->control->dev,
|
||||
"%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __func__, status);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - nonzero urb status received: %d\n",
|
||||
__func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -302,8 +275,8 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
data = (unsigned char *)(dr + 1);
|
||||
switch (dr->bNotificationType) {
|
||||
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
||||
dbg("%s network", dr->wValue ?
|
||||
"connected to" : "disconnected from");
|
||||
dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
|
||||
__func__, dr->wValue);
|
||||
break;
|
||||
|
||||
case USB_CDC_NOTIFY_SERIAL_STATE:
|
||||
|
@ -313,7 +286,8 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
if (tty) {
|
||||
if (!acm->clocal &&
|
||||
(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
dbg("calling hangup");
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - calling hangup\n", __func__);
|
||||
tty_hangup(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
@ -321,7 +295,10 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
|
||||
acm->ctrlin = newctrl;
|
||||
|
||||
dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - input control lines: dcd%c dsr%c break%c "
|
||||
"ring%c framing%c parity%c overrun%c\n",
|
||||
__func__,
|
||||
acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
|
||||
acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
|
||||
acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
|
||||
|
@ -332,7 +309,10 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
break;
|
||||
|
||||
default:
|
||||
dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - unknown notification %d received: index %d "
|
||||
"len %d data0 %d data1 %d\n",
|
||||
__func__,
|
||||
dr->bNotificationType, dr->wIndex,
|
||||
dr->wLength, data[0], data[1]);
|
||||
break;
|
||||
|
@ -340,166 +320,96 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
exit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
|
||||
"result %d", __func__, retval);
|
||||
dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
/* data interface returns incoming bytes, or we got unthrottled */
|
||||
static void acm_read_bulk(struct urb *urb)
|
||||
static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
|
||||
{
|
||||
struct acm_rb *buf;
|
||||
struct acm_ru *rcv = urb->context;
|
||||
struct acm *acm = rcv->instance;
|
||||
int status = urb->status;
|
||||
int res;
|
||||
|
||||
dbg("Entering acm_read_bulk with status %d", status);
|
||||
if (!test_and_clear_bit(index, &acm->read_urbs_free))
|
||||
return 0;
|
||||
|
||||
if (!ACM_READY(acm)) {
|
||||
dev_dbg(&acm->data->dev, "Aborting, acm not ready");
|
||||
dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
|
||||
|
||||
res = usb_submit_urb(acm->read_urbs[index], mem_flags);
|
||||
if (res) {
|
||||
if (res != -EPERM) {
|
||||
dev_err(&acm->data->dev,
|
||||
"%s - usb_submit_urb failed: %d\n",
|
||||
__func__, res);
|
||||
}
|
||||
set_bit(index, &acm->read_urbs_free);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
|
||||
{
|
||||
int res;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < acm->rx_buflimit; ++i) {
|
||||
res = acm_submit_read_urb(acm, i, mem_flags);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acm_process_read_urb(struct acm *acm, struct urb *urb)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!urb->actual_length)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static void acm_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct acm_rb *rb = urb->context;
|
||||
struct acm *acm = rb->instance;
|
||||
unsigned long flags;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
|
||||
rb->index, urb->actual_length);
|
||||
set_bit(rb->index, &acm->read_urbs_free);
|
||||
|
||||
if (!acm->dev) {
|
||||
dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
|
||||
return;
|
||||
}
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
if (status)
|
||||
dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
|
||||
if (urb->status) {
|
||||
dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
|
||||
__func__, urb->status);
|
||||
return;
|
||||
}
|
||||
acm_process_read_urb(acm, urb);
|
||||
|
||||
buf = rcv->buffer;
|
||||
buf->size = urb->actual_length;
|
||||
|
||||
if (likely(status == 0)) {
|
||||
spin_lock(&acm->read_lock);
|
||||
acm->processing++;
|
||||
list_add_tail(&rcv->list, &acm->spare_read_urbs);
|
||||
list_add_tail(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
/* throttle device if requested by tty */
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
acm->throttled = acm->throttle_req;
|
||||
if (!acm->throttled && !acm->susp_count) {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
|
||||
} else {
|
||||
/* we drop the buffer due to an error */
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add_tail(&rcv->list, &acm->spare_read_urbs);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
/* nevertheless the tasklet must be kicked unconditionally
|
||||
so the queue cannot dry up */
|
||||
}
|
||||
if (likely(!acm->susp_count))
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
}
|
||||
|
||||
static void acm_rx_tasklet(unsigned long _acm)
|
||||
{
|
||||
struct acm *acm = (void *)_acm;
|
||||
struct acm_rb *buf;
|
||||
struct tty_struct *tty;
|
||||
struct acm_ru *rcv;
|
||||
unsigned long flags;
|
||||
unsigned char throttled;
|
||||
|
||||
dbg("Entering acm_rx_tasklet");
|
||||
|
||||
if (!ACM_READY(acm)) {
|
||||
dbg("acm_rx_tasklet: ACM not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acm->throttle_lock, flags);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock_irqrestore(&acm->throttle_lock, flags);
|
||||
if (throttled) {
|
||||
dbg("acm_rx_tasklet: throttled");
|
||||
return;
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
|
||||
next_buffer:
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (list_empty(&acm->filled_read_bufs)) {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
goto urbs;
|
||||
}
|
||||
buf = list_entry(acm->filled_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
|
||||
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
|
||||
|
||||
if (tty) {
|
||||
spin_lock_irqsave(&acm->throttle_lock, flags);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock_irqrestore(&acm->throttle_lock, flags);
|
||||
if (!throttled) {
|
||||
tty_insert_flip_string(tty, buf->base, buf->size);
|
||||
tty_flip_buffer_push(tty);
|
||||
} else {
|
||||
tty_kref_put(tty);
|
||||
dbg("Throttling noticed");
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
goto next_buffer;
|
||||
|
||||
urbs:
|
||||
tty_kref_put(tty);
|
||||
|
||||
while (!list_empty(&acm->spare_read_bufs)) {
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (list_empty(&acm->spare_read_urbs)) {
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
rcv = list_entry(acm->spare_read_urbs.next,
|
||||
struct acm_ru, list);
|
||||
list_del(&rcv->list);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
|
||||
buf = list_entry(acm->spare_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
|
||||
rcv->buffer = buf;
|
||||
|
||||
if (acm->is_int_ep)
|
||||
usb_fill_int_urb(rcv->urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
buf->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk, rcv, acm->bInterval);
|
||||
else
|
||||
usb_fill_bulk_urb(rcv->urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
buf->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk, rcv);
|
||||
rcv->urb->transfer_dma = buf->dma;
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
/* This shouldn't kill the driver as unsuccessful URBs are
|
||||
returned to the free-urbs-pool and resubmited ASAP */
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (acm->susp_count ||
|
||||
usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
list_add(&rcv->list, &acm->spare_read_urbs);
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
} else {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
}
|
||||
|
||||
/* data interface wrote those outgoing bytes */
|
||||
|
@ -509,9 +419,9 @@ static void acm_write_bulk(struct urb *urb)
|
|||
struct acm *acm = wb->instance;
|
||||
unsigned long flags;
|
||||
|
||||
if (verbose || urb->status
|
||||
|| (urb->actual_length != urb->transfer_buffer_length))
|
||||
dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
|
||||
if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
|
||||
dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
|
||||
__func__,
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb->status);
|
||||
|
@ -521,8 +431,6 @@ static void acm_write_bulk(struct urb *urb)
|
|||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
if (ACM_READY(acm))
|
||||
schedule_work(&acm->work);
|
||||
else
|
||||
wake_up_interruptible(&acm->drain_wait);
|
||||
}
|
||||
|
||||
static void acm_softint(struct work_struct *work)
|
||||
|
@ -530,7 +438,8 @@ static void acm_softint(struct work_struct *work)
|
|||
struct acm *acm = container_of(work, struct acm, work);
|
||||
struct tty_struct *tty;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "tx work\n");
|
||||
dev_vdbg(&acm->data->dev, "%s\n", __func__);
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
|
@ -548,8 +457,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct acm *acm;
|
||||
int rv = -ENODEV;
|
||||
int i;
|
||||
dbg("Entering acm_tty_open.");
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
|
||||
|
@ -559,6 +466,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
else
|
||||
rv = 0;
|
||||
|
||||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||||
|
||||
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
||||
|
||||
tty->driver_data = acm;
|
||||
|
@ -578,38 +487,28 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
acm->ctrlurb->dev = acm->dev;
|
||||
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
|
||||
dbg("usb_submit_urb(ctrl irq) failed");
|
||||
dev_err(&acm->control->dev,
|
||||
"%s - usb_submit_urb(ctrl irq) failed\n", __func__);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
|
||||
(acm->ctrl_caps & USB_CDC_CAP_LINE))
|
||||
goto full_bailout;
|
||||
goto bail_out;
|
||||
|
||||
usb_autopm_put_interface(acm->control);
|
||||
|
||||
INIT_LIST_HEAD(&acm->spare_read_urbs);
|
||||
INIT_LIST_HEAD(&acm->spare_read_bufs);
|
||||
INIT_LIST_HEAD(&acm->filled_read_bufs);
|
||||
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
|
||||
|
||||
acm->throttle = 0;
|
||||
if (acm_submit_read_urbs(acm, GFP_KERNEL))
|
||||
goto bail_out;
|
||||
|
||||
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
||||
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
mutex_unlock(&acm->mutex);
|
||||
out:
|
||||
mutex_unlock(&open_mutex);
|
||||
return rv;
|
||||
|
||||
full_bailout:
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
bail_out:
|
||||
acm->port.count--;
|
||||
mutex_unlock(&acm->mutex);
|
||||
|
@ -622,26 +521,24 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
static void acm_tty_unregister(struct acm *acm)
|
||||
{
|
||||
int i, nr;
|
||||
int i;
|
||||
|
||||
nr = acm->rx_buflimit;
|
||||
tty_unregister_device(acm_tty_driver, acm->minor);
|
||||
usb_put_intf(acm->control);
|
||||
acm_table[acm->minor] = NULL;
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_free_urb(acm->read_urbs[i]);
|
||||
kfree(acm->country_codes);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
static int acm_tty_chars_in_buffer(struct tty_struct *tty);
|
||||
|
||||
static void acm_port_down(struct acm *acm)
|
||||
{
|
||||
int i, nr = acm->rx_buflimit;
|
||||
int i;
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
if (acm->dev) {
|
||||
usb_autopm_get_interface(acm->control);
|
||||
|
@ -649,10 +546,8 @@ static void acm_port_down(struct acm *acm)
|
|||
usb_kill_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
tasklet_disable(&acm->urb_task);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
tasklet_enable(&acm->urb_task);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_kill_urb(acm->read_urbs[i]);
|
||||
acm->control->needs_remote_wakeup = 0;
|
||||
usb_autopm_put_interface(acm->control);
|
||||
}
|
||||
|
@ -698,13 +593,13 @@ static int acm_tty_write(struct tty_struct *tty,
|
|||
int wbn;
|
||||
struct acm_wb *wb;
|
||||
|
||||
dbg("Entering acm_tty_write to write %d bytes,", count);
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return -EINVAL;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
wbn = acm_wb_alloc(acm);
|
||||
if (wbn < 0) {
|
||||
|
@ -714,7 +609,7 @@ static int acm_tty_write(struct tty_struct *tty,
|
|||
wb = &acm->wb[wbn];
|
||||
|
||||
count = (count > acm->writesize) ? acm->writesize : count;
|
||||
dbg("Get %d bytes...", count);
|
||||
dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
|
||||
memcpy(wb->buf, buf, count);
|
||||
wb->len = count;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
@ -751,22 +646,31 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
|
|||
static void acm_tty_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
spin_lock_bh(&acm->throttle_lock);
|
||||
acm->throttle = 1;
|
||||
spin_unlock_bh(&acm->throttle_lock);
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
acm->throttle_req = 1;
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
}
|
||||
|
||||
static void acm_tty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
unsigned int was_throttled;
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
spin_lock_bh(&acm->throttle_lock);
|
||||
acm->throttle = 0;
|
||||
spin_unlock_bh(&acm->throttle_lock);
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
was_throttled = acm->throttled;
|
||||
acm->throttled = 0;
|
||||
acm->throttle_req = 0;
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
|
||||
if (was_throttled)
|
||||
acm_submit_read_urbs(acm, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int acm_tty_break_ctl(struct tty_struct *tty, int state)
|
||||
|
@ -777,7 +681,8 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
|
|||
return -EINVAL;
|
||||
retval = acm_send_break(acm, state ? 0xffff : 0);
|
||||
if (retval < 0)
|
||||
dbg("send break failed");
|
||||
dev_dbg(&acm->control->dev, "%s - send break failed\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -872,7 +777,9 @@ static void acm_tty_set_termios(struct tty_struct *tty,
|
|||
|
||||
if (memcmp(&acm->line, &newline, sizeof newline)) {
|
||||
memcpy(&acm->line, &newline, sizeof newline);
|
||||
dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
|
||||
dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
|
||||
__func__,
|
||||
le32_to_cpu(newline.dwDTERate),
|
||||
newline.bCharFormat, newline.bParityType,
|
||||
newline.bDataBits);
|
||||
acm_set_line(acm, &acm->line);
|
||||
|
@ -897,11 +804,11 @@ static void acm_write_buffers_free(struct acm *acm)
|
|||
static void acm_read_buffers_free(struct acm *acm)
|
||||
{
|
||||
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
|
||||
int i, n = acm->rx_buflimit;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_free_coherent(usb_dev, acm->readsize,
|
||||
acm->rb[i].base, acm->rb[i].dma);
|
||||
acm->read_buffers[i].base, acm->read_buffers[i].dma);
|
||||
}
|
||||
|
||||
/* Little helper: write buffers allocate */
|
||||
|
@ -946,7 +853,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
u8 ac_management_function = 0;
|
||||
u8 call_management_function = 0;
|
||||
int call_interface_num = -1;
|
||||
int data_interface_num;
|
||||
int data_interface_num = -1;
|
||||
unsigned long quirks;
|
||||
int num_rx_buf;
|
||||
int i;
|
||||
|
@ -1030,7 +937,11 @@ static int acm_probe(struct usb_interface *intf,
|
|||
if (!union_header) {
|
||||
if (call_interface_num > 0) {
|
||||
dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
|
||||
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
|
||||
/* quirks for Droids MuIn LCD */
|
||||
if (quirks & NO_DATA_INTERFACE)
|
||||
data_interface = usb_ifnum_to_if(usb_dev, 0);
|
||||
else
|
||||
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
|
||||
control_interface = intf;
|
||||
} else {
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
|
||||
|
@ -1133,7 +1044,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
epwrite = t;
|
||||
}
|
||||
made_compressed_probe:
|
||||
dbg("interfaces are valid");
|
||||
dev_dbg(&intf->dev, "interfaces are valid\n");
|
||||
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
|
||||
|
||||
if (minor == ACM_TTY_MINORS) {
|
||||
|
@ -1143,7 +1054,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
|
||||
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
|
||||
if (acm == NULL) {
|
||||
dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
|
@ -1162,11 +1073,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
acm->ctrlsize = ctrlsize;
|
||||
acm->readsize = readsize;
|
||||
acm->rx_buflimit = num_rx_buf;
|
||||
acm->urb_task.func = acm_rx_tasklet;
|
||||
acm->urb_task.data = (unsigned long) acm;
|
||||
INIT_WORK(&acm->work, acm_softint);
|
||||
init_waitqueue_head(&acm->drain_wait);
|
||||
spin_lock_init(&acm->throttle_lock);
|
||||
spin_lock_init(&acm->write_lock);
|
||||
spin_lock_init(&acm->read_lock);
|
||||
mutex_init(&acm->mutex);
|
||||
|
@ -1179,53 +1086,69 @@ static int acm_probe(struct usb_interface *intf,
|
|||
|
||||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
if (!buf) {
|
||||
dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
goto alloc_fail2;
|
||||
}
|
||||
acm->ctrl_buffer = buf;
|
||||
|
||||
if (acm_write_buffers_alloc(acm) < 0) {
|
||||
dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
goto alloc_fail4;
|
||||
}
|
||||
|
||||
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->ctrlurb) {
|
||||
dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
goto alloc_fail5;
|
||||
}
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_ru *rcv = &(acm->ru[i]);
|
||||
struct acm_rb *rb = &(acm->read_buffers[i]);
|
||||
struct urb *urb;
|
||||
|
||||
rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (rcv->urb == NULL) {
|
||||
dev_dbg(&intf->dev,
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
|
||||
&rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_err(&intf->dev, "out of memory "
|
||||
"(read bufs usb_alloc_coherent)\n");
|
||||
goto alloc_fail6;
|
||||
}
|
||||
rb->index = i;
|
||||
rb->instance = acm;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (read urbs usb_alloc_urb)\n");
|
||||
goto alloc_fail6;
|
||||
}
|
||||
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
rcv->instance = acm;
|
||||
}
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_rb *rb = &(acm->rb[i]);
|
||||
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize,
|
||||
GFP_KERNEL, &rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_dbg(&intf->dev,
|
||||
"out of memory (read bufs usb_alloc_coherent)\n");
|
||||
goto alloc_fail7;
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->transfer_dma = rb->dma;
|
||||
if (acm->is_int_ep) {
|
||||
usb_fill_int_urb(urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
rb->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk_callback, rb,
|
||||
acm->bInterval);
|
||||
} else {
|
||||
usb_fill_bulk_urb(urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
rb->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk_callback, rb);
|
||||
}
|
||||
|
||||
acm->read_urbs[i] = urb;
|
||||
__set_bit(i, &acm->read_urbs_free);
|
||||
}
|
||||
for (i = 0; i < ACM_NW; i++) {
|
||||
struct acm_wb *snd = &(acm->wb[i]);
|
||||
|
||||
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (snd->urb == NULL) {
|
||||
dev_dbg(&intf->dev,
|
||||
"out of memory (write urbs usb_alloc_urb)");
|
||||
goto alloc_fail8;
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (write urbs usb_alloc_urb)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_int(epwrite))
|
||||
|
@ -1244,7 +1167,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
|
||||
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
|
||||
if (i < 0)
|
||||
goto alloc_fail8;
|
||||
goto alloc_fail7;
|
||||
|
||||
if (cfd) { /* export the country data */
|
||||
acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
|
||||
|
@ -1296,14 +1219,13 @@ static int acm_probe(struct usb_interface *intf,
|
|||
acm_table[minor] = acm;
|
||||
|
||||
return 0;
|
||||
alloc_fail8:
|
||||
alloc_fail7:
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
alloc_fail7:
|
||||
acm_read_buffers_free(acm);
|
||||
alloc_fail6:
|
||||
for (i = 0; i < num_rx_buf; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
usb_free_urb(acm->read_urbs[i]);
|
||||
acm_read_buffers_free(acm);
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
alloc_fail5:
|
||||
acm_write_buffers_free(acm);
|
||||
|
@ -1318,17 +1240,14 @@ static int acm_probe(struct usb_interface *intf,
|
|||
static void stop_data_traffic(struct acm *acm)
|
||||
{
|
||||
int i;
|
||||
dbg("Entering stop_data_traffic");
|
||||
|
||||
tasklet_disable(&acm->urb_task);
|
||||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||||
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
|
||||
tasklet_enable(&acm->urb_task);
|
||||
usb_kill_urb(acm->read_urbs[i]);
|
||||
|
||||
cancel_work_sync(&acm->work);
|
||||
}
|
||||
|
@ -1389,11 +1308,9 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
if (message.event & PM_EVENT_AUTO) {
|
||||
int b;
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
spin_lock(&acm->write_lock);
|
||||
b = acm->processing + acm->transmitting;
|
||||
spin_unlock(&acm->write_lock);
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
spin_lock_irq(&acm->write_lock);
|
||||
b = acm->transmitting;
|
||||
spin_unlock_irq(&acm->write_lock);
|
||||
if (b)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -1455,7 +1372,7 @@ static int acm_resume(struct usb_interface *intf)
|
|||
if (rv < 0)
|
||||
goto err_out;
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
rv = acm_submit_read_urbs(acm, GFP_NOIO);
|
||||
}
|
||||
|
||||
err_out:
|
||||
|
@ -1622,6 +1539,11 @@ static const struct usb_device_id acm_ids[] = {
|
|||
.driver_info = NOT_A_MODEM,
|
||||
},
|
||||
|
||||
/* Support for Droids MuIn LCD */
|
||||
{ USB_DEVICE(0x04d8, 0x000b),
|
||||
.driver_info = NO_DATA_INTERFACE,
|
||||
},
|
||||
|
||||
/* control interfaces without any protocol set */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
|
||||
USB_CDC_PROTO_NONE) },
|
||||
|
@ -1716,8 +1638,7 @@ static int __init acm_init(void)
|
|||
return retval;
|
||||
}
|
||||
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
|
||||
DRIVER_DESC "\n");
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -72,16 +72,10 @@ struct acm_wb {
|
|||
};
|
||||
|
||||
struct acm_rb {
|
||||
struct list_head list;
|
||||
int size;
|
||||
unsigned char *base;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
struct acm_ru {
|
||||
struct list_head list;
|
||||
struct acm_rb *buffer;
|
||||
struct urb *urb;
|
||||
int index;
|
||||
struct acm *instance;
|
||||
};
|
||||
|
||||
|
@ -97,35 +91,30 @@ struct acm {
|
|||
unsigned int country_code_size; /* size of this buffer */
|
||||
unsigned int country_rel_date; /* release date of version */
|
||||
struct acm_wb wb[ACM_NW];
|
||||
struct acm_ru ru[ACM_NR];
|
||||
struct acm_rb rb[ACM_NR];
|
||||
unsigned long read_urbs_free;
|
||||
struct urb *read_urbs[ACM_NR];
|
||||
struct acm_rb read_buffers[ACM_NR];
|
||||
int rx_buflimit;
|
||||
int rx_endpoint;
|
||||
spinlock_t read_lock;
|
||||
struct list_head spare_read_urbs;
|
||||
struct list_head spare_read_bufs;
|
||||
struct list_head filled_read_bufs;
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
int processing;
|
||||
int transmitting;
|
||||
spinlock_t write_lock;
|
||||
struct mutex mutex;
|
||||
struct usb_cdc_line_coding line; /* bits, stop, parity */
|
||||
struct work_struct work; /* work queue entry for line discipline waking up */
|
||||
wait_queue_head_t drain_wait; /* close processing */
|
||||
struct tasklet_struct urb_task; /* rx processing */
|
||||
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
|
||||
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
|
||||
unsigned int ctrlout; /* output control lines (DTR, RTS) */
|
||||
unsigned int writesize; /* max packet size for the output bulk endpoint */
|
||||
unsigned int readsize,ctrlsize; /* buffer sizes for freeing */
|
||||
unsigned int minor; /* acm minor number */
|
||||
unsigned char throttle; /* throttled by tty layer */
|
||||
unsigned char clocal; /* termios CLOCAL */
|
||||
unsigned int ctrl_caps; /* control capabilities from the class specific header */
|
||||
unsigned int susp_count; /* number of suspended interfaces */
|
||||
unsigned int combined_interfaces:1; /* control and data collapsed */
|
||||
unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */
|
||||
unsigned int throttled:1; /* actually throttled */
|
||||
unsigned int throttle_req:1; /* throttle requested */
|
||||
u8 bInterval;
|
||||
struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
|
||||
};
|
||||
|
@ -137,3 +126,4 @@ struct acm {
|
|||
#define SINGLE_RX_URB 2
|
||||
#define NO_CAP_LINE 4
|
||||
#define NOT_A_MODEM 8
|
||||
#define NO_DATA_INTERFACE 16
|
||||
|
|
|
@ -542,6 +542,8 @@ static int wdm_open(struct inode *inode, struct file *file)
|
|||
|
||||
mutex_lock(&desc->lock);
|
||||
if (!desc->count++) {
|
||||
desc->werr = 0;
|
||||
desc->rerr = 0;
|
||||
rv = usb_submit_urb(desc->validity, GFP_KERNEL);
|
||||
if (rv < 0) {
|
||||
desc->count--;
|
||||
|
@ -853,6 +855,18 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|||
struct wdm_device *desc = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&desc->lock);
|
||||
kill_urbs(desc);
|
||||
|
||||
/*
|
||||
* we notify everybody using poll of
|
||||
* an exceptional situation
|
||||
* must be done before recovery lest a spontaneous
|
||||
* message from the device is lost
|
||||
*/
|
||||
spin_lock_irq(&desc->iuspin);
|
||||
desc->rerr = -EINTR;
|
||||
spin_unlock_irq(&desc->iuspin);
|
||||
wake_up_all(&desc->wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
|
||||
else
|
||||
max_tx = 999999;
|
||||
if (desc->wBytesPerInterval > max_tx) {
|
||||
if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
|
||||
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to %d\n",
|
||||
|
|
|
@ -64,49 +64,49 @@
|
|||
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
|
||||
#define ALLOW_SERIAL_NUMBER
|
||||
|
||||
static const char *format_topo =
|
||||
static const char format_topo[] =
|
||||
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */
|
||||
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n";
|
||||
|
||||
static const char *format_string_manufacturer =
|
||||
static const char format_string_manufacturer[] =
|
||||
/* S: Manufacturer=xxxx */
|
||||
"S: Manufacturer=%.100s\n";
|
||||
|
||||
static const char *format_string_product =
|
||||
static const char format_string_product[] =
|
||||
/* S: Product=xxxx */
|
||||
"S: Product=%.100s\n";
|
||||
|
||||
#ifdef ALLOW_SERIAL_NUMBER
|
||||
static const char *format_string_serialnumber =
|
||||
static const char format_string_serialnumber[] =
|
||||
/* S: SerialNumber=xxxx */
|
||||
"S: SerialNumber=%.100s\n";
|
||||
#endif
|
||||
|
||||
static const char *format_bandwidth =
|
||||
static const char format_bandwidth[] =
|
||||
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
|
||||
"B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
|
||||
|
||||
static const char *format_device1 =
|
||||
static const char format_device1[] =
|
||||
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
|
||||
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
|
||||
|
||||
static const char *format_device2 =
|
||||
static const char format_device2[] =
|
||||
/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
|
||||
"P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
|
||||
|
||||
static const char *format_config =
|
||||
static const char format_config[] =
|
||||
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
|
||||
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
|
||||
|
||||
static const char *format_iad =
|
||||
static const char format_iad[] =
|
||||
/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
|
||||
"A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
|
||||
|
||||
static const char *format_iface =
|
||||
static const char format_iface[] =
|
||||
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
|
||||
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
|
||||
|
||||
static const char *format_endpt =
|
||||
static const char format_endpt[] =
|
||||
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
|
||||
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
|
||||
|
||||
|
|
|
@ -236,13 +236,6 @@ EXPORT_SYMBOL_GPL(usb_register_dev);
|
|||
void usb_deregister_dev(struct usb_interface *intf,
|
||||
struct usb_class_driver *class_driver)
|
||||
{
|
||||
int minor_base = class_driver->minor_base;
|
||||
char name[20];
|
||||
|
||||
#ifdef CONFIG_USB_DYNAMIC_MINORS
|
||||
minor_base = 0;
|
||||
#endif
|
||||
|
||||
if (intf->minor == -1)
|
||||
return;
|
||||
|
||||
|
@ -252,7 +245,6 @@ void usb_deregister_dev(struct usb_interface *intf,
|
|||
usb_minors[intf->minor] = NULL;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
snprintf(name, sizeof(name), class_driver->name, intf->minor - minor_base);
|
||||
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
|
||||
intf->usb_dev = NULL;
|
||||
intf->minor = -1;
|
||||
|
|
|
@ -986,7 +986,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
/* Did the HC die before the root hub was registered? */
|
||||
if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT)
|
||||
if (HCD_DEAD(hcd))
|
||||
usb_hc_died (hcd); /* This time clean up */
|
||||
}
|
||||
|
||||
|
@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
|
|||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
if (hcd->shared_hcd)
|
||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
|
||||
|
||||
if (unlikely(hcd->state == HC_STATE_HALT))
|
||||
usb_hc_died(hcd);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -2407,6 +2404,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
goto err_set_rh_speed;
|
||||
}
|
||||
|
||||
|
|
|
@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
|
|||
*status = le16_to_cpu(hub->status->port.wPortStatus);
|
||||
*change = le16_to_cpu(hub->status->port.wPortChange);
|
||||
|
||||
if ((hub->hdev->parent != NULL) &&
|
||||
hub_is_superspeed(hub->hdev)) {
|
||||
/* Translate the USB 3 port status */
|
||||
u16 tmp = *status & USB_SS_PORT_STAT_MASK;
|
||||
if (*status & USB_SS_PORT_STAT_POWER)
|
||||
tmp |= USB_PORT_STAT_POWER;
|
||||
*status = tmp;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&hub->status_mutex);
|
||||
|
@ -2160,11 +2151,76 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Warm reset a USB3 protocol port */
|
||||
static int hub_port_warm_reset(struct usb_hub *hub, int port)
|
||||
{
|
||||
int ret;
|
||||
u16 portstatus, portchange;
|
||||
|
||||
if (!hub_is_superspeed(hub->hdev)) {
|
||||
dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Warm reset the port */
|
||||
ret = set_port_feature(hub->hdev,
|
||||
port, USB_PORT_FEAT_BH_PORT_RESET);
|
||||
if (ret) {
|
||||
dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(20);
|
||||
ret = hub_port_status(hub, port, &portstatus, &portchange);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_RESET)
|
||||
clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_BH_RESET)
|
||||
clear_port_feature(hub->hdev, port,
|
||||
USB_PORT_FEAT_C_BH_PORT_RESET);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_LINK_STATE)
|
||||
clear_port_feature(hub->hdev, port,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if a port is power on */
|
||||
static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if (portstatus & USB_SS_PORT_STAT_POWER)
|
||||
ret = 1;
|
||||
} else {
|
||||
if (portstatus & USB_PORT_STAT_POWER)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \
|
||||
USB_PORT_STAT_SUSPEND)
|
||||
#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION)
|
||||
/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
|
||||
static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if ((portstatus & USB_PORT_STAT_LINK_STATE)
|
||||
== USB_SS_PORT_LS_U3)
|
||||
ret = 1;
|
||||
} else {
|
||||
if (portstatus & USB_PORT_STAT_SUSPEND)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Determine whether the device on a port is ready for a normal resume,
|
||||
* is ready for a reset-resume, or should be disconnected.
|
||||
|
@ -2174,7 +2230,9 @@ static int check_port_resume_type(struct usb_device *udev,
|
|||
int status, unsigned portchange, unsigned portstatus)
|
||||
{
|
||||
/* Is the device still present? */
|
||||
if (status || (portstatus & MASK_BITS) != WANT_BITS) {
|
||||
if (status || port_is_suspended(hub, portstatus) ||
|
||||
!port_is_power_on(hub, portstatus) ||
|
||||
!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
if (status >= 0)
|
||||
status = -ENODEV;
|
||||
}
|
||||
|
@ -2285,14 +2343,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
}
|
||||
|
||||
/* see 7.1.7.6 */
|
||||
/* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0
|
||||
* external hub.
|
||||
* FIXME: this is a temporary workaround to make the system able
|
||||
* to suspend/resume.
|
||||
*/
|
||||
if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev))
|
||||
status = clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_POWER);
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
status = set_port_feature(hub->hdev,
|
||||
port1 | (USB_SS_PORT_LS_U3 << 3),
|
||||
USB_PORT_FEAT_LINK_STATE);
|
||||
else
|
||||
status = set_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
|
@ -2439,7 +2493,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
/* Skip the initial Clear-Suspend step for a remote wakeup */
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
|
||||
if (status == 0 && !port_is_suspended(hub, portstatus))
|
||||
goto SuspendCleared;
|
||||
|
||||
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
|
||||
|
@ -2447,8 +2501,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
set_bit(port1, hub->busy_bits);
|
||||
|
||||
/* see 7.1.7.7; affects power usage, but not budgeting */
|
||||
status = clear_port_feature(hub->hdev,
|
||||
port1, USB_PORT_FEAT_SUSPEND);
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
status = set_port_feature(hub->hdev,
|
||||
port1 | (USB_SS_PORT_LS_U0 << 3),
|
||||
USB_PORT_FEAT_LINK_STATE);
|
||||
else
|
||||
status = clear_port_feature(hub->hdev,
|
||||
port1, USB_PORT_FEAT_SUSPEND);
|
||||
if (status) {
|
||||
dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
|
||||
port1, status);
|
||||
|
@ -2470,9 +2529,15 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
SuspendCleared:
|
||||
if (status == 0) {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if (portchange & USB_PORT_STAT_C_LINK_STATE)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
} else {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(port1, hub->busy_bits);
|
||||
|
@ -3147,7 +3212,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
|
||||
/* maybe switch power back on (e.g. root hub was reset) */
|
||||
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
|
||||
&& !(portstatus & USB_PORT_STAT_POWER))
|
||||
&& !port_is_power_on(hub, portstatus))
|
||||
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
|
||||
|
||||
if (portstatus & USB_PORT_STAT_ENABLE)
|
||||
|
@ -3490,6 +3555,16 @@ static void hub_events(void)
|
|||
USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
|
||||
}
|
||||
|
||||
/* Warm reset a USB3 protocol port if it's in
|
||||
* SS.Inactive state.
|
||||
*/
|
||||
if (hub_is_superspeed(hub->hdev) &&
|
||||
(portstatus & USB_PORT_STAT_LINK_STATE)
|
||||
== USB_SS_PORT_LS_SS_INACTIVE) {
|
||||
dev_dbg(hub_dev, "warm reset port %d\n", i);
|
||||
hub_port_warm_reset(hub, i);
|
||||
}
|
||||
|
||||
if (connect_change)
|
||||
hub_port_connect_change(hub, i,
|
||||
portstatus, portchange);
|
||||
|
|
|
@ -842,22 +842,19 @@ const struct attribute_group *usb_interface_groups[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
int usb_create_sysfs_intf_files(struct usb_interface *intf)
|
||||
void usb_create_sysfs_intf_files(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
int retval;
|
||||
|
||||
if (intf->sysfs_files_created || intf->unregistering)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (alt->string == NULL &&
|
||||
!(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
alt->string = usb_cache_string(udev, alt->desc.iInterface);
|
||||
if (alt->string)
|
||||
retval = device_create_file(&intf->dev, &dev_attr_interface);
|
||||
if (alt->string && device_create_file(&intf->dev, &dev_attr_interface))
|
||||
; /* We don't actually care if the function fails. */
|
||||
intf->sysfs_files_created = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
|
||||
|
|
|
@ -953,8 +953,7 @@ static int usb_bus_notify(struct notifier_block *nb, unsigned long action,
|
|||
if (dev->type == &usb_device_type)
|
||||
(void) usb_create_sysfs_dev_files(to_usb_device(dev));
|
||||
else if (dev->type == &usb_if_device_type)
|
||||
(void) usb_create_sysfs_intf_files(
|
||||
to_usb_interface(dev));
|
||||
usb_create_sysfs_intf_files(to_usb_interface(dev));
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_DEL_DEVICE:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
extern int usb_create_sysfs_dev_files(struct usb_device *dev);
|
||||
extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
|
||||
extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern void usb_create_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern int usb_create_ep_devs(struct device *parent,
|
||||
struct usb_host_endpoint *endpoint,
|
||||
|
|
|
@ -102,6 +102,9 @@ static struct kgdb_io kgdbdbgp_io_ops;
|
|||
#define dbgp_kgdb_mode (0)
|
||||
#endif
|
||||
|
||||
/* Local version of HC_LENGTH macro as ehci struct is not available here */
|
||||
#define EARLY_HC_LENGTH(p) (0x00ff & (p)) /* bits 7 : 0 */
|
||||
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
|
@ -892,7 +895,7 @@ int __init early_dbgp_init(char *s)
|
|||
dbgp_printk("ehci_bar: %p\n", ehci_bar);
|
||||
|
||||
ehci_caps = ehci_bar;
|
||||
ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
|
||||
ehci_regs = ehci_bar + EARLY_HC_LENGTH(readl(&ehci_caps->hc_capbase));
|
||||
ehci_debug = ehci_bar + offset;
|
||||
ehci_dev.bus = bus;
|
||||
ehci_dev.slot = slot;
|
||||
|
|
|
@ -260,6 +260,24 @@ config USB_R8A66597
|
|||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_RENESAS_USBHS
|
||||
boolean "Renesas USBHS"
|
||||
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.
|
||||
platform is able to configure endpoint (pipe) style
|
||||
|
||||
Say "y" to enable the gadget specific portion of the USBHS driver.
|
||||
|
||||
|
||||
config USB_RENESAS_USBHS_UDC
|
||||
tristate
|
||||
depends on USB_GADGET_RENESAS_USBHS
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA27X
|
||||
boolean "PXA 27x"
|
||||
depends on ARCH_PXA && (PXA27x || PXA3xx)
|
||||
|
@ -338,6 +356,23 @@ config USB_S3C2410_DEBUG
|
|||
boolean "S3C2410 udc debug messages"
|
||||
depends on USB_GADGET_S3C2410
|
||||
|
||||
config USB_GADGET_S3C_HSUDC
|
||||
boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
|
||||
depends on ARCH_S3C2410
|
||||
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
|
||||
8 endpoints, as well as endpoint zero.
|
||||
|
||||
This driver has been tested on S3C2416 and S3C2450 processors.
|
||||
|
||||
config USB_S3C_HSUDC
|
||||
tristate
|
||||
depends on USB_GADGET_S3C_HSUDC
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA_U2O
|
||||
boolean "PXA9xx Processor USB2.0 controller"
|
||||
select USB_GADGET_DUALSPEED
|
||||
|
|
|
@ -22,6 +22,7 @@ obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
|||
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
|
||||
obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
|
||||
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
|
||||
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
|
||||
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
|
||||
obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
|
||||
|
|
|
@ -1767,7 +1767,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* newer chips have more FIFO memory than rm9200 */
|
||||
if (cpu_is_at91sam9260()) {
|
||||
if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
udc->ep[4].maxpacket = 512;
|
||||
|
|
|
@ -310,7 +310,7 @@ static int hw_device_reset(struct ci13xxx *udc)
|
|||
udc->udc_driver->notify_event(udc,
|
||||
CI13XXX_CONTROLLER_RESET_EVENT);
|
||||
|
||||
if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING)
|
||||
if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
|
||||
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
|
||||
|
||||
/* USBMODE should be configured step by step */
|
||||
|
@ -1634,8 +1634,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
|
|||
gadget_for_each_ep(ep, gadget) {
|
||||
usb_ep_disable(ep);
|
||||
}
|
||||
usb_ep_disable(&udc->ep0out.ep);
|
||||
usb_ep_disable(&udc->ep0in.ep);
|
||||
|
||||
if (udc->status != NULL) {
|
||||
usb_ep_free_request(&udc->ep0in.ep, udc->status);
|
||||
|
@ -1678,18 +1676,10 @@ __acquires(udc->lock)
|
|||
if (retval)
|
||||
goto done;
|
||||
|
||||
retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
|
||||
if (retval)
|
||||
goto done;
|
||||
udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
|
||||
if (udc->status == NULL)
|
||||
retval = -ENOMEM;
|
||||
|
||||
retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
|
||||
if (!retval) {
|
||||
udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
|
||||
if (udc->status == NULL) {
|
||||
usb_ep_disable(&udc->ep0out.ep);
|
||||
retval = -ENOMEM;
|
||||
}
|
||||
}
|
||||
spin_lock(udc->lock);
|
||||
|
||||
done:
|
||||
|
@ -1843,7 +1833,8 @@ __releases(mEp->lock)
|
|||
__acquires(mEp->lock)
|
||||
{
|
||||
struct ci13xxx_req *mReq, *mReqTemp;
|
||||
int retval;
|
||||
struct ci13xxx_ep *mEpTemp = mEp;
|
||||
int uninitialized_var(retval);
|
||||
|
||||
trace("%p", mEp);
|
||||
|
||||
|
@ -1859,12 +1850,15 @@ __acquires(mEp->lock)
|
|||
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
|
||||
if (mReq->req.complete != NULL) {
|
||||
spin_unlock(mEp->lock);
|
||||
mReq->req.complete(&mEp->ep, &mReq->req);
|
||||
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
|
||||
mReq->req.length)
|
||||
mEpTemp = &_udc->ep0in;
|
||||
mReq->req.complete(&mEpTemp->ep, &mReq->req);
|
||||
spin_lock(mEp->lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == EBUSY)
|
||||
if (retval == -EBUSY)
|
||||
retval = 0;
|
||||
if (retval < 0)
|
||||
dbg_event(_usb_addr(mEp), "DONE", retval);
|
||||
|
@ -1894,7 +1888,7 @@ __acquires(udc->lock)
|
|||
|
||||
for (i = 0; i < hw_ep_max; i++) {
|
||||
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
|
||||
int type, num, err = -EINVAL;
|
||||
int type, num, dir, err = -EINVAL;
|
||||
struct usb_ctrlrequest req;
|
||||
|
||||
if (mEp->desc == NULL)
|
||||
|
@ -1952,7 +1946,10 @@ __acquires(udc->lock)
|
|||
if (req.wLength != 0)
|
||||
break;
|
||||
num = le16_to_cpu(req.wIndex);
|
||||
dir = num & USB_ENDPOINT_DIR_MASK;
|
||||
num &= USB_ENDPOINT_NUMBER_MASK;
|
||||
if (dir) /* TX */
|
||||
num += hw_ep_max/2;
|
||||
if (!udc->ci13xxx_ep[num].wedge) {
|
||||
spin_unlock(udc->lock);
|
||||
err = usb_ep_clear_halt(
|
||||
|
@ -2001,7 +1998,10 @@ __acquires(udc->lock)
|
|||
if (req.wLength != 0)
|
||||
break;
|
||||
num = le16_to_cpu(req.wIndex);
|
||||
dir = num & USB_ENDPOINT_DIR_MASK;
|
||||
num &= USB_ENDPOINT_NUMBER_MASK;
|
||||
if (dir) /* TX */
|
||||
num += hw_ep_max/2;
|
||||
|
||||
spin_unlock(udc->lock);
|
||||
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
|
||||
|
@ -2110,7 +2110,12 @@ static int ep_enable(struct usb_ep *ep,
|
|||
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
|
||||
mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
|
||||
|
||||
retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
|
||||
/*
|
||||
* Enable endpoints in the HW other than ep0 as ep0
|
||||
* is always enabled
|
||||
*/
|
||||
if (mEp->num)
|
||||
retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
|
||||
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
return retval;
|
||||
|
@ -2242,11 +2247,15 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
|
||||
!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
warn("endpoint ctrl %X nuked", _usb_addr(mEp));
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
|
||||
if (req->length)
|
||||
mEp = (_udc->ep0_dir == RX) ?
|
||||
&_udc->ep0out : &_udc->ep0in;
|
||||
if (!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
warn("endpoint ctrl %X nuked", _usb_addr(mEp));
|
||||
}
|
||||
}
|
||||
|
||||
/* first nuke then test link, e.g. previous status has not sent */
|
||||
|
@ -2497,6 +2506,15 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
|
||||
|
||||
if (udc->transceiver)
|
||||
return otg_set_power(udc->transceiver, mA);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device operations part of the API to the USB controller hardware,
|
||||
* which don't involve endpoints (or i/o)
|
||||
|
@ -2505,6 +2523,7 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
|
|||
static const struct usb_gadget_ops usb_gadget_ops = {
|
||||
.vbus_session = ci13xxx_vbus_session,
|
||||
.wakeup = ci13xxx_wakeup,
|
||||
.vbus_draw = ci13xxx_vbus_draw,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2595,6 +2614,14 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
}
|
||||
if (retval)
|
||||
goto done;
|
||||
spin_unlock_irqrestore(udc->lock, flags);
|
||||
retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
|
||||
if (retval)
|
||||
return retval;
|
||||
spin_lock_irqsave(udc->lock, flags);
|
||||
|
||||
udc->gadget.ep0 = &udc->ep0in.ep;
|
||||
/* bind gadget */
|
||||
|
|
|
@ -461,12 +461,23 @@ static int set_config(struct usb_composite_dev *cdev,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -895,6 +906,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
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))
|
||||
|
@ -958,7 +977,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
}
|
||||
|
||||
/* respond with data transfer before status phase? */
|
||||
if (value >= 0) {
|
||||
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);
|
||||
|
@ -967,6 +986,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
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:
|
||||
|
@ -1289,3 +1312,40 @@ void usb_composite_unregister(struct usb_composite_driver *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);
|
||||
}
|
||||
|
||||
|
|
|
@ -261,8 +261,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
|
|||
o_desc.wMaxPacketSize =
|
||||
__constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
|
||||
|
||||
dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress & 0x7f;
|
||||
dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress & 0x7f;
|
||||
dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
|
||||
dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial->in = dbgp.i_ep;
|
||||
|
@ -312,6 +312,7 @@ static int __init dbgp_bind(struct usb_gadget *gadget)
|
|||
|
||||
dbgp.req->length = DBGP_REQ_EP0_LEN;
|
||||
gadget->ep0->driver_data = gadget;
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
|
||||
|
@ -350,9 +351,9 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
u8 request = ctrl->bRequest;
|
||||
u16 value = le16_to_cpu(ctrl->wValue);
|
||||
u16 length = le16_to_cpu(ctrl->wLength);
|
||||
int err = 0;
|
||||
void *data;
|
||||
u16 len;
|
||||
int err = -EOPNOTSUPP;
|
||||
void *data = NULL;
|
||||
u16 len = 0;
|
||||
|
||||
gadget->ep0->driver_data = gadget;
|
||||
|
||||
|
@ -371,10 +372,9 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
default:
|
||||
goto fail;
|
||||
}
|
||||
err = 0;
|
||||
} else if (request == USB_REQ_SET_FEATURE &&
|
||||
value == USB_DEVICE_DEBUG_MODE) {
|
||||
len = 0;
|
||||
data = NULL;
|
||||
dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
|
||||
#ifdef CONFIG_USB_G_DBGP_PRINTK
|
||||
err = dbgp_enable_ep();
|
||||
|
|
|
@ -892,10 +892,11 @@ static int dummy_udc_probe (struct platform_device *pdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
platform_set_drvdata (pdev, dum);
|
||||
rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
|
||||
if (rc < 0)
|
||||
device_unregister (&dum->gadget.dev);
|
||||
else
|
||||
platform_set_drvdata(pdev, dum);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1995,11 +1996,29 @@ static int __init init (void)
|
|||
retval = platform_device_add(the_hcd_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_hcd;
|
||||
if (!the_controller) {
|
||||
/*
|
||||
* The hcd was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_add_udc;
|
||||
}
|
||||
retval = platform_device_add(the_udc_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_udc;
|
||||
if (!platform_get_drvdata(the_udc_pdev)) {
|
||||
/*
|
||||
* The udc was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_probe_udc;
|
||||
}
|
||||
return retval;
|
||||
|
||||
err_probe_udc:
|
||||
platform_device_del(the_udc_pdev);
|
||||
err_add_udc:
|
||||
platform_device_del(the_hcd_pdev);
|
||||
err_add_hcd:
|
||||
|
|
|
@ -177,7 +177,7 @@ static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
|
|||
};
|
||||
|
||||
/* Standard ISO OUT Endpoint Descriptor */
|
||||
static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor as_out_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
|
|
|
@ -347,6 +347,7 @@ struct fsg_operations {
|
|||
/* 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;
|
||||
|
||||
|
@ -613,6 +614,11 @@ static int fsg_setup(struct usb_function *f,
|
|||
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 USB_BULK_RESET_REQUEST:
|
||||
|
@ -1584,37 +1590,6 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int pad_with_zeros(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill;
|
||||
u32 nkeep = bh->inreq->length;
|
||||
u32 nsend;
|
||||
int rc;
|
||||
|
||||
bh->state = BUF_STATE_EMPTY; /* For the first iteration */
|
||||
fsg->common->usb_amount_left = nkeep + fsg->common->residue;
|
||||
while (fsg->common->usb_amount_left > 0) {
|
||||
|
||||
/* Wait for the next buffer to be free */
|
||||
while (bh->state != BUF_STATE_EMPTY) {
|
||||
rc = sleep_thread(fsg->common);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN);
|
||||
memset(bh->buf + nkeep, 0, nsend - nkeep);
|
||||
bh->inreq->length = nsend;
|
||||
bh->inreq->zero = 0;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
bh = fsg->common->next_buffhd_to_fill = bh->next;
|
||||
fsg->common->usb_amount_left -= nsend;
|
||||
nkeep = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int throw_away_data(struct fsg_common *common)
|
||||
{
|
||||
struct fsg_buffhd *bh;
|
||||
|
@ -1702,6 +1677,10 @@ static int finish_reply(struct fsg_common *common)
|
|||
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;
|
||||
|
@ -1710,24 +1689,19 @@ static int finish_reply(struct fsg_common *common)
|
|||
common->next_buffhd_to_fill = bh->next;
|
||||
|
||||
/*
|
||||
* For Bulk-only, if we're allowed to stall then send the
|
||||
* short packet and halt the bulk-in endpoint. If we can't
|
||||
* stall, pad out the remaining data with 0's.
|
||||
* 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 if (common->can_stall) {
|
||||
} else {
|
||||
bh->inreq->zero = 1;
|
||||
if (!start_in_transfer(common, bh))
|
||||
/* Don't know what to do if
|
||||
* common->fsg is NULL */
|
||||
rc = -EIO;
|
||||
common->next_buffhd_to_fill = bh->next;
|
||||
if (common->fsg)
|
||||
if (common->can_stall)
|
||||
rc = halt_bulk_in_endpoint(common->fsg);
|
||||
} else if (fsg_is_set(common)) {
|
||||
rc = pad_with_zeros(common->fsg);
|
||||
} else {
|
||||
/* Don't know what to do if common->fsg is NULL */
|
||||
rc = -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1910,7 +1884,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
common->lun, lun);
|
||||
|
||||
/* Check the LUN */
|
||||
if (common->lun >= 0 && common->lun < common->nluns) {
|
||||
if (common->lun < common->nluns) {
|
||||
curlun = &common->luns[common->lun];
|
||||
common->curlun = curlun;
|
||||
if (common->cmnd[0] != REQUEST_SENSE) {
|
||||
|
@ -2468,7 +2442,7 @@ 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 0;
|
||||
return USB_GADGET_DELAYED_STATUS;
|
||||
}
|
||||
|
||||
static void fsg_disable(struct usb_function *f)
|
||||
|
@ -2604,6 +2578,8 @@ static void handle_exception(struct fsg_common *common)
|
|||
|
||||
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:
|
||||
|
@ -2774,6 +2750,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||
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) {
|
||||
|
@ -2800,6 +2777,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||
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;
|
||||
|
|
|
@ -420,8 +420,7 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
*/
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_SEND_ENCAPSULATED_COMMAND:
|
||||
if (w_length > req->length || w_value
|
||||
|| w_index != rndis->ctrl_id)
|
||||
if (w_value || w_index != rndis->ctrl_id)
|
||||
goto invalid;
|
||||
/* read the request; process it later */
|
||||
value = w_length;
|
||||
|
|
|
@ -1947,37 +1947,6 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int pad_with_zeros(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
|
||||
u32 nkeep = bh->inreq->length;
|
||||
u32 nsend;
|
||||
int rc;
|
||||
|
||||
bh->state = BUF_STATE_EMPTY; // For the first iteration
|
||||
fsg->usb_amount_left = nkeep + fsg->residue;
|
||||
while (fsg->usb_amount_left > 0) {
|
||||
|
||||
/* Wait for the next buffer to be free */
|
||||
while (bh->state != BUF_STATE_EMPTY) {
|
||||
rc = sleep_thread(fsg);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen);
|
||||
memset(bh->buf + nkeep, 0, nsend - nkeep);
|
||||
bh->inreq->length = nsend;
|
||||
bh->inreq->zero = 0;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
bh = fsg->next_buffhd_to_fill = bh->next;
|
||||
fsg->usb_amount_left -= nsend;
|
||||
nkeep = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int throw_away_data(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh;
|
||||
|
@ -2082,18 +2051,20 @@ static int finish_reply(struct fsg_dev *fsg)
|
|||
}
|
||||
}
|
||||
|
||||
/* For Bulk-only, if we're allowed to stall then send the
|
||||
* short packet and halt the bulk-in endpoint. If we can't
|
||||
* stall, pad out the remaining data with 0's. */
|
||||
/*
|
||||
* 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 {
|
||||
if (mod_data.can_stall) {
|
||||
bh->inreq->zero = 1;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
fsg->next_buffhd_to_fill = bh->next;
|
||||
bh->inreq->zero = 1;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
fsg->next_buffhd_to_fill = bh->next;
|
||||
if (mod_data.can_stall)
|
||||
rc = halt_bulk_in_endpoint(fsg);
|
||||
} else
|
||||
rc = pad_with_zeros(fsg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2314,7 +2285,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
|||
fsg->lun = lun; // Use LUN from the command
|
||||
|
||||
/* Check the LUN */
|
||||
if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
|
||||
if (fsg->lun < fsg->nluns) {
|
||||
fsg->curlun = curlun = &fsg->luns[fsg->lun];
|
||||
if (fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
|
|
|
@ -207,7 +207,7 @@ struct qe_frame{
|
|||
|
||||
/* Frame status field */
|
||||
/* Receive side */
|
||||
#define FRAME_OK 0x00000000 /* Frame tranmitted or received OK */
|
||||
#define FRAME_OK 0x00000000 /* Frame transmitted or received OK */
|
||||
#define FRAME_ERROR 0x80000000 /* Error occurred on frame */
|
||||
#define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */
|
||||
#define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Li Yang <leoli@freescale.com>
|
||||
* Jiang Bo <tanya.jiang@freescale.com>
|
||||
*
|
||||
* Description:
|
||||
* Freescale high-speed USB SOC DR module device controller driver.
|
||||
* This can be found on MPC8349E/MPC8313E cpus.
|
||||
* This can be found on MPC8349E/MPC8313E/MPC5121E cpus.
|
||||
* The driver is previously named as mpc_udc. Based on bare board
|
||||
* code from Dave Liu and Shlomi Gridish.
|
||||
*
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include <asm/system.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "fsl_usb2_udc.h"
|
||||
|
||||
|
@ -77,12 +79,64 @@ fsl_ep0_desc = {
|
|||
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
#define fsl_readl(addr) in_le32(addr)
|
||||
#define fsl_writel(val32, addr) out_le32(addr, val32)
|
||||
#else
|
||||
/*
|
||||
* On some SoCs, the USB controller registers can be big or little endian,
|
||||
* depending on the version of the chip. In order to be able to run the
|
||||
* same kernel binary on 2 different versions of an SoC, the BE/LE decision
|
||||
* must be made at run time. _fsl_readl and fsl_writel are pointers to the
|
||||
* BE or LE readl() and writel() functions, and fsl_readl() and fsl_writel()
|
||||
* call through those pointers. Platform code for SoCs that have BE USB
|
||||
* registers should set pdata->big_endian_mmio flag.
|
||||
*
|
||||
* This also applies to controller-to-cpu accessors for the USB descriptors,
|
||||
* since their endianness is also SoC dependant. Platform code for SoCs that
|
||||
* have BE USB descriptors should set pdata->big_endian_desc flag.
|
||||
*/
|
||||
static u32 _fsl_readl_be(const unsigned __iomem *p)
|
||||
{
|
||||
return in_be32(p);
|
||||
}
|
||||
|
||||
static u32 _fsl_readl_le(const unsigned __iomem *p)
|
||||
{
|
||||
return in_le32(p);
|
||||
}
|
||||
|
||||
static void _fsl_writel_be(u32 v, unsigned __iomem *p)
|
||||
{
|
||||
out_be32(p, v);
|
||||
}
|
||||
|
||||
static void _fsl_writel_le(u32 v, unsigned __iomem *p)
|
||||
{
|
||||
out_le32(p, v);
|
||||
}
|
||||
|
||||
static u32 (*_fsl_readl)(const unsigned __iomem *p);
|
||||
static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
|
||||
|
||||
#define fsl_readl(p) (*_fsl_readl)((p))
|
||||
#define fsl_writel(v, p) (*_fsl_writel)((v), (p))
|
||||
|
||||
static inline u32 cpu_to_hc32(const u32 x)
|
||||
{
|
||||
return udc_controller->pdata->big_endian_desc
|
||||
? (__force u32)cpu_to_be32(x)
|
||||
: (__force u32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpu(const u32 x)
|
||||
{
|
||||
return udc_controller->pdata->big_endian_desc
|
||||
? be32_to_cpu((__force __be32)x)
|
||||
: le32_to_cpu((__force __le32)x);
|
||||
}
|
||||
#else /* !CONFIG_PPC32 */
|
||||
#define fsl_readl(addr) readl(addr)
|
||||
#define fsl_writel(val32, addr) writel(val32, addr)
|
||||
#endif
|
||||
#define cpu_to_hc32(x) cpu_to_le32(x)
|
||||
#define hc32_to_cpu(x) le32_to_cpu(x)
|
||||
#endif /* CONFIG_PPC32 */
|
||||
|
||||
/********************************************************************
|
||||
* Internal Used Function
|
||||
|
@ -177,7 +231,8 @@ static void nuke(struct fsl_ep *ep, int status)
|
|||
|
||||
static int dr_controller_setup(struct fsl_udc *udc)
|
||||
{
|
||||
unsigned int tmp, portctrl;
|
||||
unsigned int tmp, portctrl, ep_num;
|
||||
unsigned int max_no_of_ep;
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
unsigned int ctrl;
|
||||
#endif
|
||||
|
@ -226,9 +281,12 @@ static int dr_controller_setup(struct fsl_udc *udc)
|
|||
|
||||
/* Set the controller as device mode */
|
||||
tmp = fsl_readl(&dr_regs->usbmode);
|
||||
tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
|
||||
tmp |= USB_MODE_CTRL_MODE_DEVICE;
|
||||
/* Disable Setup Lockout */
|
||||
tmp |= USB_MODE_SETUP_LOCK_OFF;
|
||||
if (udc->pdata->es)
|
||||
tmp |= USB_MODE_ES;
|
||||
fsl_writel(tmp, &dr_regs->usbmode);
|
||||
|
||||
/* Clear the setup status */
|
||||
|
@ -242,22 +300,34 @@ static int dr_controller_setup(struct fsl_udc *udc)
|
|||
udc->ep_qh, (int)tmp,
|
||||
fsl_readl(&dr_regs->endpointlistaddr));
|
||||
|
||||
max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
|
||||
for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
|
||||
tmp = fsl_readl(&dr_regs->endptctrl[ep_num]);
|
||||
tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
|
||||
tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
|
||||
| (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
|
||||
fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
|
||||
}
|
||||
/* Config control enable i/o output, cpu endian register */
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
ctrl = __raw_readl(&usb_sys_regs->control);
|
||||
ctrl |= USB_CTRL_IOENB;
|
||||
__raw_writel(ctrl, &usb_sys_regs->control);
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
ctrl = __raw_readl(&usb_sys_regs->control);
|
||||
ctrl |= USB_CTRL_IOENB;
|
||||
__raw_writel(ctrl, &usb_sys_regs->control);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
/* Turn on cache snooping hardware, since some PowerPC platforms
|
||||
* wholly rely on hardware to deal with cache coherent. */
|
||||
|
||||
/* Setup Snooping for all the 4GB space */
|
||||
tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop1);
|
||||
tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop2);
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
/* Setup Snooping for all the 4GB space */
|
||||
tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop1);
|
||||
tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -293,6 +363,19 @@ static void dr_controller_stop(struct fsl_udc *udc)
|
|||
{
|
||||
unsigned int tmp;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
/* if we're in OTG mode, and the Host is currently using the port,
|
||||
* stop now and don't rip the controller out from under the
|
||||
* ehci driver
|
||||
*/
|
||||
if (udc->gadget.is_otg) {
|
||||
if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
|
||||
pr_debug("udc: Leaving early\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable all INTR */
|
||||
fsl_writel(0, &dr_regs->usbintr);
|
||||
|
||||
|
@ -318,12 +401,14 @@ static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
|
|||
if (ep_num)
|
||||
tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
|
||||
tmp_epctrl |= EPCTRL_TX_ENABLE;
|
||||
tmp_epctrl &= ~EPCTRL_TX_TYPE;
|
||||
tmp_epctrl |= ((unsigned int)(ep_type)
|
||||
<< EPCTRL_TX_EP_TYPE_SHIFT);
|
||||
} else {
|
||||
if (ep_num)
|
||||
tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
|
||||
tmp_epctrl |= EPCTRL_RX_ENABLE;
|
||||
tmp_epctrl &= ~EPCTRL_RX_TYPE;
|
||||
tmp_epctrl |= ((unsigned int)(ep_type)
|
||||
<< EPCTRL_RX_EP_TYPE_SHIFT);
|
||||
}
|
||||
|
@ -409,7 +494,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
|
|||
if (zlt)
|
||||
tmp |= EP_QUEUE_HEAD_ZLT_SEL;
|
||||
|
||||
p_QH->max_pkt_length = cpu_to_le32(tmp);
|
||||
p_QH->max_pkt_length = cpu_to_hc32(tmp);
|
||||
p_QH->next_dtd_ptr = 1;
|
||||
p_QH->size_ioc_int_sts = 0;
|
||||
}
|
||||
|
@ -546,10 +631,13 @@ static int fsl_ep_disable(struct usb_ep *_ep)
|
|||
/* disable ep on controller */
|
||||
ep_num = ep_index(ep);
|
||||
epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
|
||||
if (ep_is_in(ep))
|
||||
epctrl &= ~EPCTRL_TX_ENABLE;
|
||||
else
|
||||
epctrl &= ~EPCTRL_RX_ENABLE;
|
||||
if (ep_is_in(ep)) {
|
||||
epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
|
||||
epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
|
||||
} else {
|
||||
epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
|
||||
epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
|
||||
}
|
||||
fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
|
||||
|
||||
udc = (struct fsl_udc *)ep->udc;
|
||||
|
@ -616,7 +704,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
|
|||
struct fsl_req *lastreq;
|
||||
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
|
||||
lastreq->tail->next_td_ptr =
|
||||
cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
|
||||
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
|
||||
/* Read prime bit, if 1 goto done */
|
||||
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
|
||||
goto out;
|
||||
|
@ -641,10 +729,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
|
|||
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
dQH->next_dtd_ptr = cpu_to_le32(temp);
|
||||
dQH->next_dtd_ptr = cpu_to_hc32(temp);
|
||||
|
||||
/* Clear active and halt bit */
|
||||
temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
|
||||
temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
|
||||
| EP_QUEUE_HEAD_STATUS_HALT));
|
||||
dQH->size_ioc_int_sts &= temp;
|
||||
|
||||
|
@ -682,17 +770,17 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
|
|||
|
||||
dtd->td_dma = *dma;
|
||||
/* Clear reserved field */
|
||||
swap_temp = cpu_to_le32(dtd->size_ioc_sts);
|
||||
swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
|
||||
swap_temp &= ~DTD_RESERVED_FIELDS;
|
||||
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
|
||||
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
|
||||
|
||||
/* Init all of buffer page pointers */
|
||||
swap_temp = (u32) (req->req.dma + req->req.actual);
|
||||
dtd->buff_ptr0 = cpu_to_le32(swap_temp);
|
||||
dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
|
||||
dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
|
||||
dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
|
||||
dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
|
||||
dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
|
||||
dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
|
||||
dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
|
||||
dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
|
||||
dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
|
||||
|
||||
req->req.actual += *length;
|
||||
|
||||
|
@ -716,7 +804,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
|
|||
if (*is_last && !req->req.no_interrupt)
|
||||
swap_temp |= DTD_IOC;
|
||||
|
||||
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
|
||||
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
|
||||
|
||||
mb();
|
||||
|
||||
|
@ -743,7 +831,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
|
|||
is_first = 0;
|
||||
req->head = dtd;
|
||||
} else {
|
||||
last_dtd->next_td_ptr = cpu_to_le32(dma);
|
||||
last_dtd->next_td_ptr = cpu_to_hc32(dma);
|
||||
last_dtd->next_td_virt = dtd;
|
||||
}
|
||||
last_dtd = dtd;
|
||||
|
@ -751,7 +839,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
|
|||
req->dtd_count++;
|
||||
} while (!is_last);
|
||||
|
||||
dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
|
||||
dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
|
||||
|
||||
req->tail = dtd;
|
||||
|
||||
|
@ -962,6 +1050,36 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int fsl_ep_fifo_status(struct usb_ep *_ep)
|
||||
{
|
||||
struct fsl_ep *ep;
|
||||
struct fsl_udc *udc;
|
||||
int size = 0;
|
||||
u32 bitmask;
|
||||
struct ep_queue_head *d_qh;
|
||||
|
||||
ep = container_of(_ep, struct fsl_ep, ep);
|
||||
if (!_ep || (!ep->desc && ep_index(ep) != 0))
|
||||
return -ENODEV;
|
||||
|
||||
udc = (struct fsl_udc *)ep->udc;
|
||||
|
||||
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
|
||||
|
||||
bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
|
||||
(1 << (ep_index(ep)));
|
||||
|
||||
if (fsl_readl(&dr_regs->endptstatus) & bitmask)
|
||||
size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
|
||||
>> DTD_LENGTH_BIT_POS;
|
||||
|
||||
pr_debug("%s %u\n", __func__, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void fsl_ep_fifo_flush(struct usb_ep *_ep)
|
||||
{
|
||||
struct fsl_ep *ep;
|
||||
|
@ -1014,6 +1132,7 @@ static struct usb_ep_ops fsl_ep_ops = {
|
|||
.dequeue = fsl_ep_dequeue,
|
||||
|
||||
.set_halt = fsl_ep_set_halt,
|
||||
.fifo_status = fsl_ep_fifo_status,
|
||||
.fifo_flush = fsl_ep_fifo_flush, /* flush fifo */
|
||||
};
|
||||
|
||||
|
@ -1228,6 +1347,10 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
|
|||
req = udc->status_req;
|
||||
/* Fill in the reqest structure */
|
||||
*((u16 *) req->req.buf) = cpu_to_le16(tmp);
|
||||
|
||||
/* flush cache for the req buffer */
|
||||
flush_dcache_range((u32)req->req.buf, (u32)req->req.buf + 8);
|
||||
|
||||
req->ep = ep;
|
||||
req->req.length = 2;
|
||||
req->req.status = -EINPROGRESS;
|
||||
|
@ -1280,6 +1403,7 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
/* Status phase from udc */
|
||||
{
|
||||
int rc = -EOPNOTSUPP;
|
||||
u16 ptc = 0;
|
||||
|
||||
if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
|
||||
== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
|
||||
|
@ -1301,17 +1425,19 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
| USB_TYPE_STANDARD)) {
|
||||
/* Note: The driver has not include OTG support yet.
|
||||
* This will be set when OTG support is added */
|
||||
if (!gadget_is_otg(&udc->gadget))
|
||||
break;
|
||||
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
|
||||
udc->gadget.b_hnp_enable = 1;
|
||||
else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
|
||||
udc->gadget.a_hnp_support = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_ALT_HNP_SUPPORT)
|
||||
udc->gadget.a_alt_hnp_support = 1;
|
||||
else
|
||||
break;
|
||||
if (wValue == USB_DEVICE_TEST_MODE)
|
||||
ptc = wIndex >> 8;
|
||||
else if (gadget_is_otg(&udc->gadget)) {
|
||||
if (setup->bRequest ==
|
||||
USB_DEVICE_B_HNP_ENABLE)
|
||||
udc->gadget.b_hnp_enable = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_HNP_SUPPORT)
|
||||
udc->gadget.a_hnp_support = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_ALT_HNP_SUPPORT)
|
||||
udc->gadget.a_alt_hnp_support = 1;
|
||||
}
|
||||
rc = 0;
|
||||
} else
|
||||
break;
|
||||
|
@ -1320,6 +1446,15 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
if (ep0_prime_status(udc, EP_DIR_IN))
|
||||
ep0stall(udc);
|
||||
}
|
||||
if (ptc) {
|
||||
u32 tmp;
|
||||
|
||||
mdelay(10);
|
||||
tmp = fsl_readl(&dr_regs->portsc1) | (ptc << 16);
|
||||
fsl_writel(tmp, &dr_regs->portsc1);
|
||||
printk(KERN_INFO "udc: switch to test mode %d.\n", ptc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1394,6 +1529,7 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
|
|||
{
|
||||
u32 temp;
|
||||
struct ep_queue_head *qh;
|
||||
struct fsl_usb2_platform_data *pdata = udc->pdata;
|
||||
|
||||
qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
|
||||
|
||||
|
@ -1408,7 +1544,16 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
|
|||
fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
|
||||
|
||||
/* Copy the setup packet to local buffer */
|
||||
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
|
||||
if (pdata->le_setup_buf) {
|
||||
u32 *p = (u32 *)buffer_ptr;
|
||||
u32 *s = (u32 *)qh->setup_buffer;
|
||||
|
||||
/* Convert little endian setup buffer to CPU endian */
|
||||
*p++ = le32_to_cpu(*s++);
|
||||
*p = le32_to_cpu(*s);
|
||||
} else {
|
||||
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
|
||||
}
|
||||
} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
|
||||
|
||||
/* Clear Setup Tripwire */
|
||||
|
@ -1432,19 +1577,19 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
|||
actual = curr_req->req.length;
|
||||
|
||||
for (j = 0; j < curr_req->dtd_count; j++) {
|
||||
remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
|
||||
remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
|
||||
& DTD_PACKET_SIZE)
|
||||
>> DTD_LENGTH_BIT_POS;
|
||||
actual -= remaining_length;
|
||||
|
||||
if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
|
||||
DTD_ERROR_MASK)) {
|
||||
errors = hc32_to_cpu(curr_td->size_ioc_sts);
|
||||
if (errors & DTD_ERROR_MASK) {
|
||||
if (errors & DTD_STATUS_HALTED) {
|
||||
ERR("dTD error %08x QH=%d\n", errors, pipe);
|
||||
/* Clear the errors and Halt condition */
|
||||
tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
|
||||
tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
|
||||
tmp &= ~errors;
|
||||
curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
|
||||
curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp);
|
||||
status = -EPIPE;
|
||||
/* FIXME: continue with next queued TD? */
|
||||
|
||||
|
@ -1462,7 +1607,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
|||
ERR("Unknown error has occurred (0x%x)!\n",
|
||||
errors);
|
||||
|
||||
} else if (le32_to_cpu(curr_td->size_ioc_sts)
|
||||
} else if (hc32_to_cpu(curr_td->size_ioc_sts)
|
||||
& DTD_STATUS_ACTIVE) {
|
||||
VDBG("Request not complete");
|
||||
status = REQ_UNCOMPLETE;
|
||||
|
@ -1551,6 +1696,9 @@ static void port_change_irq(struct fsl_udc *udc)
|
|||
{
|
||||
u32 speed;
|
||||
|
||||
if (udc->bus_reset)
|
||||
udc->bus_reset = 0;
|
||||
|
||||
/* Bus resetting is finished */
|
||||
if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
|
||||
/* Get the speed */
|
||||
|
@ -1658,6 +1806,8 @@ static void reset_irq(struct fsl_udc *udc)
|
|||
|
||||
if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
|
||||
VDBG("Bus reset");
|
||||
/* Bus is reseting */
|
||||
udc->bus_reset = 1;
|
||||
/* Reset all the queues, include XD, dTD, EP queue
|
||||
* head and TR Queue */
|
||||
reset_queues(udc);
|
||||
|
@ -1735,6 +1885,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
|
|||
|
||||
/* Reset Received */
|
||||
if (irq_src & USB_STS_RESET) {
|
||||
VDBG("reset int");
|
||||
reset_irq(udc);
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1792,11 +1943,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
|
||||
dr_controller_run(udc_controller);
|
||||
udc_controller->usb_state = USB_STATE_ATTACHED;
|
||||
udc_controller->ep0_state = WAIT_FOR_SETUP;
|
||||
udc_controller->ep0_dir = 0;
|
||||
if (udc_controller->transceiver) {
|
||||
/* Suspend the controller until OTG enable it */
|
||||
udc_controller->stopped = 1;
|
||||
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (udc_controller->transceiver) {
|
||||
retval = otg_set_peripheral(udc_controller->transceiver,
|
||||
&udc_controller->gadget);
|
||||
if (retval < 0) {
|
||||
ERR("can't bind to transceiver\n");
|
||||
driver->unbind(&udc_controller->gadget);
|
||||
udc_controller->gadget.dev.driver = 0;
|
||||
udc_controller->driver = 0;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Enable DR IRQ reg and set USBCMD reg Run bit */
|
||||
dr_controller_run(udc_controller);
|
||||
udc_controller->usb_state = USB_STATE_ATTACHED;
|
||||
udc_controller->ep0_state = WAIT_FOR_SETUP;
|
||||
udc_controller->ep0_dir = 0;
|
||||
}
|
||||
printk(KERN_INFO "%s: bind to driver %s\n",
|
||||
udc_controller->gadget.name, driver->driver.name);
|
||||
|
||||
|
@ -2044,16 +2214,18 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
|
|||
next += t;
|
||||
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
tmp_reg = usb_sys_regs->snoop1;
|
||||
t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
tmp_reg = usb_sys_regs->snoop1;
|
||||
t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
|
||||
tmp_reg = usb_sys_regs->control;
|
||||
t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
|
||||
tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
tmp_reg = usb_sys_regs->control;
|
||||
t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
|
||||
tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
|
||||
|
@ -2233,6 +2405,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
|
|||
*/
|
||||
static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct resource *res;
|
||||
int ret = -ENODEV;
|
||||
unsigned int i;
|
||||
|
@ -2249,20 +2422,35 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
udc_controller->pdata = pdata;
|
||||
spin_lock_init(&udc_controller->lock);
|
||||
udc_controller->stopped = 1;
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
udc_controller->transceiver = otg_get_transceiver();
|
||||
if (!udc_controller->transceiver) {
|
||||
ERR("Can't find OTG driver!\n");
|
||||
ret = -ENODEV;
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENXIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
driver_name)) {
|
||||
ERR("request mem region for %s failed\n", pdev->name);
|
||||
ret = -EBUSY;
|
||||
goto err_kfree;
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
driver_name)) {
|
||||
ERR("request mem region for %s failed\n", pdev->name);
|
||||
ret = -EBUSY;
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
|
||||
dr_regs = ioremap(res->start, resource_size(res));
|
||||
|
@ -2271,9 +2459,29 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
goto err_release_mem_region;
|
||||
}
|
||||
|
||||
pdata->regs = (void *)dr_regs;
|
||||
|
||||
/*
|
||||
* do platform specific init: check the clock, grab/config pins, etc.
|
||||
*/
|
||||
if (pdata->init && pdata->init(pdev)) {
|
||||
ret = -ENODEV;
|
||||
goto err_iounmap_noclk;
|
||||
}
|
||||
|
||||
/* Set accessors only after pdata->init() ! */
|
||||
if (pdata->big_endian_mmio) {
|
||||
_fsl_readl = _fsl_readl_be;
|
||||
_fsl_writel = _fsl_writel_be;
|
||||
} else {
|
||||
_fsl_readl = _fsl_readl_le;
|
||||
_fsl_writel = _fsl_writel_le;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
usb_sys_regs = (struct usb_sys_interface *)
|
||||
((u32)dr_regs + USB_DR_SYS_OFFSET);
|
||||
if (pdata->have_sysif_regs)
|
||||
usb_sys_regs = (struct usb_sys_interface *)
|
||||
((u32)dr_regs + USB_DR_SYS_OFFSET);
|
||||
#endif
|
||||
|
||||
/* Initialize USB clocks */
|
||||
|
@ -2313,9 +2521,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
goto err_free_irq;
|
||||
}
|
||||
|
||||
/* initialize usb hw reg except for regs for EP,
|
||||
* leave usbintr reg untouched */
|
||||
dr_controller_setup(udc_controller);
|
||||
if (!udc_controller->transceiver) {
|
||||
/* initialize usb hw reg except for regs for EP,
|
||||
* leave usbintr reg untouched */
|
||||
dr_controller_setup(udc_controller);
|
||||
}
|
||||
|
||||
fsl_udc_clk_finalize(pdev);
|
||||
|
||||
|
@ -2335,6 +2545,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
if (udc_controller->transceiver)
|
||||
udc_controller->gadget.is_otg = 1;
|
||||
|
||||
/* setup QH and epctrl for ep0 */
|
||||
ep0_setup(udc_controller);
|
||||
|
||||
|
@ -2373,11 +2586,14 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
err_free_irq:
|
||||
free_irq(udc_controller->irq, udc_controller);
|
||||
err_iounmap:
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
fsl_udc_clk_release();
|
||||
err_iounmap_noclk:
|
||||
iounmap(dr_regs);
|
||||
err_release_mem_region:
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
err_kfree:
|
||||
kfree(udc_controller);
|
||||
udc_controller = NULL;
|
||||
|
@ -2390,6 +2606,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
static int __exit fsl_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
DECLARE_COMPLETION(done);
|
||||
|
||||
|
@ -2410,12 +2627,20 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
|
|||
dma_pool_destroy(udc_controller->td_pool);
|
||||
free_irq(udc_controller->irq, udc_controller);
|
||||
iounmap(dr_regs);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
/* free udc --wait for the release() finished */
|
||||
wait_for_completion(&done);
|
||||
|
||||
/*
|
||||
* do platform specific un-initialization:
|
||||
* release iomux pins, etc.
|
||||
*/
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2446,6 +2671,62 @@ static int fsl_udc_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct fsl_udc *udc = udc_controller;
|
||||
u32 mode, usbcmd;
|
||||
|
||||
mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
|
||||
|
||||
pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped);
|
||||
|
||||
/*
|
||||
* If the controller is already stopped, then this must be a
|
||||
* PM suspend. Remember this fact, so that we will leave the
|
||||
* controller stopped at PM resume time.
|
||||
*/
|
||||
if (udc->stopped) {
|
||||
pr_debug("gadget already stopped, leaving early\n");
|
||||
udc->already_stopped = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mode != USB_MODE_CTRL_MODE_DEVICE) {
|
||||
pr_debug("gadget not in device mode, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* stop the controller */
|
||||
usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
|
||||
fsl_writel(usbcmd, &dr_regs->usbcmd);
|
||||
|
||||
udc->stopped = 1;
|
||||
|
||||
pr_info("USB Gadget suspended\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_udc_otg_resume(struct device *dev)
|
||||
{
|
||||
pr_debug("%s(): stopped %d already_stopped %d\n", __func__,
|
||||
udc_controller->stopped, udc_controller->already_stopped);
|
||||
|
||||
/*
|
||||
* If the controller was stopped at suspend time, then
|
||||
* don't resume it now.
|
||||
*/
|
||||
if (udc_controller->already_stopped) {
|
||||
udc_controller->already_stopped = 0;
|
||||
pr_debug("gadget was already stopped, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_info("USB Gadget resume\n");
|
||||
|
||||
return fsl_udc_resume(NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Register entry point for the peripheral controller driver
|
||||
--------------------------------------------------------------------------*/
|
||||
|
@ -2458,6 +2739,9 @@ static struct platform_driver udc_driver = {
|
|||
.driver = {
|
||||
.name = (char *)driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
/* udc suspend/resume called from OTG driver */
|
||||
.suspend = fsl_udc_otg_suspend,
|
||||
.resume = fsl_udc_otg_resume,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -275,7 +275,9 @@ struct usb_sys_interface {
|
|||
#define USB_MODE_CTRL_MODE_IDLE 0x00000000
|
||||
#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
|
||||
#define USB_MODE_CTRL_MODE_HOST 0x00000003
|
||||
#define USB_MODE_CTRL_MODE_MASK 0x00000003
|
||||
#define USB_MODE_CTRL_MODE_RSV 0x00000001
|
||||
#define USB_MODE_ES 0x00000004 /* Endian Select */
|
||||
#define USB_MODE_SETUP_LOCK_OFF 0x00000008
|
||||
#define USB_MODE_STREAM_DISABLE 0x00000010
|
||||
/* Endpoint Flush Register */
|
||||
|
@ -461,6 +463,7 @@ struct fsl_ep {
|
|||
struct fsl_udc {
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct completion *done; /* to make sure release() is done */
|
||||
struct fsl_ep *eps;
|
||||
unsigned int max_ep;
|
||||
|
@ -473,6 +476,8 @@ struct fsl_udc {
|
|||
unsigned vbus_active:1;
|
||||
unsigned stopped:1;
|
||||
unsigned remote_wakeup:1;
|
||||
unsigned already_stopped:1;
|
||||
unsigned big_endian_desc:1;
|
||||
|
||||
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
|
||||
struct fsl_req *status_req; /* ep0 status request */
|
||||
|
@ -483,6 +488,7 @@ struct fsl_udc {
|
|||
dma_addr_t ep_qh_dma; /* dma address of QH */
|
||||
|
||||
u32 max_pipes; /* Device max pipes */
|
||||
u32 bus_reset; /* Device is bus resetting */
|
||||
u32 resume_state; /* USB state to resume */
|
||||
u32 usb_state; /* USB current state */
|
||||
u32 ep0_state; /* Endpoint zero state */
|
||||
|
|
|
@ -136,6 +136,12 @@
|
|||
#define gadget_is_s3c_hsotg(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_S3C_HSUDC
|
||||
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_s3c_hsudc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_EG20T
|
||||
#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
|
||||
#else
|
||||
|
@ -148,6 +154,12 @@
|
|||
#define gadget_is_ci13xxx_msm(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
|
||||
#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_renesas_usbhs(g) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* usb_gadget_controller_number - support bcdDevice id convention
|
||||
* @gadget: the controller being driven
|
||||
|
@ -207,6 +219,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *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;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
|
|
@ -1189,6 +1189,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
else if (gadget->a_alt_hnp_support)
|
||||
DBG(dev, "HNP needs a different root port\n");
|
||||
value = printer_set_config(dev, wValue);
|
||||
if (!value)
|
||||
value = set_interface(dev, PRINTER_INTERFACE);
|
||||
break;
|
||||
case USB_REQ_GET_CONFIGURATION:
|
||||
if (ctrl->bRequestType != USB_DIR_IN)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* linux/drivers/usb/gadget/s3c-hsotg.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
|
@ -613,11 +616,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
|
|||
maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
|
||||
} else {
|
||||
maxsize = 64+64;
|
||||
if (hs_ep->dir_in) {
|
||||
if (hs_ep->dir_in)
|
||||
maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
|
||||
} else {
|
||||
else
|
||||
maxpkt = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* we made the constant loading easier above by using +1 */
|
||||
|
@ -679,6 +681,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
|||
__func__, readl(hsotg->regs + epctrl_reg), index,
|
||||
hs_ep->dir_in ? "in" : "out");
|
||||
|
||||
/* If endpoint is stalled, we will restart request later */
|
||||
ctrl = readl(hsotg->regs + epctrl_reg);
|
||||
|
||||
if (ctrl & S3C_DxEPCTL_Stall) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
|
||||
return;
|
||||
}
|
||||
|
||||
length = ureq->length - ureq->actual;
|
||||
|
||||
if (0)
|
||||
|
@ -731,18 +741,6 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
|||
/* write size / packets */
|
||||
writel(epsize, hsotg->regs + epsize_reg);
|
||||
|
||||
ctrl = readl(hsotg->regs + epctrl_reg);
|
||||
|
||||
if (ctrl & S3C_DxEPCTL_Stall) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
|
||||
|
||||
/* not sure what we can do here, if it is EP0 then we should
|
||||
* get this cleared once the endpoint has transmitted the
|
||||
* STALL packet, otherwise it needs to be cleared by the
|
||||
* host.
|
||||
*/
|
||||
}
|
||||
|
||||
if (using_dma(hsotg)) {
|
||||
unsigned int dma_reg;
|
||||
|
||||
|
@ -1047,6 +1045,20 @@ static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg,
|
|||
|
||||
static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value);
|
||||
|
||||
/**
|
||||
* get_ep_head - return the first request on the endpoint
|
||||
* @hs_ep: The controller endpoint to get
|
||||
*
|
||||
* Get the first request on the endpoint.
|
||||
*/
|
||||
static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
|
||||
{
|
||||
if (list_empty(&hs_ep->queue))
|
||||
return NULL;
|
||||
|
||||
return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
|
||||
* @hsotg: The device state
|
||||
|
@ -1055,8 +1067,12 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value);
|
|||
static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
|
||||
struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
|
||||
struct s3c_hsotg_req *hs_req;
|
||||
bool restart;
|
||||
bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
|
||||
struct s3c_hsotg_ep *ep;
|
||||
int ret;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
|
||||
__func__, set ? "SET" : "CLEAR");
|
||||
|
@ -1072,6 +1088,36 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
|
|||
switch (le16_to_cpu(ctrl->wValue)) {
|
||||
case USB_ENDPOINT_HALT:
|
||||
s3c_hsotg_ep_sethalt(&ep->ep, set);
|
||||
|
||||
ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev,
|
||||
"%s: failed to send reply\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!set) {
|
||||
/*
|
||||
* If we have request in progress,
|
||||
* then complete it
|
||||
*/
|
||||
if (ep->req) {
|
||||
hs_req = ep->req;
|
||||
ep->req = NULL;
|
||||
list_del_init(&hs_req->queue);
|
||||
hs_req->req.complete(&ep->ep,
|
||||
&hs_req->req);
|
||||
}
|
||||
|
||||
/* If we have pending request, then start it */
|
||||
restart = !list_empty(&ep->queue);
|
||||
if (restart) {
|
||||
hs_req = get_ep_head(ep);
|
||||
s3c_hsotg_start_req(hsotg, ep,
|
||||
hs_req, false);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1148,14 +1194,6 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
|
|||
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (!ep0->dir_in) {
|
||||
/* need to generate zlp in reply or take data */
|
||||
/* todo - deal with any data we might be sent? */
|
||||
ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* the request is either unhandlable, or is not formatted correctly
|
||||
* so respond with a STALL for the status stage to indicate failure.
|
||||
*/
|
||||
|
@ -1246,20 +1284,6 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_ep_head - return the first request on the endpoint
|
||||
* @hs_ep: The controller endpoint to get
|
||||
*
|
||||
* Get the first request on the endpoint.
|
||||
*/
|
||||
static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
|
||||
{
|
||||
if (list_empty(&hs_ep->queue))
|
||||
return NULL;
|
||||
|
||||
return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_complete_request - complete a request given to us
|
||||
* @hsotg: The device state.
|
||||
|
@ -1683,6 +1707,37 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
|
|||
dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_txfifo_flush - flush Tx FIFO
|
||||
* @hsotg: The driver state
|
||||
* @idx: The index for the endpoint (0..15)
|
||||
*/
|
||||
static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
|
||||
{
|
||||
int timeout;
|
||||
int val;
|
||||
|
||||
writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh,
|
||||
hsotg->regs + S3C_GRSTCTL);
|
||||
|
||||
/* wait until the fifo is flushed */
|
||||
timeout = 100;
|
||||
|
||||
while (1) {
|
||||
val = readl(hsotg->regs + S3C_GRSTCTL);
|
||||
|
||||
if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0)
|
||||
break;
|
||||
|
||||
if (--timeout == 0) {
|
||||
dev_err(hsotg->dev,
|
||||
"%s: timeout flushing fifo (GRSTCTL=%08x)\n",
|
||||
__func__, val);
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_trytx - check to see if anything needs transmitting
|
||||
|
@ -1775,10 +1830,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
|
||||
u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
|
||||
u32 ints;
|
||||
u32 clear = 0;
|
||||
|
||||
ints = readl(hsotg->regs + epint_reg);
|
||||
|
||||
/* Clear endpoint interrupts */
|
||||
writel(ints, hsotg->regs + epint_reg);
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
|
||||
__func__, idx, dir_in ? "in" : "out", ints);
|
||||
|
||||
|
@ -1801,19 +1858,28 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
|
||||
s3c_hsotg_handle_outdone(hsotg, idx, false);
|
||||
}
|
||||
|
||||
clear |= S3C_DxEPINT_XferCompl;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_EPDisbld) {
|
||||
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
|
||||
clear |= S3C_DxEPINT_EPDisbld;
|
||||
|
||||
if (dir_in) {
|
||||
int epctl = readl(hsotg->regs + epctl_reg);
|
||||
|
||||
s3c_hsotg_txfifo_flush(hsotg, idx);
|
||||
|
||||
if ((epctl & S3C_DxEPCTL_Stall) &&
|
||||
(epctl & S3C_DxEPCTL_EPType_Bulk)) {
|
||||
int dctl = readl(hsotg->regs + S3C_DCTL);
|
||||
|
||||
dctl |= S3C_DCTL_CGNPInNAK;
|
||||
writel(dctl, hsotg->regs + S3C_DCTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_AHBErr) {
|
||||
if (ints & S3C_DxEPINT_AHBErr)
|
||||
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
|
||||
clear |= S3C_DxEPINT_AHBErr;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */
|
||||
dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__);
|
||||
|
@ -1829,14 +1895,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
else
|
||||
s3c_hsotg_handle_outdone(hsotg, 0, true);
|
||||
}
|
||||
|
||||
clear |= S3C_DxEPINT_Setup;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_Back2BackSetup) {
|
||||
if (ints & S3C_DxEPINT_Back2BackSetup)
|
||||
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
|
||||
clear |= S3C_DxEPINT_Back2BackSetup;
|
||||
}
|
||||
|
||||
if (dir_in) {
|
||||
/* not sure if this is important, but we'll clear it anyway
|
||||
|
@ -1844,14 +1906,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
|
||||
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
|
||||
__func__, idx);
|
||||
clear |= S3C_DIEPMSK_INTknTXFEmpMsk;
|
||||
}
|
||||
|
||||
/* this probably means something bad is happening */
|
||||
if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
|
||||
__func__, idx);
|
||||
clear |= S3C_DIEPMSK_INTknEPMisMsk;
|
||||
}
|
||||
|
||||
/* FIFO has space or is empty (see GAHBCFG) */
|
||||
|
@ -1860,11 +1920,8 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
|
||||
__func__, idx);
|
||||
s3c_hsotg_trytx(hsotg, hs_ep);
|
||||
clear |= S3C_DIEPMSK_TxFIFOEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
writel(clear, hsotg->regs + epint_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2056,7 +2113,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
|
||||
|
||||
writel(otgint, hsotg->regs + S3C_GOTGINT);
|
||||
writel(S3C_GINTSTS_OTGInt, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_DisconnInt) {
|
||||
|
@ -2072,8 +2128,9 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_EnumDone) {
|
||||
s3c_hsotg_irq_enumdone(hsotg);
|
||||
writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_irq_enumdone(hsotg);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_ConIDStsChng) {
|
||||
|
@ -2101,10 +2158,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
if (daint_in & 1)
|
||||
s3c_hsotg_epint(hsotg, ep, 1);
|
||||
}
|
||||
|
||||
writel(daint, hsotg->regs + S3C_DAINT);
|
||||
writel(gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt),
|
||||
hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_USBRst) {
|
||||
|
@ -2112,6 +2165,8 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
|
||||
readl(hsotg->regs + S3C_GNPTXSTS));
|
||||
|
||||
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
|
||||
|
||||
/* it seems after a reset we can end up with a situation
|
||||
|
@ -2123,8 +2178,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
s3c_hsotg_init_fifo(hsotg);
|
||||
|
||||
s3c_hsotg_enqueue_setup(hsotg);
|
||||
|
||||
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
/* check both FIFOs */
|
||||
|
@ -2138,8 +2191,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
|
||||
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
|
||||
s3c_hsotg_irq_fifoempty(hsotg, false);
|
||||
|
||||
writel(S3C_GINTSTS_NPTxFEmp, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_PTxFEmp) {
|
||||
|
@ -2149,8 +2200,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
|
||||
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
|
||||
s3c_hsotg_irq_fifoempty(hsotg, true);
|
||||
|
||||
writel(S3C_GINTSTS_PTxFEmp, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_RxFLvl) {
|
||||
|
@ -2159,7 +2208,6 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
* set. */
|
||||
|
||||
s3c_hsotg_handle_rx(hsotg);
|
||||
writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_ModeMis) {
|
||||
|
@ -2193,19 +2241,17 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
|||
if (gintsts & S3C_GINTSTS_GOUTNakEff) {
|
||||
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
|
||||
writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
|
||||
writel(S3C_GINTSTS_GOUTNakEff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_GINNakEff) {
|
||||
dev_info(hsotg->dev, "GINNakEff triggered\n");
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
|
||||
writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
|
||||
writel(S3C_GINTSTS_GINNakEff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
}
|
||||
|
||||
/* if we've had fifo events, we should try and go around the
|
||||
|
@ -2403,11 +2449,6 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
|||
|
||||
dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
|
||||
|
||||
if (hs_req == hs_ep->req) {
|
||||
dev_dbg(hs->dev, "%s: already in progress\n", __func__);
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
|
||||
if (!on_list(hs_ep, hs_req)) {
|
||||
|
@ -2429,6 +2470,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
unsigned long irqflags;
|
||||
u32 epreg;
|
||||
u32 epctl;
|
||||
u32 xfertype;
|
||||
|
||||
dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
|
||||
|
||||
|
@ -2439,10 +2481,17 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
epreg = S3C_DIEPCTL(index);
|
||||
epctl = readl(hs->regs + epreg);
|
||||
|
||||
if (value)
|
||||
epctl |= S3C_DxEPCTL_Stall;
|
||||
else
|
||||
if (value) {
|
||||
epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK;
|
||||
if (epctl & S3C_DxEPCTL_EPEna)
|
||||
epctl |= S3C_DxEPCTL_EPDis;
|
||||
} else {
|
||||
epctl &= ~S3C_DxEPCTL_Stall;
|
||||
xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
|
||||
if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
|
||||
xfertype == S3C_DxEPCTL_EPType_Intterupt)
|
||||
epctl |= S3C_DxEPCTL_SetD0PID;
|
||||
}
|
||||
|
||||
writel(epctl, hs->regs + epreg);
|
||||
|
||||
|
@ -2451,8 +2500,13 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
|
||||
if (value)
|
||||
epctl |= S3C_DxEPCTL_Stall;
|
||||
else
|
||||
else {
|
||||
epctl &= ~S3C_DxEPCTL_Stall;
|
||||
xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
|
||||
if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
|
||||
xfertype == S3C_DxEPCTL_EPType_Intterupt)
|
||||
epctl |= S3C_DxEPCTL_SetD0PID;
|
||||
}
|
||||
|
||||
writel(epctl, hs->regs + epreg);
|
||||
|
||||
|
@ -2491,9 +2545,9 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
|||
timeout = 1000;
|
||||
do {
|
||||
grstctl = readl(hsotg->regs + S3C_GRSTCTL);
|
||||
} while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
|
||||
} while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
|
||||
|
||||
if (!(grstctl & S3C_GRSTCTL_CSftRst)) {
|
||||
if (grstctl & S3C_GRSTCTL_CSftRst) {
|
||||
dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2510,13 +2564,10 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (grstctl & S3C_GRSTCTL_CSftRst)
|
||||
continue;
|
||||
|
||||
if (!(grstctl & S3C_GRSTCTL_AHBIdle))
|
||||
continue;
|
||||
|
||||
break; /* reset done */
|
||||
break; /* reset done */
|
||||
}
|
||||
|
||||
dev_dbg(hsotg->dev, "reset successful\n");
|
||||
|
@ -2588,6 +2639,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
|
||||
writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG);
|
||||
|
||||
/* Clear any pending OTG interrupts */
|
||||
writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
|
||||
|
||||
/* Clear any pending interrupts */
|
||||
writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
|
||||
S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
|
||||
S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
|
||||
|
@ -3261,7 +3318,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
|||
hsotg->clk = clk_get(&pdev->dev, "otg");
|
||||
if (IS_ERR(hsotg->clk)) {
|
||||
dev_err(dev, "cannot get otg clock\n");
|
||||
ret = -EINVAL;
|
||||
ret = PTR_ERR(hsotg->clk);
|
||||
goto err_mem;
|
||||
}
|
||||
|
||||
|
|
1349
drivers/usb/gadget/s3c-hsudc.c
Normal file
1349
drivers/usb/gadget/s3c-hsudc.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -708,13 +708,14 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t rc = count;
|
||||
ssize_t rc;
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
unsigned long ro;
|
||||
unsigned ro;
|
||||
|
||||
if (strict_strtoul(buf, 2, &ro))
|
||||
return -EINVAL;
|
||||
rc = kstrtouint(buf, 2, &ro);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Allow the write-enable status to change only while the
|
||||
|
@ -728,6 +729,7 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
|||
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;
|
||||
|
@ -738,10 +740,12 @@ static ssize_t fsg_store_nofua(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
unsigned long nofua;
|
||||
unsigned nofua;
|
||||
int ret;
|
||||
|
||||
if (strict_strtoul(buf, 2, &nofua))
|
||||
return -EINVAL;
|
||||
ret = kstrtouint(buf, 2, &nofua);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Sync data when switching from async mode to sync */
|
||||
if (!nofua && curlun->nofua)
|
||||
|
|
|
@ -106,13 +106,13 @@ config USB_EHCI_BIG_ENDIAN_MMIO
|
|||
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
|
||||
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
|
||||
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
|
||||
PMC_MSP)
|
||||
PMC_MSP || SPARC_LEON)
|
||||
default y
|
||||
|
||||
config USB_EHCI_BIG_ENDIAN_DESC
|
||||
bool
|
||||
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
|
||||
PPC_MPC512x || PMC_MSP)
|
||||
PPC_MPC512x || PMC_MSP || SPARC_LEON)
|
||||
default y
|
||||
|
||||
config XPS_USB_HCD_XILINX
|
||||
|
@ -188,6 +188,12 @@ config USB_EHCI_SH
|
|||
Enables support for the on-chip EHCI controller on the SuperH.
|
||||
If you use the PCI EHCI controller, this option is not necessary.
|
||||
|
||||
config USB_EHCI_S5P
|
||||
boolean "S5P EHCI support"
|
||||
depends on USB_EHCI_HCD && PLAT_S5P
|
||||
help
|
||||
Enable support for the S5P SOC's on-chip EHCI controller.
|
||||
|
||||
config USB_W90X900_EHCI
|
||||
bool "W90X900(W90P910) EHCI support"
|
||||
depends on USB_EHCI_HCD && ARCH_W90X900
|
||||
|
@ -202,6 +208,15 @@ config USB_CNS3XXX_EHCI
|
|||
It is needed for high-speed (480Mbit/sec) USB 2.0 device
|
||||
support.
|
||||
|
||||
config USB_EHCI_ATH79
|
||||
bool "EHCI support for AR7XXX/AR9XXX SoCs"
|
||||
depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X)
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
default y
|
||||
---help---
|
||||
Enables support for the built-in EHCI controller present
|
||||
on the Atheros AR7XXX/AR9XXX SoCs.
|
||||
|
||||
config USB_OXU210HP_HCD
|
||||
tristate "OXU210HP HCD support"
|
||||
depends on USB
|
||||
|
@ -287,6 +302,14 @@ config USB_OHCI_HCD_OMAP3
|
|||
Enables support for the on-chip OHCI controller on
|
||||
OMAP3 and later chips.
|
||||
|
||||
config USB_OHCI_ATH79
|
||||
bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs"
|
||||
depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
|
||||
default y
|
||||
help
|
||||
Enables support for the built-in OHCI controller present on the
|
||||
Atheros AR71XX/AR7240 SoCs.
|
||||
|
||||
config USB_OHCI_HCD_PPC_SOC
|
||||
bool "OHCI support for on-chip PPC USB controller"
|
||||
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
|
||||
|
@ -373,7 +396,7 @@ config USB_OHCI_LITTLE_ENDIAN
|
|||
|
||||
config USB_UHCI_HCD
|
||||
tristate "UHCI HCD (most Intel and VIA) support"
|
||||
depends on USB && PCI
|
||||
depends on USB && (PCI || SPARC_LEON)
|
||||
---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
|
||||
|
@ -382,11 +405,27 @@ config USB_UHCI_HCD
|
|||
with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
|
||||
i810, i820) conform to this standard. Also all VIA PCI chipsets
|
||||
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
|
||||
133). If unsure, say Y.
|
||||
133) and LEON/GRLIB SoCs with the GRUSBHC controller.
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called uhci-hcd.
|
||||
|
||||
config USB_UHCI_SUPPORT_NON_PCI_HC
|
||||
bool
|
||||
depends on USB_UHCI_HCD
|
||||
default y if SPARC_LEON
|
||||
|
||||
config USB_UHCI_BIG_ENDIAN_MMIO
|
||||
bool
|
||||
depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
|
||||
default y
|
||||
|
||||
config USB_UHCI_BIG_ENDIAN_DESC
|
||||
bool
|
||||
depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
|
||||
default y
|
||||
|
||||
config USB_FHCI_HCD
|
||||
tristate "Freescale QE USB Host Controller support"
|
||||
depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE
|
||||
|
@ -444,6 +483,16 @@ config USB_SL811_HCD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called sl811-hcd.
|
||||
|
||||
config USB_SL811_HCD_ISO
|
||||
bool "partial ISO support"
|
||||
depends on USB_SL811_HCD
|
||||
help
|
||||
The driver doesn't support iso_frame_desc (yet), but for some simple
|
||||
devices that just queue one ISO frame per URB, then ISO transfers
|
||||
"should" work using the normal urb status fields.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config USB_SL811_CS
|
||||
tristate "CF/PCMCIA support for SL811HS HCD"
|
||||
depends on USB_SL811_HCD && PCMCIA
|
||||
|
|
202
drivers/usb/host/ehci-ath79.c
Normal file
202
drivers/usb/host/ehci-ath79.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
* Copyright (C) 2007 Atheros Communications, Inc.
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
|
||||
enum {
|
||||
EHCI_ATH79_IP_V1 = 0,
|
||||
EHCI_ATH79_IP_V2,
|
||||
};
|
||||
|
||||
static const struct platform_device_id ehci_ath79_id_table[] = {
|
||||
{
|
||||
.name = "ar71xx-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V1,
|
||||
},
|
||||
{
|
||||
.name = "ar724x-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V2,
|
||||
},
|
||||
{
|
||||
.name = "ar913x-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V2,
|
||||
},
|
||||
{
|
||||
/* terminating entry */
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
|
||||
|
||||
static int ehci_ath79_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct platform_device *pdev = to_platform_device(hcd->self.controller);
|
||||
const struct platform_device_id *id;
|
||||
int hclength;
|
||||
int ret;
|
||||
|
||||
id = platform_get_device_id(pdev);
|
||||
if (!id) {
|
||||
dev_err(hcd->self.controller, "missing device id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
switch (id->driver_data) {
|
||||
case EHCI_ATH79_IP_V1:
|
||||
ehci->has_synopsys_hc_bug = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + hclength;
|
||||
break;
|
||||
|
||||
case EHCI_ATH79_IP_V2:
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 + hclength;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ret = ehci_init(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_ath79_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Atheros built-in EHCI controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
.reset = ehci_ath79_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int ehci_ath79_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no IRQ specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no base address specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
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);
|
||||
if (!hcd->regs) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
ret = -EFAULT;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (ret)
|
||||
goto err_iounmap;
|
||||
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int ehci_ath79_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;
|
||||
}
|
||||
|
||||
static struct platform_driver ehci_ath79_driver = {
|
||||
.probe = ehci_ath79_probe,
|
||||
.remove = ehci_ath79_remove,
|
||||
.id_table = ehci_ath79_id_table,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ath79-ehci",
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
|
|
@ -56,7 +56,7 @@ static int ehci_atmel_setup(struct usb_hcd *hcd)
|
|||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
@ -175,7 +175,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
|
@ -215,10 +216,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
|||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
return 0;
|
||||
rc = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
@ -233,13 +231,13 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
|||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
au1xxx_stop_ehc();
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
// ... we'd only use it to handle clock skew
|
||||
|
||||
au1xxx_stop_ehc();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 0;
|
||||
|
|
|
@ -726,7 +726,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
|||
}
|
||||
|
||||
/* Capability Registers */
|
||||
i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
temp = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
|
|
|
@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
|
||||
pdata->regs = hcd->regs;
|
||||
|
||||
if (pdata->power_budget)
|
||||
hcd->power_budget = pdata->power_budget;
|
||||
|
||||
/*
|
||||
* do platform specific init: check the clock, grab/config pins, etc.
|
||||
*/
|
||||
|
@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->transceiver = otg_get_transceiver();
|
||||
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
|
||||
hcd, ehci, ehci->transceiver);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
retval = otg_set_host(ehci->transceiver,
|
||||
&ehci_to_hcd(ehci)->self);
|
||||
if (retval) {
|
||||
if (ehci->transceiver)
|
||||
put_device(ehci->transceiver->dev);
|
||||
goto err4;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "can't find transceiver\n");
|
||||
retval = -ENODEV;
|
||||
goto err4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
|
@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
|
|||
struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
otg_set_host(ehci->transceiver, NULL);
|
||||
put_device(ehci->transceiver->dev);
|
||||
}
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
|
@ -291,7 +324,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
@ -328,6 +361,149 @@ struct ehci_fsl {
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
#ifdef DEBUG
|
||||
u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
mode &= USBMODE_CM_MASK;
|
||||
tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d "
|
||||
"mode=%d usbcmd %08x\n", pdata->suspended,
|
||||
pdata->already_suspended, mode, tmp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the controller is already suspended, then this must be a
|
||||
* PM suspend. Remember this fact, so that we will leave the
|
||||
* controller suspended at PM resume time.
|
||||
*/
|
||||
if (pdata->suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "suspending...\n");
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
dev->power.power_state = PMSG_SUSPEND;
|
||||
|
||||
/* ignore non-host interrupts */
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* stop the controller */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp &= ~CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
/* save EHCI registers */
|
||||
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
|
||||
pdata->pm_command &= ~CMD_RUN;
|
||||
pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
|
||||
pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
|
||||
pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
|
||||
pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
|
||||
pdata->pm_configured_flag =
|
||||
ehci_readl(ehci, &ehci->regs->configured_flag);
|
||||
pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
pdata->pm_usbgenctrl = ehci_readl(ehci,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
|
||||
/* clear the W1C bits */
|
||||
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
|
||||
|
||||
pdata->suspended = 1;
|
||||
|
||||
/* clear PP to cut power to the port */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
tmp &= ~PORT_POWER;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d\n",
|
||||
pdata->suspended, pdata->already_suspended);
|
||||
|
||||
/*
|
||||
* If the controller was already suspended at suspend time,
|
||||
* then don't resume it now.
|
||||
*/
|
||||
if (pdata->already_suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pdata->suspended) {
|
||||
dev_dbg(dev, "not suspended, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdata->suspended = 0;
|
||||
|
||||
dev_dbg(dev, "resuming...\n");
|
||||
|
||||
/* set host mode */
|
||||
tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
|
||||
ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
|
||||
ehci_writel(ehci, pdata->pm_usbgenctrl,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
|
||||
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
|
||||
|
||||
/* restore EHCI registers */
|
||||
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
|
||||
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
|
||||
ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
|
||||
ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
|
||||
ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
|
||||
ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
|
||||
ehci_writel(ehci, pdata->pm_configured_flag,
|
||||
&ehci->regs->configured_flag);
|
||||
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
dev->power.power_state = PMSG_ON;
|
||||
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp |= CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PPC_MPC512x */
|
||||
|
||||
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
@ -341,6 +517,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
|
|||
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_suspend(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
|
||||
device_may_wakeup(dev));
|
||||
if (!fsl_deep_sleep())
|
||||
|
@ -357,6 +538,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
|
|||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_resume(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!fsl_deep_sleep())
|
||||
return 0;
|
||||
|
@ -391,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = {
|
|||
#define EHCI_FSL_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
u32 status;
|
||||
|
||||
if (!port)
|
||||
return -EINVAL;
|
||||
|
||||
port--;
|
||||
|
||||
/* start port reset before HNP protocol time out */
|
||||
status = readl(&ehci->regs->port_status[port]);
|
||||
if (!(status & PORT_CONNECT))
|
||||
return -ENODEV;
|
||||
|
||||
/* khubd will finish the reset later */
|
||||
if (ehci_is_TDI(ehci)) {
|
||||
writel(PORT_RESET |
|
||||
(status & ~(PORT_CSC | PORT_PEC | PORT_OCC)),
|
||||
&ehci->regs->port_status[port]);
|
||||
} else {
|
||||
writel(PORT_RESET, &ehci->regs->port_status[port]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ehci_start_port_reset NULL
|
||||
#endif /* CONFIG_USB_OTG */
|
||||
|
||||
|
||||
static const struct hc_driver ehci_fsl_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Freescale On-Chip EHCI Host Controller",
|
||||
|
@ -430,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
|
|||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.start_port_reset = ehci_start_port_reset,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#define PORT_PTS_SERIAL (3<<30)
|
||||
#define PORT_PTS_PTW (1<<28)
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
|
||||
#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
|
||||
#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
|
||||
|
||||
#define FSL_SOC_USB_USBGENCTRL 0x200
|
||||
#define USBGENCTRL_PPP (1 << 3)
|
||||
|
|
242
drivers/usb/host/ehci-grlib.c
Normal file
242
drivers/usb/host/ehci-grlib.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
|
||||
*
|
||||
* GRUSBHC is typically found on LEON/GRLIB SoCs
|
||||
*
|
||||
* (c) Jan Andersson <jan@gaisler.com>
|
||||
*
|
||||
* Based on ehci-ppc-of.c which is:
|
||||
* (c) Valentine Barshak <vbarshak@ru.mvista.com>
|
||||
* and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
|
||||
* and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_grlib_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
return ehci_reset(ehci);
|
||||
}
|
||||
|
||||
|
||||
static const struct hc_driver ehci_grlib_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "GRLIB GRUSBHC EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_grlib_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
#endif
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
|
||||
static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
|
||||
{
|
||||
struct device_node *dn = op->dev.of_node;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci = NULL;
|
||||
struct resource res;
|
||||
u32 hc_capbase;
|
||||
int irq;
|
||||
int rv;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
|
||||
|
||||
rv = of_address_to_resource(dn, 0, &res);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* usb_create_hcd requires dma_mask != NULL */
|
||||
op->dev.dma_mask = &op->dev.coherent_dma_mask;
|
||||
hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
|
||||
"GRUSBHC EHCI USB");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = res.start;
|
||||
hcd->rsrc_len = res.end - res.start + 1;
|
||||
|
||||
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__);
|
||||
rv = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
|
||||
rv = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
/* determine endianness of this implementation */
|
||||
hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
|
||||
if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
|
||||
ehci->big_endian_mmio = 1;
|
||||
ehci->big_endian_desc = 1;
|
||||
ehci->big_endian_capbase = 1;
|
||||
}
|
||||
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv)
|
||||
goto err_ehci;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static int ehci_hcd_grlib_remove(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
dev_set_drvdata(&op->dev, NULL);
|
||||
|
||||
dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ehci_hcd_grlib_shutdown(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id ehci_hcd_grlib_of_match[] = {
|
||||
{
|
||||
.name = "GAISLER_EHCI",
|
||||
},
|
||||
{
|
||||
.name = "01_026",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
|
||||
|
||||
|
||||
static struct platform_driver ehci_grlib_driver = {
|
||||
.probe = ehci_hcd_grlib_probe,
|
||||
.remove = ehci_hcd_grlib_remove,
|
||||
.shutdown = ehci_hcd_grlib_shutdown,
|
||||
.driver = {
|
||||
.name = "grlib-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ehci_hcd_grlib_of_match,
|
||||
},
|
||||
};
|
|
@ -739,7 +739,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
|||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
ehci->last_periodic_enable = ktime_get_real();
|
||||
|
||||
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci_info (ehci,
|
||||
"USB %x.%x started, EHCI %x.%02x%s\n",
|
||||
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
|
||||
|
@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||
goto dead;
|
||||
}
|
||||
|
||||
/* Shared IRQ? */
|
||||
masked_status = status & INTR_MASK;
|
||||
if (!masked_status) { /* irq sharing? */
|
||||
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||
spin_unlock(&ehci->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||
dead:
|
||||
ehci_reset(ehci);
|
||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||
usb_hc_died(hcd);
|
||||
/* generic layer kills/unlinks all urbs, then
|
||||
* uses ehci_stop to clean up the rest
|
||||
*/
|
||||
|
@ -1265,6 +1267,21 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER tegra_ehci_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_S5P
|
||||
#include "ehci-s5p.c"
|
||||
#define PLATFORM_DRIVER s5p_ehci_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_ATH79
|
||||
#include "ehci-ath79.c"
|
||||
#define PLATFORM_DRIVER ehci_ath79_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARC_LEON
|
||||
#include "ehci-grlib.c"
|
||||
#define PLATFORM_DRIVER ehci_grlib_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
|
||||
|
||||
|
@ -127,7 +128,7 @@ static int ehci_port_change(struct ehci_hcd *ehci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
bool suspending, bool do_wakeup)
|
||||
{
|
||||
int port;
|
||||
|
@ -801,6 +802,13 @@ static int ehci_hub_control (
|
|||
goto error;
|
||||
if (ehci->no_selective_suspend)
|
||||
break;
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if ((hcd->self.otg_port == (wIndex + 1))
|
||||
&& hcd->self.b_hnp_enable) {
|
||||
otg_start_hnp(ehci->transceiver);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (!(temp & PORT_SUSPEND))
|
||||
break;
|
||||
if ((temp & PORT_PE) == 0)
|
||||
|
|
|
@ -23,7 +23,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100
|
||||
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
|
|
@ -41,7 +41,7 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = USB_CAPLENGTH;
|
||||
ehci->regs = USB_CAPLENGTH +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* set up the PORTSCx register */
|
||||
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
|
||||
|
|
|
@ -151,7 +151,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
|||
/* we know this is the memory we want, no need to ioremap again */
|
||||
omap_ehci->caps = hcd->regs;
|
||||
omap_ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(readl(&omap_ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(omap_ehci, "reset");
|
||||
dbg_hcc_params(omap_ehci, "reset");
|
||||
|
|
|
@ -251,7 +251,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
|
|||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
|
|
@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
@ -83,7 +83,7 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
@ -29,7 +29,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
|||
ehci->big_endian_mmio = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
|
|
|
@ -826,6 +826,7 @@ qh_make (
|
|||
is_input, 0,
|
||||
hb_mult(maxp) * max_packet(maxp)));
|
||||
qh->start = NO_FRAME;
|
||||
qh->stamp = ehci->periodic_stamp;
|
||||
|
||||
if (urb->dev->speed == USB_SPEED_HIGH) {
|
||||
qh->c_usecs = 0;
|
||||
|
@ -1183,6 +1184,10 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
|||
ehci->reclaim = NULL;
|
||||
start_unlink_async (ehci, next);
|
||||
}
|
||||
|
||||
if (ehci->has_synopsys_hc_bug)
|
||||
ehci_writel(ehci, (u32) ehci->async->qh_dma,
|
||||
&ehci->regs->async_next);
|
||||
}
|
||||
|
||||
/* makes sure the async qh will become idle */
|
||||
|
|
202
drivers/usb/host/ehci-s5p.c
Normal file
202
drivers/usb/host/ehci-s5p.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* SAMSUNG S5P USB HOST EHCI Controller
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Jingoo Han <jg1.han@samsung.com>
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/regs-pmu.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/ehci.h>
|
||||
#include <plat/usb-phy.h>
|
||||
|
||||
struct s5p_ehci_hcd {
|
||||
struct device *dev;
|
||||
struct usb_hcd *hcd;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static const struct hc_driver s5p_ehci_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "S5P EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
.reset = ehci_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_platdata *pdata;
|
||||
struct s5p_ehci_hcd *s5p_ehci;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int err;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
|
||||
if (!s5p_ehci)
|
||||
return -ENOMEM;
|
||||
|
||||
s5p_ehci->dev = &pdev->dev;
|
||||
|
||||
hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
dev_err(&pdev->dev, "Unable to create HCD\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_hcd;
|
||||
}
|
||||
|
||||
s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
|
||||
|
||||
if (IS_ERR(s5p_ehci->clk)) {
|
||||
dev_err(&pdev->dev, "Failed to get usbhost clock\n");
|
||||
err = PTR_ERR(s5p_ehci->clk);
|
||||
goto fail_clk;
|
||||
}
|
||||
|
||||
err = clk_enable(s5p_ehci->clk);
|
||||
if (err)
|
||||
goto fail_clken;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Failed to get I/O memory\n");
|
||||
err = -ENXIO;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = ioremap(res->start, resource_size(res));
|
||||
if (!hcd->regs) {
|
||||
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ\n");
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pdata->phy_init)
|
||||
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, s5p_ehci);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
iounmap(hcd->regs);
|
||||
fail_io:
|
||||
clk_disable(s5p_ehci->clk);
|
||||
fail_clken:
|
||||
clk_put(s5p_ehci->clk);
|
||||
fail_clk:
|
||||
usb_put_hcd(hcd);
|
||||
fail_hcd:
|
||||
kfree(s5p_ehci);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit s5p_ehci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
|
||||
clk_disable(s5p_ehci->clk);
|
||||
clk_put(s5p_ehci->clk);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
kfree(s5p_ehci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s5p_ehci_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
static struct platform_driver s5p_ehci_driver = {
|
||||
.probe = s5p_ehci_probe,
|
||||
.remove = __devexit_p(s5p_ehci_remove),
|
||||
.shutdown = s5p_ehci_shutdown,
|
||||
.driver = {
|
||||
.name = "s5p-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:s5p-ehci");
|
|
@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
|
|||
*/
|
||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||
STS_PSS, 0, 9 * 125);
|
||||
if (status)
|
||||
if (status) {
|
||||
usb_hc_died(ehci_to_hcd(ehci));
|
||||
return status;
|
||||
}
|
||||
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
|
@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
|
|||
*/
|
||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||
STS_PSS, STS_PSS, 9 * 125);
|
||||
if (status)
|
||||
if (status) {
|
||||
usb_hc_died(ehci_to_hcd(ehci));
|
||||
return status;
|
||||
}
|
||||
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
|
@ -2287,6 +2291,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
}
|
||||
clock &= mod - 1;
|
||||
clock_frame = clock >> 3;
|
||||
++ehci->periodic_stamp;
|
||||
|
||||
for (;;) {
|
||||
union ehci_shadow q, *q_p;
|
||||
|
@ -2315,10 +2320,14 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
temp.qh = qh_get (q.qh);
|
||||
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
|
||||
q = q.qh->qh_next;
|
||||
modified = qh_completions (ehci, temp.qh);
|
||||
if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
temp.qh->needs_rescan))
|
||||
intr_deschedule (ehci, temp.qh);
|
||||
if (temp.qh->stamp != ehci->periodic_stamp) {
|
||||
modified = qh_completions(ehci, temp.qh);
|
||||
if (!modified)
|
||||
temp.qh->stamp = ehci->periodic_stamp;
|
||||
if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
temp.qh->needs_rescan))
|
||||
intr_deschedule(ehci, temp.qh);
|
||||
}
|
||||
qh_put (temp.qh);
|
||||
break;
|
||||
case Q_TYPE_FSTN:
|
||||
|
@ -2460,6 +2469,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
if (ehci->clock_frame != clock_frame) {
|
||||
free_cached_lists(ehci);
|
||||
ehci->clock_frame = clock_frame;
|
||||
++ehci->periodic_stamp;
|
||||
}
|
||||
} else {
|
||||
now_uframe++;
|
||||
|
|
|
@ -23,7 +23,7 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
|
|||
int ret;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
|
|
|
@ -38,7 +38,7 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
|
|||
|
||||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
@ -58,6 +58,71 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
|
|||
clk_disable(tegra->emc_clk);
|
||||
}
|
||||
|
||||
static int tegra_ehci_internal_port_reset(
|
||||
struct ehci_hcd *ehci,
|
||||
u32 __iomem *portsc_reg
|
||||
)
|
||||
{
|
||||
u32 temp;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
int i, tries;
|
||||
u32 saved_usbintr;
|
||||
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
/* disable USB interrupt */
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
/*
|
||||
* Here we have to do Port Reset at most twice for
|
||||
* Port Enable bit to be set.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
temp = ehci_readl(ehci, portsc_reg);
|
||||
temp |= PORT_RESET;
|
||||
ehci_writel(ehci, temp, portsc_reg);
|
||||
mdelay(10);
|
||||
temp &= ~PORT_RESET;
|
||||
ehci_writel(ehci, temp, portsc_reg);
|
||||
mdelay(1);
|
||||
tries = 100;
|
||||
do {
|
||||
mdelay(1);
|
||||
/*
|
||||
* Up to this point, Port Enable bit is
|
||||
* expected to be set after 2 ms waiting.
|
||||
* USB1 usually takes extra 45 ms, for safety,
|
||||
* we take 100 ms as timeout.
|
||||
*/
|
||||
temp = ehci_readl(ehci, portsc_reg);
|
||||
} while (!(temp & PORT_PE) && tries--);
|
||||
if (temp & PORT_PE)
|
||||
break;
|
||||
}
|
||||
if (i == 2)
|
||||
retval = -ETIMEDOUT;
|
||||
|
||||
/*
|
||||
* Clear Connect Status Change bit if it's set.
|
||||
* We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
|
||||
*/
|
||||
if (temp & PORT_CSC)
|
||||
ehci_writel(ehci, PORT_CSC, portsc_reg);
|
||||
|
||||
/*
|
||||
* Write to clear any interrupt status bits that might be set
|
||||
* during port reset.
|
||||
*/
|
||||
temp = ehci_readl(ehci, &ehci->regs->status);
|
||||
ehci_writel(ehci, temp, &ehci->regs->status);
|
||||
|
||||
/* restore original interrupt enable bits */
|
||||
ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int tegra_ehci_hub_control(
|
||||
struct usb_hcd *hcd,
|
||||
u16 typeReq,
|
||||
|
@ -121,6 +186,13 @@ static int tegra_ehci_hub_control(
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* For USB1 port we need to issue Port Reset twice internally */
|
||||
if (tegra->phy->instance == 0 &&
|
||||
(typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
return tegra_ehci_internal_port_reset(ehci, status_reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tegra host controller will time the resume operation to clear the bit
|
||||
* when the port control state switches to HS or FS Idle. This behavior
|
||||
|
@ -328,7 +400,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
@ -121,7 +121,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
@ -57,7 +57,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
|
|||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* enable PHY 0,1,the regs only apply to w90p910
|
||||
* 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
|
||||
|
|
|
@ -220,7 +220,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
|
|||
*/
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
|
|||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
|
@ -128,12 +129,14 @@ struct ehci_hcd { /* one per controller */
|
|||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||
unsigned big_endian_mmio:1;
|
||||
unsigned big_endian_desc:1;
|
||||
unsigned big_endian_capbase:1;
|
||||
unsigned has_amcc_usb23:1;
|
||||
unsigned need_io_watchdog:1;
|
||||
unsigned broken_periodic:1;
|
||||
unsigned amd_pll_fix:1;
|
||||
unsigned fs_i_thresh:1; /* Intel iso scheduling */
|
||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
|
@ -160,6 +163,10 @@ struct ehci_hcd { /* one per controller */
|
|||
#ifdef DEBUG
|
||||
struct dentry *debug_dir;
|
||||
#endif
|
||||
/*
|
||||
* OTG controllers and transceivers need software interaction
|
||||
*/
|
||||
struct otg_transceiver *transceiver;
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
|
@ -600,12 +607,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
|||
* This attempts to support either format at compile time without a
|
||||
* runtime penalty, or both formats with the additional overhead
|
||||
* of checking a flag bit.
|
||||
*
|
||||
* ehci_big_endian_capbase is a special quirk for controllers that
|
||||
* implement the HC capability registers as separate registers and not
|
||||
* as fields of a 32-bit register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
|
||||
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
|
||||
#else
|
||||
#define ehci_big_endian_mmio(e) 0
|
||||
#define ehci_big_endian_capbase(e) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
|
|||
/* IRQ's are off, we do no DMA,
|
||||
perfectly ready to die ... */
|
||||
hcd->state = HC_STATE_HALT;
|
||||
usb_hc_died(hcd);
|
||||
ret = IRQ_HANDLED;
|
||||
goto done;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -49,10 +49,9 @@ void deinit_kmem_cache(void);
|
|||
#define SW_RESET_RESET_ALL (1 << 0)
|
||||
|
||||
#define HC_BUFFER_STATUS_REG 0x334
|
||||
#define ATL_BUFFER 0x1
|
||||
#define INT_BUFFER 0x2
|
||||
#define ISO_BUFFER 0x4
|
||||
#define BUFFER_MAP 0x7
|
||||
#define ISO_BUF_FILL (1 << 2)
|
||||
#define INT_BUF_FILL (1 << 1)
|
||||
#define ATL_BUF_FILL (1 << 0)
|
||||
|
||||
#define HC_MEMORY_REG 0x33c
|
||||
#define ISP_BANK(x) ((x) << 16)
|
||||
|
@ -68,14 +67,13 @@ void deinit_kmem_cache(void);
|
|||
#define HC_INTERRUPT_REG 0x310
|
||||
|
||||
#define HC_INTERRUPT_ENABLE 0x314
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_INTL_INT | HC_SOT_INT | HC_EOT_INT)
|
||||
|
||||
#define HC_ISO_INT (1 << 9)
|
||||
#define HC_ATL_INT (1 << 8)
|
||||
#define HC_INTL_INT (1 << 7)
|
||||
#define HC_EOT_INT (1 << 3)
|
||||
#define HC_SOT_INT (1 << 1)
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
|
||||
|
||||
#define HC_ISO_IRQ_MASK_OR_REG 0x318
|
||||
#define HC_INT_IRQ_MASK_OR_REG 0x31C
|
||||
|
@ -106,7 +104,7 @@ struct ptd {
|
|||
#define ATL_PTD_OFFSET 0x0c00
|
||||
#define PAYLOAD_OFFSET 0x1000
|
||||
|
||||
struct inter_packet_info {
|
||||
struct slotinfo {
|
||||
struct isp1760_qh *qh;
|
||||
struct isp1760_qtd *qtd;
|
||||
};
|
||||
|
@ -156,54 +154,52 @@ struct memory_chunk {
|
|||
|
||||
/* ATL */
|
||||
/* DW0 */
|
||||
#define PTD_VALID 1
|
||||
#define PTD_LENGTH(x) (((u32) x) << 3)
|
||||
#define PTD_MAXPACKET(x) (((u32) x) << 18)
|
||||
#define PTD_MULTI(x) (((u32) x) << 29)
|
||||
#define PTD_ENDPOINT(x) (((u32) x) << 31)
|
||||
#define DW0_VALID_BIT 1
|
||||
#define FROM_DW0_VALID(x) ((x) & 0x01)
|
||||
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
|
||||
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
|
||||
#define TO_DW0_MULTI(x) (((u32) x) << 29)
|
||||
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
|
||||
/* DW1 */
|
||||
#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
|
||||
#define PTD_PID_TOKEN(x) (((u32) x) << 10)
|
||||
#define PTD_TRANS_BULK ((u32) 2 << 12)
|
||||
#define PTD_TRANS_INT ((u32) 3 << 12)
|
||||
#define PTD_TRANS_SPLIT ((u32) 1 << 14)
|
||||
#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
|
||||
#define PTD_PORT_NUM(x) (((u32) x) << 18)
|
||||
#define PTD_HUB_NUM(x) (((u32) x) << 25)
|
||||
#define PTD_PING(x) (((u32) x) << 26)
|
||||
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
|
||||
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
|
||||
#define DW1_TRANS_BULK ((u32) 2 << 12)
|
||||
#define DW1_TRANS_INT ((u32) 3 << 12)
|
||||
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
|
||||
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
|
||||
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
|
||||
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
|
||||
/* DW2 */
|
||||
#define PTD_RL_CNT(x) (((u32) x) << 25)
|
||||
#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
|
||||
#define BASE_ADDR 0x1000
|
||||
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
|
||||
#define TO_DW2_RL(x) ((x) << 25)
|
||||
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
|
||||
/* DW3 */
|
||||
#define PTD_CERR(x) (((u32) x) << 23)
|
||||
#define PTD_NAC_CNT(x) (((u32) x) << 19)
|
||||
#define PTD_ACTIVE ((u32) 1 << 31)
|
||||
#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
|
||||
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
|
||||
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
|
||||
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
|
||||
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
|
||||
#define TO_DW3_CERR(x) ((x) << 23)
|
||||
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
|
||||
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
|
||||
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
|
||||
#define TO_DW3_PING(x) ((x) << 26)
|
||||
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
|
||||
#define DW3_ERROR_BIT (1 << 28)
|
||||
#define DW3_QTD_ACTIVE (1 << 31)
|
||||
#define DW3_BABBLE_BIT (1 << 29)
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define DW3_ACTIVE_BIT (1 << 31)
|
||||
|
||||
#define INT_UNDERRUN (1 << 2)
|
||||
#define INT_BABBLE (1 << 1)
|
||||
#define INT_EXACT (1 << 0)
|
||||
|
||||
#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
|
||||
#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
|
||||
#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
|
||||
|
||||
#define SETUP_PID (2)
|
||||
#define IN_PID (1)
|
||||
#define OUT_PID (0)
|
||||
#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
|
||||
|
||||
#define DATA_TOGGLE (1 << 31)
|
||||
#define GET_DATA_TOGGLE(x) ((x) >> 31)
|
||||
|
||||
/* Errata 1 */
|
||||
#define RL_COUNTER (0)
|
||||
#define NAK_COUNTER (0)
|
||||
#define ERR_COUNTER (2)
|
||||
|
||||
#endif
|
||||
#endif /* _ISP1760_HCD_H_ */
|
||||
|
|
|
@ -3,18 +3,19 @@
|
|||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2010 Cavium Networks
|
||||
* Copyright (C) 2010, 2011 Cavium Networks
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include <asm/octeon/octeon.h>
|
||||
#include <asm/octeon/cvmx-uctlx-defs.h>
|
||||
|
||||
static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
|
||||
|
||||
static int octeon2_usb_clock_start_cnt;
|
||||
|
||||
void octeon2_usb_clocks_start(void)
|
||||
{
|
||||
|
@ -26,8 +27,12 @@ void octeon2_usb_clocks_start(void)
|
|||
int i;
|
||||
unsigned long io_clk_64_to_ns;
|
||||
|
||||
if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1)
|
||||
return;
|
||||
|
||||
mutex_lock(&octeon2_usb_clocks_mutex);
|
||||
|
||||
octeon2_usb_clock_start_cnt++;
|
||||
if (octeon2_usb_clock_start_cnt != 1)
|
||||
goto exit;
|
||||
|
||||
io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
|
||||
|
||||
|
@ -43,6 +48,13 @@ void octeon2_usb_clocks_start(void)
|
|||
|
||||
/* Step 3: Configure the reference clock, PHY, and HCLK */
|
||||
clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
|
||||
|
||||
/*
|
||||
* If the UCTL looks like it has already been started, skip
|
||||
* the initialization, otherwise bus errors are obtained.
|
||||
*/
|
||||
if (clk_rst_ctl.s.hrst)
|
||||
goto end_clock;
|
||||
/* 3a */
|
||||
clk_rst_ctl.s.p_por = 1;
|
||||
clk_rst_ctl.s.hrst = 0;
|
||||
|
@ -158,28 +170,31 @@ void octeon2_usb_clocks_start(void)
|
|||
clk_rst_ctl.s.hrst = 1;
|
||||
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
|
||||
|
||||
end_clock:
|
||||
/* Now we can set some other registers. */
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
port_ctl_status.u64 =
|
||||
cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
|
||||
/* Set txvreftune to 15 to obtain complient 'eye' diagram. */
|
||||
/* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
|
||||
port_ctl_status.s.txvreftune = 15;
|
||||
port_ctl_status.s.txrisetune = 1;
|
||||
port_ctl_status.s.txpreemphasistune = 1;
|
||||
cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
|
||||
port_ctl_status.u64);
|
||||
}
|
||||
|
||||
/* Set uSOF cycle period to 60,000 bits. */
|
||||
cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
|
||||
exit:
|
||||
mutex_unlock(&octeon2_usb_clocks_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(octeon2_usb_clocks_start);
|
||||
|
||||
void octeon2_usb_clocks_stop(void)
|
||||
{
|
||||
union cvmx_uctlx_if_ena if_ena;
|
||||
|
||||
if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0)
|
||||
return;
|
||||
|
||||
if_ena.u64 = 0;
|
||||
if_ena.s.en = 0;
|
||||
cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
|
||||
mutex_lock(&octeon2_usb_clocks_mutex);
|
||||
octeon2_usb_clock_start_cnt--;
|
||||
mutex_unlock(&octeon2_usb_clocks_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(octeon2_usb_clocks_stop);
|
||||
|
|
151
drivers/usb/host/ohci-ath79.c
Normal file
151
drivers/usb/host/ohci-ath79.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* Bus Glue for Atheros AR71XX/AR724X built-in OHCI controller.
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
* Copyright (C) 2007 Atheros Communications, Inc.
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
|
||||
static int __devinit ohci_ath79_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
int ret;
|
||||
|
||||
ret = ohci_init(ohci);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ohci_run(ohci);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hc_driver ohci_ath79_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Atheros built-in OHCI controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_USB11 | HCD_MEMORY,
|
||||
|
||||
.start = ohci_ath79_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ohci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
static int ohci_ath79_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no IRQ specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
hcd = usb_create_hcd(&ohci_ath79_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no base address specified\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
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);
|
||||
if (!hcd->regs) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
ret = -EFAULT;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
if (ret)
|
||||
goto err_stop_hcd;
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_hcd:
|
||||
iounmap(hcd->regs);
|
||||
err_release_region:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_ath79_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;
|
||||
}
|
||||
|
||||
static struct platform_driver ohci_hcd_ath79_driver = {
|
||||
.probe = ohci_ath79_probe,
|
||||
.remove = ohci_ath79_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ath79-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ohci");
|
|
@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
if (ints == ~(u32)0) {
|
||||
disable (ohci);
|
||||
ohci_dbg (ohci, "device removed!\n");
|
||||
usb_hc_died(hcd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
ints &= ohci_readl(ohci, ®s->intrenable);
|
||||
|
||||
/* interrupt for some other device? */
|
||||
if (ints == 0)
|
||||
if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
|
||||
return IRQ_NOTMINE;
|
||||
|
||||
if (ints & OHCI_INTR_UE) {
|
||||
|
@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
} else {
|
||||
disable (ohci);
|
||||
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
|
||||
usb_hc_died(hcd);
|
||||
}
|
||||
|
||||
ohci_dump (ohci, 1);
|
||||
|
@ -1105,6 +1107,11 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_OHCI_ATH79
|
||||
#include "ohci-ath79.c"
|
||||
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && \
|
||||
!defined(PLATFORM_DRIVER) && \
|
||||
!defined(OMAP1_PLATFORM_DRIVER) && \
|
||||
|
|
|
@ -181,10 +181,18 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
|
|||
*/
|
||||
static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci->flags |= OHCI_QUIRK_SHUTDOWN;
|
||||
ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
|
||||
/* Evidently nVidia fixed their later hardware; this is a guess at
|
||||
* the changeover point.
|
||||
*/
|
||||
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d
|
||||
|
||||
if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) {
|
||||
ohci->flags |= OHCI_QUIRK_SHUTDOWN;
|
||||
ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue