2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-18 07:35:12 +08:00

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:
Linus Torvalds 2011-05-23 12:33:02 -07:00
commit c44dead70a
184 changed files with 14777 additions and 3506 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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
;------------------------------------------------------------------------------

View File

@ -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]

View File

@ -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*

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View 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 */

View File

@ -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));
}

View 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;
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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[] = {

View File

@ -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 */

View File

@ -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

View File

@ -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

View 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;
}

View 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 */

View File

@ -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)

View 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 */

View File

@ -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 */

View File

@ -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

View File

@ -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/

View File

@ -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) },

View File

@ -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

View File

@ -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"

View File

@ -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/

View File

@ -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 @@ early_bail:
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 @@ next_desc:
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 @@ skip_normal_probe:
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 @@ made_compressed_probe:
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 @@ made_compressed_probe:
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 @@ made_compressed_probe:
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 @@ made_compressed_probe:
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 @@ skip_countries:
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 @@ alloc_fail:
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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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",

View File

@ -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";

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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:

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 @@ out:
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 @@ out:
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 */

View File

@ -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 @@ unknown:
}
/* 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 @@ unknown:
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);
}

View File

@ -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();

View File

@ -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:

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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 @@ out:
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 @@ err_unregister:
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 @@ err_kfree:
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,
},
};

View File

@ -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 */

View File

@ -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;
}

View File

@ -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)

View File

@ -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 @@ bad_mps:
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 @@ irq_retry:
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 @@ irq_retry:
}
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 @@ irq_retry:
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 @@ irq_retry:
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 @@ irq_retry:
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 @@ irq_retry:
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 @@ irq_retry:
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 @@ irq_retry:
* set. */
s3c_hsotg_handle_rx(hsotg);
writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS);
}
if (gintsts & S3C_GINTSTS_ModeMis) {
@ -2193,19 +2241,17 @@ irq_retry:
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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

View 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");

View File

@ -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");

View File

@ -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;
}

View File

@ -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;

View File

@ -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"

View File

@ -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,

View File

@ -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)

View 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,
},
};

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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");

View File

@ -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]);

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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");

View File

@ -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");

View File

@ -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);

View File

@ -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");

View File

@ -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
View 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");

View File

@ -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 @@ restart:
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 @@ restart:
if (ehci->clock_frame != clock_frame) {
free_cached_lists(ehci);
ehci->clock_frame = clock_frame;
++ehci->periodic_stamp;
}
} else {
now_uframe++;

View File

@ -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");

View File

@ -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);

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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
/*

View File

@ -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

View File

@ -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_ */

View File

@ -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);

View 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");

View File

@ -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, &regs->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) && \

View File

@ -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