提交 50ee9339 编写于 作者: G Greg Kroah-Hartman

Merge 2.6.39-rc4 into usb-next

This is needed to help resolve some xhci issues and other minor
differences.
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
......@@ -170,6 +170,7 @@ config MACH_NURI
select S3C_DEV_HSMMC3
select S3C_DEV_I2C1
select S3C_DEV_I2C5
select S5P_DEV_USB_EHCI
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_I2C5
select EXYNOS4_SETUP_SDHCI
......
......@@ -54,3 +54,5 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
obj-$(CONFIG_USB_SUPPORT) += usb-phy.o
......@@ -97,7 +97,12 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
.length = SZ_4K,
.type = MT_DEVICE,
},
}, {
.virtual = (unsigned long)S5P_VA_USB_HSPHY,
.pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
.length = SZ_4K,
.type = MT_DEVICE,
}
};
static void exynos4_idle(void)
......
......@@ -101,6 +101,9 @@
#define EXYNOS4_PA_SROMC 0x12570000
#define EXYNOS4_PA_EHCI 0x12580000
#define EXYNOS4_PA_HSPHY 0x125B0000
#define EXYNOS4_PA_UART 0x13800000
#define EXYNOS4_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
......@@ -143,6 +146,7 @@
#define S5P_PA_SROMC EXYNOS4_PA_SROMC
#define S5P_PA_SYSCON EXYNOS4_PA_SYSCON
#define S5P_PA_TIMER EXYNOS4_PA_TIMER
#define S5P_PA_EHCI EXYNOS4_PA_EHCI
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
......
......@@ -33,6 +33,9 @@
#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708)
#define S5P_USBHOST_PHY_ENABLE (1 << 0)
#define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4)
#define S5P_MIPI_DPHY_ENABLE (1 << 0)
#define S5P_MIPI_DPHY_SRESETN (1 << 1)
......
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __PLAT_S5P_REGS_USB_PHY_H
#define __PLAT_S5P_REGS_USB_PHY_H
#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S5P_VA_USB_HSPHY)
#define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00)
#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
#define PHY1_HSIC1_SLEEP (1 << 12)
#define PHY1_HSIC1_FORCE_SUSPEND (1 << 11)
#define PHY1_HSIC0_SLEEP (1 << 10)
#define PHY1_HSIC0_FORCE_SUSPEND (1 << 9)
#define PHY1_STD_NORMAL_MASK (0x7 << 6)
#define PHY1_STD_SLEEP (1 << 8)
#define PHY1_STD_ANALOG_POWERDOWN (1 << 7)
#define PHY1_STD_FORCE_SUSPEND (1 << 6)
#define PHY0_NORMAL_MASK (0x39 << 0)
#define PHY0_SLEEP (1 << 5)
#define PHY0_OTG_DISABLE (1 << 4)
#define PHY0_ANALOG_POWERDOWN (1 << 3)
#define PHY0_FORCE_SUSPEND (1 << 0)
#define EXYNOS4_PHYCLK EXYNOS4_HSOTG_PHYREG(0x04)
#define PHY1_COMMON_ON_N (1 << 7)
#define PHY0_COMMON_ON_N (1 << 4)
#define PHY0_ID_PULLUP (1 << 2)
#define CLKSEL_MASK (0x3 << 0)
#define CLKSEL_SHIFT (0)
#define CLKSEL_48M (0x0 << 0)
#define CLKSEL_12M (0x2 << 0)
#define CLKSEL_24M (0x3 << 0)
#define EXYNOS4_RSTCON EXYNOS4_HSOTG_PHYREG(0x08)
#define HOST_LINK_PORT_SWRST_MASK (0xf << 6)
#define HOST_LINK_PORT2_SWRST (1 << 9)
#define HOST_LINK_PORT1_SWRST (1 << 8)
#define HOST_LINK_PORT0_SWRST (1 << 7)
#define HOST_LINK_ALL_SWRST (1 << 6)
#define PHY1_SWRST_MASK (0x7 << 3)
#define PHY1_HSIC_SWRST (1 << 5)
#define PHY1_STD_SWRST (1 << 4)
#define PHY1_ALL_SWRST (1 << 3)
#define PHY0_SWRST_MASK (0x7 << 0)
#define PHY0_PHYLINK_SWRST (1 << 2)
#define PHY0_HLINK_SWRST (1 << 1)
#define PHY0_SWRST (1 << 0)
#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34)
#define FPENABLEN (1 << 0)
#endif /* __PLAT_S5P_REGS_USB_PHY_H */
......@@ -30,6 +30,8 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
#include <plat/ehci.h>
#include <plat/clock.h>
#include <mach/map.h>
......@@ -262,6 +264,16 @@ static struct i2c_board_info i2c5_devs[] __initdata = {
/* max8997, To be updated */
};
/* USB EHCI */
static struct s5p_ehci_platdata nuri_ehci_pdata;
static void __init nuri_ehci_init(void)
{
struct s5p_ehci_platdata *pdata = &nuri_ehci_pdata;
s5p_ehci_set_platdata(pdata);
}
static struct platform_device *nuri_devices[] __initdata = {
/* Samsung Platform Devices */
&emmc_fixed_voltage,
......@@ -270,6 +282,7 @@ static struct platform_device *nuri_devices[] __initdata = {
&s3c_device_hsmmc3,
&s3c_device_wdt,
&s3c_device_timer[0],
&s5p_device_ehci,
/* NURI Devices */
&nuri_gpio_keys,
......@@ -291,6 +304,9 @@ static void __init nuri_machine_init(void)
i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
nuri_ehci_init();
clk_xusbxti.rate = 24000000;
/* Last */
platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
}
......
/*
* 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;
}
......@@ -85,6 +85,11 @@ config S5P_DEV_CSIS1
help
Compile in platform device definitions for MIPI-CSIS channel 1
config S5P_DEV_USB_EHCI
bool
help
Compile in platform device definition for USB EHCI
config S5P_SETUP_MIPIPHY
bool
help
......
......@@ -33,4 +33,5 @@ obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
obj-$(CONFIG_S5P_DEV_USB_EHCI) += dev-ehci.o
obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
/*
* 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;
}
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __PLAT_S5P_EHCI_H
#define __PLAT_S5P_EHCI_H
struct s5p_ehci_platdata {
int (*phy_init)(struct platform_device *pdev, int type);
int (*phy_exit)(struct platform_device *pdev, int type);
};
extern void s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd);
#endif /* __PLAT_S5P_EHCI_H */
......@@ -39,7 +39,7 @@
#define S5P_VA_TWD S5P_VA_COREPERI(0x600)
#define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000)
#define S3C_VA_USB_HSPHY S3C_ADDR(0x02900000)
#define S5P_VA_USB_HSPHY S3C_ADDR(0x02900000)
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000))
#define VA_VIC0 VA_VIC(0)
......
/*
* 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 */
......@@ -142,6 +142,8 @@ extern struct platform_device s5p_device_fimc3;
extern struct platform_device s5p_device_mipi_csis0;
extern struct platform_device s5p_device_mipi_csis1;
extern struct platform_device s5p_device_ehci;
extern struct platform_device exynos4_device_sysmmu;
/* s3c2440 specific devices */
......
......@@ -26,12 +26,17 @@ config ATH79_MACH_PB44
endmenu
config SOC_AR71XX
select USB_ARCH_HAS_EHCI
select USB_ARCH_HAS_OHCI
def_bool n
config SOC_AR724X
select USB_ARCH_HAS_EHCI
select USB_ARCH_HAS_OHCI
def_bool n
config SOC_AR913X
select USB_ARCH_HAS_EHCI
def_bool n
config ATH79_DEV_AR913X_WMAC
......
......@@ -64,11 +64,10 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/
obj-$(CONFIG_USB_OTG_UTILS) += usb/otg/
obj-$(CONFIG_USB_OTG_UTILS) += usb/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_USB_GADGET) += usb/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
......
......@@ -65,6 +65,7 @@ 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 PCI
......@@ -116,6 +117,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"
......
......@@ -45,3 +45,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/
此差异已折叠。
......@@ -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 */
};
......
......@@ -64,49 +64,49 @@
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
#define ALLOW_SERIAL_NUMBER
static const char *format_topo =
static const char format_topo[] =
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n";
static const char *format_string_manufacturer =
static const char format_string_manufacturer[] =
/* S: Manufacturer=xxxx */
"S: Manufacturer=%.100s\n";
static const char *format_string_product =
static const char format_string_product[] =
/* S: Product=xxxx */
"S: Product=%.100s\n";
#ifdef ALLOW_SERIAL_NUMBER
static const char *format_string_serialnumber =
static const char format_string_serialnumber[] =
/* S: SerialNumber=xxxx */
"S: SerialNumber=%.100s\n";
#endif
static const char *format_bandwidth =
static const char format_bandwidth[] =
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
"B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
static const char *format_device1 =
static const char format_device1[] =
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
static const char *format_device2 =
static const char format_device2[] =
/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
"P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
static const char *format_config =
static const char format_config[] =
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
static const char *format_iad =
static const char format_iad[] =
/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
"A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
static const char *format_iface =
static const char format_iface[] =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static const char *format_endpt =
static const char format_endpt[] =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
......
......@@ -236,13 +236,6 @@ EXPORT_SYMBOL_GPL(usb_register_dev);
void usb_deregister_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
{
int minor_base = class_driver->minor_base;
char name[20];
#ifdef CONFIG_USB_DYNAMIC_MINORS
minor_base = 0;
#endif
if (intf->minor == -1)
return;
......@@ -252,7 +245,6 @@ void usb_deregister_dev(struct usb_interface *intf,
usb_minors[intf->minor] = NULL;
up_write(&minor_rwsem);
snprintf(name, sizeof(name), class_driver->name, intf->minor - minor_base);
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
intf->usb_dev = NULL;
intf->minor = -1;
......
......@@ -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)
......
......@@ -613,6 +613,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 +1589,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 +1676,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 +1688,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;
......@@ -2800,6 +2773,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;
......
......@@ -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;
......
......@@ -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 */
......
......@@ -148,6 +148,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 +213,9 @@ 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;
return -ENOENT;
}
......
......@@ -711,10 +711,11 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
ssize_t rc = count;
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
......@@ -738,10 +739,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)
......
......@@ -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)
......@@ -444,6 +467,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
......
/*
* 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 ret;
id = platform_get_device_id(pdev);
if (!id) {
dev_err(hcd->self.controller, "missing device id\n");
return -EINVAL;
}
switch (id->driver_data) {
case EHCI_ATH79_IP_V1:
ehci->has_synopsys_hc_bug = 1;
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
break;
case EHCI_ATH79_IP_V2:
hcd->has_tt = 1;
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
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");
......@@ -1265,6 +1265,16 @@ 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
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
......
......@@ -127,7 +127,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;
......
......@@ -1183,6 +1183,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 */
......
/*
* 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 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(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 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 = s5p_ehci_remove,
.shutdown = s5p_ehci_shutdown,
.driver = {
.name = "s5p-ehci",
.owner = THIS_MODULE,
}
};
MODULE_ALIAS("platform:s5p-ehci");
......@@ -134,6 +134,7 @@ struct ehci_hcd { /* one per controller */
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)
......
/*
* 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");
......@@ -1105,6 +1105,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) && \
......
......@@ -71,12 +71,6 @@ MODULE_ALIAS("platform:sl811-hcd");
/* for now, use only one transfer register bank */
#undef USE_B
/* this doesn't understand urb->iso_frame_desc[], but if you had a driver
* that just queued one ISO frame per URB then iso transfers "should" work
* using the normal urb status fields.
*/
#define DISABLE_ISO
// #define QUIRK2
#define QUIRK3
......@@ -807,7 +801,7 @@ static int sl811h_urb_enqueue(
int retval;
struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
#ifndef CONFIG_USB_SL811_HCD_ISO
if (type == PIPE_ISOCHRONOUS)
return -ENOSPC;
#endif
......
......@@ -3230,8 +3230,7 @@ static int __init u132_hcd_init(void)
mutex_init(&u132_module_lock);
if (usb_disabled())
return -ENODEV;
printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
__DATE__);
printk(KERN_INFO "driver %s\n", hcd_name);
workqueue = create_singlethread_workqueue("u132");
retval = platform_driver_register(&u132_platform_driver);
return retval;
......
......@@ -139,10 +139,7 @@ static void finish_reset(struct uhci_hcd *uhci)
uhci->port_c_suspend = uhci->resuming_ports = 0;
uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
uhci->dead = 0; /* Full reset resurrects the controller */
}
/*
......@@ -188,10 +185,6 @@ static void configure_hc(struct uhci_hcd *uhci)
outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
uhci->io_addr + USBFRNUM);
/* Mark controller as not halted before we enable interrupts */
uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
mb();
/* Enable PIRQ */
pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
......@@ -360,7 +353,6 @@ __acquires(uhci->lock)
static void start_rh(struct uhci_hcd *uhci)
{
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
uhci->is_stopped = 0;
/* Mark it configured and running with a 64-byte max packet.
......@@ -449,6 +441,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
lprintk(errbuf);
}
uhci_hc_died(uhci);
usb_hc_died(hcd);
/* Force a callback in case there are
* pending unlinks */
......@@ -842,16 +835,17 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
spin_lock_irq(&uhci->lock);
/* Make sure resume from hibernation re-enumerates everything */
if (hibernated)
uhci_hc_died(uhci);
if (hibernated) {
uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
finish_reset(uhci);
}
/* The firmware or a boot kernel may have changed the controller
* settings during a system wakeup. Check it and reconfigure
* to avoid problems.
/* The firmware may have changed the controller settings during
* a system wakeup. Check it and reconfigure to avoid problems.
*/
check_and_reset_hc(uhci);
/* If the controller was dead before, it's back alive now */
else {
check_and_reset_hc(uhci);
}
configure_hc(uhci);
/* Tell the core if the controller had to be reset */
......
......@@ -2889,8 +2889,7 @@ static struct usb_driver ftdi_elan_driver = {
static int __init ftdi_elan_init(void)
{
int result;
printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
__TIME__, __DATE__);
printk(KERN_INFO "driver %s\n", ftdi_elan_driver.name);
mutex_init(&ftdi_module_lock);
INIT_LIST_HEAD(&ftdi_static_list);
status_queue = create_singlethread_workqueue("ftdi-status-control");
......
......@@ -160,6 +160,7 @@ struct twl4030_usb {
int irq;
u8 linkstat;
bool vbus_supplied;
u8 asleep;
bool irq_enabled;
};
......@@ -250,6 +251,8 @@ static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
int status;
int linkstat = USB_EVENT_NONE;
twl->vbus_supplied = false;
/*
* For ID/VBUS sensing, see manual section 15.4.8 ...
* except when using only battery backup power, two
......@@ -265,6 +268,9 @@ static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
if (status < 0)
dev_err(twl->dev, "USB link status err %d\n", status);
else if (status & (BIT(7) | BIT(2))) {
if (status & (BIT(7)))
twl->vbus_supplied = true;
if (status & BIT(2))
linkstat = USB_EVENT_ID;
else
......@@ -484,7 +490,7 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
spin_lock_irqsave(&twl->lock, flags);
ret = sprintf(buf, "%s\n",
(twl->linkstat == USB_EVENT_VBUS) ? "on" : "off");
twl->vbus_supplied ? "on" : "off");
spin_unlock_irqrestore(&twl->lock, flags);
return ret;
......@@ -608,6 +614,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
twl->otg.set_peripheral = twl4030_set_peripheral;
twl->otg.set_suspend = twl4030_set_suspend;
twl->usb_mode = pdata->usb_mode;
twl->vbus_supplied = false;
twl->asleep = 1;
/* init spinlock for workqueue */
......
......@@ -101,7 +101,7 @@ struct twl6030_usb {
bool irq_enabled;
};
#define xceiv_to_twl(x) container_of((x), struct twl6030_usb, otg);
#define xceiv_to_twl(x) container_of((x), struct twl6030_usb, otg)
/*-------------------------------------------------------------------------*/
......
#
# Renesas USB Controller Drivers
#
config USB_RENESAS_USBHS
tristate 'Renesas USBHS controller'
default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
that supports both full and high speed USB 2.0 data transfers.
It has nine or more configurable endpoints, and endpoint zero.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "renesas_usbhs" and force all
gadget drivers to also be dynamically linked.
#
# for Renesas USB
#
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
renesas_usbhs-y := common.o mod.o pipe.o
renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include "./common.h"
/*
* platform call back
*
* renesas usb support platform callback function.
* Below macro call it.
* if platform doesn't have callback, it return 0 (no error)
*/
#define usbhs_platform_call(priv, func, args...)\
(!(priv) ? -ENODEV : \
!((priv)->pfunc->func) ? 0 : \
(priv)->pfunc->func(args))
/*
* common functions
*/
u16 usbhs_read(struct usbhs_priv *priv, u32 reg)
{
return ioread16(priv->base + reg);
}
void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data)
{
iowrite16(data, priv->base + reg);
}
void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data)
{
u16 val = usbhs_read(priv, reg);
val &= ~mask;
val |= data & mask;
usbhs_write(priv, reg, val);
}
/*
* syscfg functions
*/
void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
{
usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0);
}
void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable)
{
usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0);
}
void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable)
{
usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0);
}
void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU;
u16 val = DCFM | DRPD;
/*
* if enable
*
* - select Host mode
* - D+ Line/D- Line Pull-down
*/
usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
}
void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU;
u16 val = DPRPU;
/*
* if enable
*
* - select Function mode
* - D+ Line Pull-up
*/
usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
}
/*
* frame functions
*/
int usbhs_frame_get_num(struct usbhs_priv *priv)
{
return usbhs_read(priv, FRMNUM) & FRNM_MASK;
}
/*
* local functions
*/
static struct usbhs_priv *usbhsc_pdev_to_priv(struct platform_device *pdev)
{
return dev_get_drvdata(&pdev->dev);
}
static void usbhsc_bus_ctrl(struct usbhs_priv *priv, int enable)
{
int wait = usbhs_get_dparam(priv, buswait_bwait);
u16 data = 0;
if (enable) {
/* set bus wait if platform have */
if (wait)
usbhs_bset(priv, BUSWAIT, 0x000F, wait);
}
usbhs_write(priv, DVSTCTR, data);
}
/*
* platform default param
*/
static u32 usbhsc_default_pipe_type[] = {
USB_ENDPOINT_XFER_CONTROL,
USB_ENDPOINT_XFER_ISOC,
USB_ENDPOINT_XFER_ISOC,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_INT,
};
/*
* driver callback functions
*/
static void usbhsc_notify_hotplug(struct work_struct *work)
{
struct usbhs_priv *priv = container_of(work,
struct usbhs_priv,
notify_hotplug_work);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
int id;
int enable;
int ret;
/*
* get vbus status from platform
*/
enable = usbhs_platform_call(priv, get_vbus, pdev);
/*
* get id from platform
*/
id = usbhs_platform_call(priv, get_id, pdev);
if (enable && !mod) {
ret = usbhs_mod_change(priv, id);
if (ret < 0)
return;
dev_dbg(&pdev->dev, "%s enable\n", __func__);
/* enable PM */
pm_runtime_get_sync(&pdev->dev);
/* USB on */
usbhs_sys_clock_ctrl(priv, enable);
usbhsc_bus_ctrl(priv, enable);
/* module start */
usbhs_mod_call(priv, start, priv);
} else if (!enable && mod) {
dev_dbg(&pdev->dev, "%s disable\n", __func__);
/* module stop */
usbhs_mod_call(priv, stop, priv);
/* USB off */
usbhsc_bus_ctrl(priv, enable);
usbhs_sys_clock_ctrl(priv, enable);
/* disable PM */
pm_runtime_put_sync(&pdev->dev);
usbhs_mod_change(priv, -1);
/* reset phy for next connection */
usbhs_platform_call(priv, phy_reset, pdev);
}
}
static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhsc_pdev_to_priv(pdev);
/*
* This functions will be called in interrupt.
* To make sure safety context,
* use workqueue for usbhs_notify_hotplug
*/
schedule_work(&priv->notify_hotplug_work);
return 0;
}
/*
* platform functions
*/
static int __devinit usbhs_probe(struct platform_device *pdev)
{
struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
struct renesas_usbhs_driver_callback *dfunc;
struct usbhs_priv *priv;
struct resource *res;
unsigned int irq;
int ret;
/* check platform information */
if (!info ||
!info->platform_callback.get_id ||
!info->platform_callback.get_vbus) {
dev_err(&pdev->dev, "no platform information\n");
return -EINVAL;
}
/* platform data */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!res || (int)irq <= 0) {
dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
/* usb private data */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "Could not allocate priv\n");
return -ENOMEM;
}
priv->base = ioremap_nocache(res->start, resource_size(res));
if (!priv->base) {
dev_err(&pdev->dev, "ioremap error.\n");
ret = -ENOMEM;
goto probe_end_kfree;
}
/*
* care platform info
*/
priv->pfunc = &info->platform_callback;
priv->dparam = &info->driver_param;
/* set driver callback functions for platform */
dfunc = &info->driver_callback;
dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
/* set default param if platform doesn't have */
if (!priv->dparam->pipe_type) {
priv->dparam->pipe_type = usbhsc_default_pipe_type;
priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
}
/*
* priv settings
*/
priv->irq = irq;
priv->pdev = pdev;
INIT_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
spin_lock_init(usbhs_priv_to_lock(priv));
/* call pipe and module init */
ret = usbhs_pipe_probe(priv);
if (ret < 0)
goto probe_end_mod_exit;
ret = usbhs_mod_probe(priv);
if (ret < 0)
goto probe_end_iounmap;
/* dev_set_drvdata should be called after usbhs_mod_init */
dev_set_drvdata(&pdev->dev, priv);
/*
* deviece reset here because
* USB device might be used in boot loader.
*/
usbhs_sys_clock_ctrl(priv, 0);
/*
* platform call
*
* USB phy setup might depend on CPU/Board.
* If platform has its callback functions,
* call it here.
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "platform prove failed.\n");
goto probe_end_pipe_exit;
}
/* reset phy for connection */
usbhs_platform_call(priv, phy_reset, pdev);
/*
* manual call notify_hotplug for cold plug
*/
pm_runtime_enable(&pdev->dev);
ret = usbhsc_drvcllbck_notify_hotplug(pdev);
if (ret < 0)
goto probe_end_call_remove;
dev_info(&pdev->dev, "probed\n");
return ret;
probe_end_call_remove:
usbhs_platform_call(priv, hardware_exit, pdev);
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
probe_end_mod_exit:
usbhs_mod_remove(priv);
probe_end_iounmap:
iounmap(priv->base);
probe_end_kfree:
kfree(priv);
dev_info(&pdev->dev, "probe failed\n");
return ret;
}
static int __devexit usbhs_remove(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhsc_pdev_to_priv(pdev);
dev_dbg(&pdev->dev, "usb remove\n");
pm_runtime_disable(&pdev->dev);
usbhsc_bus_ctrl(priv, 0);
usbhs_platform_call(priv, hardware_exit, pdev);
usbhs_pipe_remove(priv);
usbhs_mod_remove(priv);
iounmap(priv->base);
kfree(priv);
return 0;
}
static struct platform_driver renesas_usbhs_driver = {
.driver = {
.name = "renesas_usbhs",
},
.probe = usbhs_probe,
.remove = __devexit_p(usbhs_remove),
};
static int __init usbhs_init(void)
{
return platform_driver_register(&renesas_usbhs_driver);
}
static void __exit usbhs_exit(void)
{
platform_driver_unregister(&renesas_usbhs_driver);
}
module_init(usbhs_init);
module_exit(usbhs_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Renesas USB driver");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
#include <linux/platform_device.h>
#include <linux/usb/renesas_usbhs.h>
struct usbhs_priv;
#include "./mod.h"
#include "./pipe.h"
/*
*
* register define
*
*/
#define SYSCFG 0x0000
#define BUSWAIT 0x0002
#define DVSTCTR 0x0008
#define CFIFO 0x0014
#define CFIFOSEL 0x0020
#define CFIFOCTR 0x0022
#define INTENB0 0x0030
#define INTENB1 0x0032
#define BRDYENB 0x0036
#define NRDYENB 0x0038
#define BEMPENB 0x003A
#define INTSTS0 0x0040
#define INTSTS1 0x0042
#define BRDYSTS 0x0046
#define NRDYSTS 0x0048
#define BEMPSTS 0x004A
#define FRMNUM 0x004C
#define USBREQ 0x0054 /* USB request type register */
#define USBVAL 0x0056 /* USB request value register */
#define USBINDX 0x0058 /* USB request index register */
#define USBLENG 0x005A /* USB request length register */
#define DCPCFG 0x005C
#define DCPMAXP 0x005E
#define DCPCTR 0x0060
#define PIPESEL 0x0064
#define PIPECFG 0x0068
#define PIPEBUF 0x006A
#define PIPEMAXP 0x006C
#define PIPEPERI 0x006E
#define PIPEnCTR 0x0070
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
#define HSE (1 << 7) /* High-Speed Operation Enable */
#define DCFM (1 << 6) /* Controller Function Select */
#define DRPD (1 << 5) /* D+ Line/D- Line Resistance Control */
#define DPRPU (1 << 4) /* D+ Line Resistance Control */
#define USBE (1 << 0) /* USB Module Operation Enable */
/* DVSTCTR */
#define EXTLP (1 << 10) /* Controls the EXTLP pin output state */
#define PWEN (1 << 9) /* Controls the PWEN pin output state */
#define RHST (0x7) /* Reset Handshake */
#define RHST_LOW_SPEED 1 /* Low-speed connection */
#define RHST_FULL_SPEED 2 /* Full-speed connection */
#define RHST_HIGH_SPEED 3 /* High-speed connection */
/* CFIFOSEL */
#define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */
/* CFIFOCTR */
#define BVAL (1 << 15) /* Buffer Memory Enable Flag */
#define BCLR (1 << 14) /* CPU buffer clear */
#define FRDY (1 << 13) /* FIFO Port Ready */
#define DTLN_MASK (0x0FFF) /* Receive Data Length */
/* INTENB0 */
#define VBSE (1 << 15) /* Enable IRQ VBUS_0 and VBUSIN_0 */
#define RSME (1 << 14) /* Enable IRQ Resume */
#define SOFE (1 << 13) /* Enable IRQ Frame Number Update */
#define DVSE (1 << 12) /* Enable IRQ Device State Transition */
#define CTRE (1 << 11) /* Enable IRQ Control Stage Transition */
#define BEMPE (1 << 10) /* Enable IRQ Buffer Empty */
#define NRDYE (1 << 9) /* Enable IRQ Buffer Not Ready Response */
#define BRDYE (1 << 8) /* Enable IRQ Buffer Ready */
/* INTENB1 */
#define BCHGE (1 << 14) /* USB Bus Change Interrupt Enable */
#define DTCHE (1 << 12) /* Disconnection Detect Interrupt Enable */
#define ATTCHE (1 << 11) /* Connection Detect Interrupt Enable */
#define EOFERRE (1 << 6) /* EOF Error Detect Interrupt Enable */
#define SIGNE (1 << 5) /* Setup Transaction Error Interrupt Enable */
#define SACKE (1 << 4) /* Setup Transaction ACK Interrupt Enable */
/* INTSTS0 */
#define DVST (1 << 12) /* Device State Transition Interrupt Status */
#define CTRT (1 << 11) /* Control Stage Interrupt Status */
#define BEMP (1 << 10) /* Buffer Empty Interrupt Status */
#define BRDY (1 << 8) /* Buffer Ready Interrupt Status */
#define VBSTS (1 << 7) /* VBUS_0 and VBUSIN_0 Input Status */
#define VALID (1 << 3) /* USB Request Receive */
#define DVSQ_MASK (0x3 << 4) /* Device State */
#define POWER_STATE (0 << 4)
#define DEFAULT_STATE (1 << 4)
#define ADDRESS_STATE (2 << 4)
#define CONFIGURATION_STATE (3 << 4)
#define CTSQ_MASK (0x7) /* Control Transfer Stage */
#define IDLE_SETUP_STAGE 0 /* Idle stage or setup stage */
#define READ_DATA_STAGE 1 /* Control read data stage */
#define READ_STATUS_STAGE 2 /* Control read status stage */
#define WRITE_DATA_STAGE 3 /* Control write data stage */
#define WRITE_STATUS_STAGE 4 /* Control write status stage */
#define NODATA_STATUS_STAGE 5 /* Control write NoData status stage */
#define SEQUENCE_ERROR 6 /* Control transfer sequence error */
/* PIPECFG */
/* DCPCFG */
#define TYPE_NONE (0 << 14) /* Transfer Type */
#define TYPE_BULK (1 << 14)
#define TYPE_INT (2 << 14)
#define TYPE_ISO (3 << 14)
#define DBLB (1 << 9) /* Double Buffer Mode */
#define SHTNAK (1 << 7) /* Pipe Disable in Transfer End */
#define DIR_OUT (1 << 4) /* Transfer Direction */
/* PIPEMAXP */
/* DCPMAXP */
#define DEVSEL_MASK (0xF << 12) /* Device Select */
#define DCP_MAXP_MASK (0x7F)
#define PIPE_MAXP_MASK (0x7FF)
/* PIPEBUF */
#define BUFSIZE_SHIFT 10
#define BUFSIZE_MASK (0x1F << BUFSIZE_SHIFT)
#define BUFNMB_MASK (0xFF)
/* PIPEnCTR */
/* DCPCTR */
#define BSTS (1 << 15) /* Buffer Status */
#define CSSTS (1 << 12) /* CSSTS Status */
#define SQCLR (1 << 8) /* Toggle Bit Clear */
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
#define PBUSY (1 << 5) /* Pipe Busy */
#define PID_MASK (0x3) /* Response PID */
#define PID_NAK 0
#define PID_BUF 1
#define PID_STALL10 2
#define PID_STALL11 3
#define CCPL (1 << 2) /* Control Transfer End Enable */
/* FRMNUM */
#define FRNM_MASK (0x7FF)
/*
* struct
*/
struct usbhs_priv {
void __iomem *base;
unsigned int irq;
struct renesas_usbhs_platform_callback *pfunc;
struct renesas_usbhs_driver_param *dparam;
struct work_struct notify_hotplug_work;
struct platform_device *pdev;
spinlock_t lock;
/*
* module control
*/
struct usbhs_mod_info mod_info;
/*
* pipe control
*/
struct usbhs_pipe_info pipe_info;
};
/*
* common
*/
u16 usbhs_read(struct usbhs_priv *priv, u32 reg);
void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data);
void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
/*
* sysconfig
*/
void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
/*
* frame
*/
int usbhs_frame_get_num(struct usbhs_priv *priv);
/*
* data
*/
#define usbhs_get_dparam(priv, param) (priv->dparam->param)
#define usbhs_priv_to_pdev(priv) (priv->pdev)
#define usbhs_priv_to_dev(priv) (&priv->pdev->dev)
#define usbhs_priv_to_lock(priv) (&priv->lock)
#endif /* RENESAS_USB_DRIVER_H */
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/interrupt.h>
#include "./common.h"
#include "./mod.h"
#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
/*
* host / gadget functions
*
* renesas_usbhs host/gadget can register itself by below functions.
* these functions are called when probe
*
*/
void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
info->mod[id] = mod;
mod->priv = priv;
}
struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
struct usbhs_mod *ret = NULL;
switch (id) {
case USBHS_HOST:
case USBHS_GADGET:
ret = info->mod[id];
break;
}
return ret;
}
int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
if (!mod)
return -EINVAL;
return info->mod[USBHS_HOST] == mod;
}
struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
return info->curt;
}
int usbhs_mod_change(struct usbhs_priv *priv, int id)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
struct usbhs_mod *mod = NULL;
int ret = 0;
/* id < 0 mean no current */
switch (id) {
case USBHS_HOST:
case USBHS_GADGET:
mod = info->mod[id];
break;
default:
ret = -EINVAL;
}
info->curt = mod;
return ret;
}
static irqreturn_t usbhs_interrupt(int irq, void *data);
int usbhs_mod_probe(struct usbhs_priv *priv)
{
struct device *dev = usbhs_priv_to_dev(priv);
int ret;
/*
* install host/gadget driver
*/
ret = usbhs_mod_gadget_probe(priv);
if (ret < 0)
return ret;
/* irq settings */
ret = request_irq(priv->irq, usbhs_interrupt,
IRQF_DISABLED, dev_name(dev), priv);
if (ret) {
dev_err(dev, "irq request err\n");
goto mod_init_gadget_err;
}
return ret;
mod_init_gadget_err:
usbhs_mod_gadget_remove(priv);
return ret;
}
void usbhs_mod_remove(struct usbhs_priv *priv)
{
usbhs_mod_gadget_remove(priv);
free_irq(priv->irq, priv);
}
/*
* status functions
*/
int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state)
{
switch (irq_state->dvstctr & RHST) {
case RHST_LOW_SPEED:
return USB_SPEED_LOW;
case RHST_FULL_SPEED:
return USB_SPEED_FULL;
case RHST_HIGH_SPEED:
return USB_SPEED_HIGH;
}
return USB_SPEED_UNKNOWN;
}
int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state)
{
int state = irq_state->intsts0 & DVSQ_MASK;
switch (state) {
case POWER_STATE:
case DEFAULT_STATE:
case ADDRESS_STATE:
case CONFIGURATION_STATE:
return state;
}
return -EIO;
}
int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
{
/*
* return value
*
* IDLE_SETUP_STAGE
* READ_DATA_STAGE
* READ_STATUS_STAGE
* WRITE_DATA_STAGE
* WRITE_STATUS_STAGE
* NODATA_STATUS_STAGE
* SEQUENCE_ERROR
*/
return (int)irq_state->intsts0 & CTSQ_MASK;
}
static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
struct usbhs_irq_state *state)
{
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
state->intsts0 = usbhs_read(priv, INTSTS0);
state->intsts1 = usbhs_read(priv, INTSTS1);
state->brdysts = usbhs_read(priv, BRDYSTS);
state->nrdysts = usbhs_read(priv, NRDYSTS);
state->bempsts = usbhs_read(priv, BEMPSTS);
state->dvstctr = usbhs_read(priv, DVSTCTR);
/* mask */
state->bempsts &= mod->irq_bempsts;
state->brdysts &= mod->irq_brdysts;
}
/*
* interrupt
*/
#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */
#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */
static irqreturn_t usbhs_interrupt(int irq, void *data)
{
struct usbhs_priv *priv = data;
struct usbhs_irq_state irq_state;
usbhs_status_get_each_irq(priv, &irq_state);
/*
* clear interrupt
*
* The hardware is _very_ picky to clear interrupt bit.
* Especially INTSTS0_MAGIC, INTSTS1_MAGIC value.
*
* see
* "Operation"
* - "Control Transfer (DCP)"
* - Function :: VALID bit should 0
*/
usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
usbhs_write(priv, BRDYSTS, 0);
usbhs_write(priv, NRDYSTS, 0);
usbhs_write(priv, BEMPSTS, 0);
/*
* call irq callback functions
* see also
* usbhs_irq_setting_update
*/
if (irq_state.intsts0 & DVST)
usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
if (irq_state.intsts0 & CTRT)
usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state);
if (irq_state.intsts0 & BEMP)
usbhs_mod_call(priv, irq_empty, priv, &irq_state);
if (irq_state.intsts0 & BRDY)
usbhs_mod_call(priv, irq_ready, priv, &irq_state);
return IRQ_HANDLED;
}
void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
{
u16 intenb0 = 0;
usbhs_write(priv, INTENB0, 0);
usbhs_write(priv, BEMPENB, 0);
usbhs_write(priv, BRDYENB, 0);
/*
* see also
* usbhs_interrupt
*/
/*
* it don't enable DVSE (intenb0) here
* but "mod->irq_dev_state" will be called.
*/
if (mod->irq_ctrl_stage)
intenb0 |= CTRE;
if (mod->irq_empty && mod->irq_bempsts) {
usbhs_write(priv, BEMPENB, mod->irq_bempsts);
intenb0 |= BEMPE;
}
if (mod->irq_ready && mod->irq_brdysts) {
usbhs_write(priv, BRDYENB, mod->irq_brdysts);
intenb0 |= BRDYE;
}
usbhs_write(priv, INTENB0, intenb0);
}
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef RENESAS_USB_MOD_H
#define RENESAS_USB_MOD_H
#include <linux/spinlock.h>
#include <linux/usb/renesas_usbhs.h>
#include "./common.h"
/*
* struct
*/
struct usbhs_irq_state {
u16 intsts0;
u16 intsts1;
u16 brdysts;
u16 nrdysts;
u16 bempsts;
u16 dvstctr;
};
struct usbhs_mod {
char *name;
/*
* entry point from common.c
*/
int (*start)(struct usbhs_priv *priv);
int (*stop)(struct usbhs_priv *priv);
/* INTSTS0 :: DVST (DVSQ) */
int (*irq_dev_state)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
/* INTSTS0 :: CTRT (CTSQ) */
int (*irq_ctrl_stage)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
/* INTSTS0 :: BEMP */
/* BEMPSTS */
int (*irq_empty)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
u16 irq_bempsts;
/* INTSTS0 :: BRDY */
/* BRDYSTS */
int (*irq_ready)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
u16 irq_brdysts;
struct usbhs_priv *priv;
};
struct usbhs_mod_info {
struct usbhs_mod *mod[USBHS_MAX];
struct usbhs_mod *curt; /* current mod */
};
/*
* for host/gadget module
*/
struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id);
struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv);
void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *usb, int id);
int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod);
int usbhs_mod_change(struct usbhs_priv *priv, int id);
int usbhs_mod_probe(struct usbhs_priv *priv);
void usbhs_mod_remove(struct usbhs_priv *priv);
/*
* status functions
*/
int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state);
int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state);
int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state);
/*
* callback functions
*/
void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod);
#define usbhs_mod_call(priv, func, param...) \
({ \
struct usbhs_mod *mod; \
mod = usbhs_mod_get_current(priv); \
!mod ? -ENODEV : \
!mod->func ? 0 : \
mod->func(param); \
})
/*
* gadget control
*/
#ifdef CONFIG_USB_RENESAS_USBHS_UDC
extern int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv);
extern void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv);
#else
static inline int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
{
return 0;
}
static inline void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
{
}
#endif
#endif /* RENESAS_USB_MOD_H */
此差异已折叠。
此差异已折叠。
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef RENESAS_USB_PIPE_H
#define RENESAS_USB_PIPE_H
#include "./common.h"
/*
* struct
*/
struct usbhs_pipe {
u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */
struct usbhs_priv *priv;
u32 flags;
#define USBHS_PIPE_FLAGS_IS_USED (1 << 0)
#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1)
void *mod_private;
};
struct usbhs_pipe_info {
struct usbhs_pipe *pipe;
int size; /* array size of "pipe" */
int bufnmb_last; /* FIXME : driver needs good allocator */
};
/*
* pipe list
*/
#define __usbhs_for_each_pipe(start, pos, info, i) \
for (i = start, pos = (info)->pipe; \
i < (info)->size; \
i++, pos = (info)->pipe + i)
#define usbhs_for_each_pipe(pos, priv, i) \
__usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
#define usbhs_for_each_pipe_with_dcp(pos, priv, i) \
__usbhs_for_each_pipe(0, pos, &((priv)->pipe_info), i)
/*
* pipe module probe / remove
*/
int usbhs_pipe_probe(struct usbhs_priv *priv);
void usbhs_pipe_remove(struct usbhs_priv *priv);
/*
* cfifo
*/
int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe);
int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);
void usbhs_fifo_enable(struct usbhs_pipe *pipe);
void usbhs_fifo_disable(struct usbhs_pipe *pipe);
void usbhs_fifo_stall(struct usbhs_pipe *pipe);
void usbhs_fifo_send_terminator(struct usbhs_pipe *pipe);
/*
* usb request
*/
void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
/*
* pipe control
*/
struct usbhs_pipe
*usbhs_pipe_malloc(struct usbhs_priv *priv,
const struct usb_endpoint_descriptor *desc);
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
void usbhs_pipe_init(struct usbhs_priv *priv);
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe);
#define usbhs_pipe_number(p) (((u32)(p) - (u32)(p)->priv->pipe_info.pipe) / \
sizeof(struct usbhs_pipe))
/*
* dcp control
*/
struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv);
void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_PIPE_H */
......@@ -527,15 +527,6 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
config USB_SERIAL_SAMBA
tristate "USB Atmel SAM Boot Assistant (SAM-BA) driver"
help
Say Y here if you want to access the SAM-BA boot application of an
Atmel AT91SAM device.
To compile this driver as a module, choose M here: the
module will be called sam-ba.
config USB_SERIAL_SIEMENS_MPI
tristate "USB Siemens MPI driver"
help
......
......@@ -48,7 +48,6 @@ obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SAMBA) += sam-ba.o
obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
......
此差异已折叠。
......@@ -890,8 +890,8 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v)
/* utility wrapping a simple endpoint selection policy */
extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
struct usb_endpoint_descriptor *) __devinit;
struct usb_endpoint_descriptor *);
extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit;
extern void usb_ep_autoconfig_reset(struct usb_gadget *);
#endif /* __LINUX_USB_GADGET_H */
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册