Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
  USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
  xhci: Clean up 32-bit build warnings.
  USB: update documentation for usbmon
  usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
  drivers/usb/class/cdc-acm.c: clear dangling pointer
  drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
  drivers/usb/host/isp1760-if.c: introduce missing kfree
  usb: option: add ZD Incorporated HSPA modem
  usb: ch9: fix up MaxStreams helper
  USB: usb-skeleton.c: cleanup open_count
  USB: usb-skeleton.c: fix open/disconnect race
  xhci: Properly handle COMP_2ND_BW_ERR
  USB: remove dead code from suspend/resume path
  USB: add quirk for another camera
  drivers: usb: wusbcore: Fix dependency for USB_WUSB
  xhci: Better debugging for critical host errors.
  xhci: Be less verbose during URB cancellation.
  xhci: Remove debugging about ring structure allocation.
  xhci: Remove debugging about toggling cycle bits.
  xhci: Remove debugging for individual transfers.
  ...
This commit is contained in:
Linus Torvalds 2012-01-09 12:09:47 -08:00
commit 55b81e6f27
203 changed files with 4992 additions and 3811 deletions

View File

@ -119,6 +119,31 @@ Description:
Write a 1 to force the device to disconnect
(equivalent to unplugging a wired USB device).
What: /sys/bus/usb/drivers/.../new_id
Date: October 2011
Contact: linux-usb@vger.kernel.org
Description:
Writing a device ID to this file will attempt to
dynamically add a new device ID to a USB device driver.
This may allow the driver to support more hardware than
was included in the driver's static device ID support
table at compile time. The format for the device ID is:
idVendor idProduct bInterfaceClass.
The vendor ID and device ID fields are required, the
interface class is optional.
Upon successfully adding an ID, the driver will probe
for the device and attempt to bind to it. For example:
# echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
What: /sys/bus/usb-serial/drivers/.../new_id
Date: October 2011
Contact: linux-usb@vger.kernel.org
Description:
For serial USB drivers, this attribute appears under the
extra bus folder "usb-serial" in sysfs; apart from that
difference, all descriptions from the entry
"/sys/bus/usb/drivers/.../new_id" apply.
What: /sys/bus/usb/drivers/.../remove_id
Date: November 2009
Contact: CHENG Renquan <rqcheng@smu.edu.sg>

View File

@ -523,6 +523,20 @@ Why: In 3.0, we can now autodetect internal 3G device and already have
information log when acer-wmi initial.
Who: Lee, Chun-Yi <jlee@novell.com>
---------------------------
What: /sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and
is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file.
When: 3.8
Why: The is_dualspeed file is superseded by maximum_speed in the same
directory and is_dualspeed line in device file is superseded by
max_speed line in the same file.
The maximum_speed/max_speed specifies maximum speed supported by UDC.
To check if dualspeeed is supported, check if the value is >= 3.
Various possible speeds are defined in <linux/usb/ch9.h>.
Who: Michal Nazarewicz <mina86@mina86.com>
----------------------------
What: The XFS nodelaylog mount option

View File

@ -2637,6 +2637,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
[USB] Start with the old device initialization
scheme (default 0 = off).
usbcore.usbfs_memory_mb=
[USB] Memory limit (in MB) for buffers allocated by
usbfs (default = 16, 0 = max = 2047).
usbcore.use_both_schemes=
[USB] Try the other device initialization scheme
if the first one fails (default 1 = enabled).

View File

@ -47,10 +47,11 @@ This allows to filter away annoying devices that talk continuously.
2. Find which bus connects to the desired device
Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
the device. Usually you do it by looking for the vendor string. If you have
many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
The T-line will have a bus number. Example:
Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
to the device. Usually you do it by looking for the vendor string. If you have
many similar devices, unplug one and compare the two
/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
Example:
T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
@ -58,7 +59,10 @@ P: Vendor=0557 ProdID=2004 Rev= 1.00
S: Manufacturer=ATEN
S: Product=UC100KM V2.00
Bus=03 means it's bus 3.
"Bus=03" means it's bus 3. Alternatively, you can look at the output from
"lsusb" and get the bus number from the appropriate line. Example:
Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
3. Start 'cat'

View File

@ -46,7 +46,7 @@ static struct device *mmc_device;
#define TUSB6010_GPIO_ENABLE 0
#define TUSB6010_DMACHAN 0x3f
#ifdef CONFIG_USB_MUSB_TUSB6010
#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/*
* Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
* 1.5 V voltage regulators of PM companion chip. Companion chip will then

View File

@ -50,6 +50,7 @@
#include <plat/nand.h>
#include <plat/sdhci.h>
#include <plat/udc.h>
#include <linux/platform_data/s3c-hsudc.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>

View File

@ -29,6 +29,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mmc/host.h>
#include <linux/ioport.h>
#include <linux/platform_data/s3c-hsudc.h>
#include <asm/irq.h>
#include <asm/pmu.h>

View File

@ -37,20 +37,7 @@ 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);
};
struct s3c24xx_hsudc_platdata;
extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);

View File

@ -212,11 +212,13 @@ kvp_respond_to_host(char *key, char *value, int error)
* The windows host expects the key/value pair to be encoded
* in utf16.
*/
keylen = utf8s_to_utf16s(key_name, strlen(key_name),
(wchar_t *)kvp_data->data.key);
keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
(wchar_t *) kvp_data->data.key,
HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
valuelen = utf8s_to_utf16s(value, strlen(value),
(wchar_t *)kvp_data->data.value);
valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
(wchar_t *) kvp_data->data.value,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
kvp_data->data.value_type = REG_SZ; /* all our values are strings */

View File

@ -6,6 +6,8 @@
obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/
@ -51,7 +53,6 @@ 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/
obj-$(CONFIG_USB_COMMON) += usb-common.o

View File

@ -225,21 +225,10 @@ static struct platform_driver c67x00_driver = {
.name = "c67x00",
},
};
MODULE_ALIAS("platform:c67x00");
static int __init c67x00_init(void)
{
return platform_driver_register(&c67x00_driver);
}
static void __exit c67x00_exit(void)
{
platform_driver_unregister(&c67x00_driver);
}
module_init(c67x00_init);
module_exit(c67x00_exit);
module_platform_driver(c67x00_driver);
MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:c67x00");

View File

@ -271,7 +271,6 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
if (int_status & SOFEOP_FLG(sie->sie_num)) {
c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
c67x00_sched_kick(c67x00);
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
}

View File

@ -58,12 +58,62 @@ static struct usb_driver acm_driver;
static struct tty_driver *acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS];
static DEFINE_MUTEX(open_mutex);
static DEFINE_MUTEX(acm_table_lock);
#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
/*
* acm_table accessors
*/
static const struct tty_port_operations acm_port_ops = {
};
/*
* Look up an ACM structure by index. If found and not disconnected, increment
* its refcount and return it with its mutex held.
*/
static struct acm *acm_get_by_index(unsigned index)
{
struct acm *acm;
mutex_lock(&acm_table_lock);
acm = acm_table[index];
if (acm) {
mutex_lock(&acm->mutex);
if (acm->disconnected) {
mutex_unlock(&acm->mutex);
acm = NULL;
} else {
tty_port_get(&acm->port);
mutex_unlock(&acm->mutex);
}
}
mutex_unlock(&acm_table_lock);
return acm;
}
/*
* Try to find an available minor number and if found, associate it with 'acm'.
*/
static int acm_alloc_minor(struct acm *acm)
{
int minor;
mutex_lock(&acm_table_lock);
for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
if (!acm_table[minor]) {
acm_table[minor] = acm;
break;
}
}
mutex_unlock(&acm_table_lock);
return minor;
}
/* Release the minor number associated with 'acm'. */
static void acm_release_minor(struct acm *acm)
{
mutex_lock(&acm_table_lock);
acm_table[acm->minor] = NULL;
mutex_unlock(&acm_table_lock);
}
/*
* Functions for ACM control messages.
@ -267,9 +317,6 @@ static void acm_ctrl_irq(struct urb *urb)
goto exit;
}
if (!ACM_READY(acm))
goto exit;
usb_mark_last_busy(acm->dev);
data = (unsigned char *)(dr + 1);
@ -429,8 +476,7 @@ static void acm_write_bulk(struct urb *urb)
spin_lock_irqsave(&acm->write_lock, flags);
acm_write_done(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags);
if (ACM_READY(acm))
schedule_work(&acm->work);
schedule_work(&acm->work);
}
static void acm_softint(struct work_struct *work)
@ -440,8 +486,6 @@ static void acm_softint(struct work_struct *work)
dev_vdbg(&acm->data->dev, "%s\n", __func__);
if (!ACM_READY(acm))
return;
tty = tty_port_tty_get(&acm->port);
if (!tty)
return;
@ -453,93 +497,122 @@ static void acm_softint(struct work_struct *work)
* TTY handlers
*/
static int acm_tty_open(struct tty_struct *tty, struct file *filp)
static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct acm *acm;
int rv = -ENODEV;
int retval;
mutex_lock(&open_mutex);
dev_dbg(tty->dev, "%s\n", __func__);
acm = acm_table[tty->index];
if (!acm || !acm->dev)
goto out;
else
rv = 0;
acm = acm_get_by_index(tty->index);
if (!acm)
return -ENODEV;
retval = tty_init_termios(tty);
if (retval)
goto error_init_termios;
tty->driver_data = acm;
/* Final install (we use the default method) */
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[tty->index] = tty;
return 0;
error_init_termios:
tty_port_put(&acm->port);
return retval;
}
static int acm_tty_open(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = tty->driver_data;
dev_dbg(tty->dev, "%s\n", __func__);
return tty_port_open(&acm->port, tty, filp);
}
static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct acm *acm = container_of(port, struct acm, port);
int retval = -ENODEV;
dev_dbg(&acm->control->dev, "%s\n", __func__);
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
tty->driver_data = acm;
tty_port_tty_set(&acm->port, tty);
if (usb_autopm_get_interface(acm->control) < 0)
goto early_bail;
else
acm->control->needs_remote_wakeup = 1;
mutex_lock(&acm->mutex);
if (acm->port.count++) {
mutex_unlock(&acm->mutex);
usb_autopm_put_interface(acm->control);
goto out;
}
if (acm->disconnected)
goto disconnected;
retval = usb_autopm_get_interface(acm->control);
if (retval)
goto error_get_interface;
/*
* FIXME: Why do we need this? Allocating 64K of physically contiguous
* memory is really nasty...
*/
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
acm->control->needs_remote_wakeup = 1;
acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
dev_err(&acm->control->dev,
"%s - usb_submit_urb(ctrl irq) failed\n", __func__);
goto bail_out;
goto error_submit_urb;
}
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
if (acm_set_control(acm, acm->ctrlout) < 0 &&
(acm->ctrl_caps & USB_CDC_CAP_LINE))
goto bail_out;
goto error_set_control;
usb_autopm_put_interface(acm->control);
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);
goto error_submit_read_urbs;
mutex_unlock(&acm->mutex);
out:
mutex_unlock(&open_mutex);
return rv;
bail_out:
acm->port.count--;
mutex_unlock(&acm->mutex);
return 0;
error_submit_read_urbs:
acm->ctrlout = 0;
acm_set_control(acm, acm->ctrlout);
error_set_control:
usb_kill_urb(acm->ctrlurb);
error_submit_urb:
usb_autopm_put_interface(acm->control);
early_bail:
mutex_unlock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
return -EIO;
error_get_interface:
disconnected:
mutex_unlock(&acm->mutex);
return retval;
}
static void acm_tty_unregister(struct acm *acm)
static void acm_port_destruct(struct tty_port *port)
{
int i;
struct acm *acm = container_of(port, struct acm, port);
dev_dbg(&acm->control->dev, "%s\n", __func__);
tty_unregister_device(acm_tty_driver, acm->minor);
acm_release_minor(acm);
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 < acm->rx_buflimit; i++)
usb_free_urb(acm->read_urbs[i]);
kfree(acm->country_codes);
kfree(acm);
}
static void acm_port_down(struct acm *acm)
static void acm_port_shutdown(struct tty_port *port)
{
struct acm *acm = container_of(port, struct acm, port);
int i;
if (acm->dev) {
dev_dbg(&acm->control->dev, "%s\n", __func__);
mutex_lock(&acm->mutex);
if (!acm->disconnected) {
usb_autopm_get_interface(acm->control);
acm_set_control(acm, acm->ctrlout = 0);
usb_kill_urb(acm->ctrlurb);
@ -550,40 +623,28 @@ static void acm_port_down(struct acm *acm)
acm->control->needs_remote_wakeup = 0;
usb_autopm_put_interface(acm->control);
}
mutex_unlock(&acm->mutex);
}
static void acm_tty_cleanup(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
dev_dbg(&acm->control->dev, "%s\n", __func__);
tty_port_put(&acm->port);
}
static void acm_tty_hangup(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
dev_dbg(&acm->control->dev, "%s\n", __func__);
tty_port_hangup(&acm->port);
mutex_lock(&open_mutex);
acm_port_down(acm);
mutex_unlock(&open_mutex);
}
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = tty->driver_data;
/* Perform the closing process and see if we need to do the hardware
shutdown */
if (!acm)
return;
mutex_lock(&open_mutex);
if (tty_port_close_start(&acm->port, tty, filp) == 0) {
if (!acm->dev) {
tty_port_tty_set(&acm->port, NULL);
acm_tty_unregister(acm);
tty->driver_data = NULL;
}
mutex_unlock(&open_mutex);
return;
}
acm_port_down(acm);
tty_port_close_end(&acm->port, tty);
tty_port_tty_set(&acm->port, NULL);
mutex_unlock(&open_mutex);
dev_dbg(&acm->control->dev, "%s\n", __func__);
tty_port_close(&acm->port, tty, filp);
}
static int acm_tty_write(struct tty_struct *tty,
@ -595,8 +656,6 @@ static int acm_tty_write(struct tty_struct *tty,
int wbn;
struct acm_wb *wb;
if (!ACM_READY(acm))
return -EINVAL;
if (!count)
return 0;
@ -625,8 +684,6 @@ static int acm_tty_write(struct tty_struct *tty,
static int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
/*
* Do not let the line discipline to know that we have a reserve,
* or it might get too enthusiastic.
@ -637,7 +694,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
/*
* if the device was unplugged then any remaining characters fell out
* of the connector ;)
*/
if (acm->disconnected)
return 0;
/*
* This is inaccurate (overcounts), but it works.
@ -649,9 +710,6 @@ static void acm_tty_throttle(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return;
spin_lock_irq(&acm->read_lock);
acm->throttle_req = 1;
spin_unlock_irq(&acm->read_lock);
@ -662,9 +720,6 @@ 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_irq(&acm->read_lock);
was_throttled = acm->throttled;
acm->throttled = 0;
@ -679,8 +734,7 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
{
struct acm *acm = tty->driver_data;
int retval;
if (!ACM_READY(acm))
return -EINVAL;
retval = acm_send_break(acm, state ? 0xffff : 0);
if (retval < 0)
dev_dbg(&acm->control->dev, "%s - send break failed\n",
@ -692,9 +746,6 @@ static int acm_tty_tiocmget(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
(acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
(acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
@ -709,9 +760,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
struct acm *acm = tty->driver_data;
unsigned int newctrl;
if (!ACM_READY(acm))
return -EINVAL;
newctrl = acm->ctrlout;
set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
(set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
@ -728,11 +776,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
static int acm_tty_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
return -ENOIOCTLCMD;
}
@ -756,9 +799,6 @@ static void acm_tty_set_termios(struct tty_struct *tty,
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
if (!ACM_READY(acm))
return;
newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
newline.bParityType = termios->c_cflag & PARENB ?
@ -788,6 +828,12 @@ static void acm_tty_set_termios(struct tty_struct *tty,
}
}
static const struct tty_port_operations acm_port_ops = {
.shutdown = acm_port_shutdown,
.activate = acm_port_activate,
.destruct = acm_port_destruct,
};
/*
* USB probe and disconnect routines.
*/
@ -1047,12 +1093,6 @@ skip_normal_probe:
}
made_compressed_probe:
dev_dbg(&intf->dev, "interfaces are valid\n");
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (minor == ACM_TTY_MINORS) {
dev_err(&intf->dev, "no more free acm devices\n");
return -ENODEV;
}
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
if (acm == NULL) {
@ -1060,6 +1100,13 @@ made_compressed_probe:
goto alloc_fail;
}
minor = acm_alloc_minor(acm);
if (minor == ACM_TTY_MINORS) {
dev_err(&intf->dev, "no more free acm devices\n");
kfree(acm);
return -ENODEV;
}
ctrlsize = usb_endpoint_maxp(epctrl);
readsize = usb_endpoint_maxp(epread) *
(quirks == SINGLE_RX_URB ? 1 : 2);
@ -1183,6 +1230,8 @@ made_compressed_probe:
i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
if (i < 0) {
kfree(acm->country_codes);
acm->country_codes = NULL;
acm->country_code_size = 0;
goto skip_countries;
}
@ -1191,6 +1240,8 @@ made_compressed_probe:
if (i < 0) {
device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
kfree(acm->country_codes);
acm->country_codes = NULL;
acm->country_code_size = 0;
goto skip_countries;
}
}
@ -1218,8 +1269,6 @@ skip_countries:
usb_get_intf(control_interface);
tty_register_device(acm_tty_driver, minor, &control_interface->dev);
acm_table[minor] = acm;
return 0;
alloc_fail7:
for (i = 0; i < ACM_NW; i++)
@ -1234,6 +1283,7 @@ alloc_fail5:
alloc_fail4:
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2:
acm_release_minor(acm);
kfree(acm);
alloc_fail:
return -ENOMEM;
@ -1259,12 +1309,16 @@ static void acm_disconnect(struct usb_interface *intf)
struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct tty_struct *tty;
int i;
dev_dbg(&intf->dev, "%s\n", __func__);
/* sibling interface is already cleaning up */
if (!acm)
return;
mutex_lock(&open_mutex);
mutex_lock(&acm->mutex);
acm->disconnected = true;
if (acm->country_codes) {
device_remove_file(&acm->control->dev,
&dev_attr_wCountryCodes);
@ -1272,33 +1326,32 @@ static void acm_disconnect(struct usb_interface *intf)
&dev_attr_iCountryCodeRelDate);
}
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
acm->dev = NULL;
usb_set_intfdata(acm->control, NULL);
usb_set_intfdata(acm->data, NULL);
mutex_unlock(&acm->mutex);
tty = tty_port_tty_get(&acm->port);
if (tty) {
tty_vhangup(tty);
tty_kref_put(tty);
}
stop_data_traffic(acm);
usb_free_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_free_urb(acm->read_urbs[i]);
acm_write_buffers_free(acm);
usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
acm->ctrl_dma);
usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
acm_read_buffers_free(acm);
if (!acm->combined_interfaces)
usb_driver_release_interface(&acm_driver, intf == acm->control ?
acm->data : acm->control);
if (acm->port.count == 0) {
acm_tty_unregister(acm);
mutex_unlock(&open_mutex);
return;
}
mutex_unlock(&open_mutex);
tty = tty_port_tty_get(&acm->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
tty_port_put(&acm->port);
}
#ifdef CONFIG_PM
@ -1325,16 +1378,10 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
if (cnt)
return 0;
/*
we treat opened interfaces differently,
we must guard against open
*/
mutex_lock(&acm->mutex);
if (acm->port.count)
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
stop_data_traffic(acm);
mutex_unlock(&acm->mutex);
return 0;
}
@ -1353,8 +1400,7 @@ static int acm_resume(struct usb_interface *intf)
if (cnt)
return 0;
mutex_lock(&acm->mutex);
if (acm->port.count) {
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
spin_lock_irq(&acm->write_lock);
@ -1378,7 +1424,6 @@ static int acm_resume(struct usb_interface *intf)
}
err_out:
mutex_unlock(&acm->mutex);
return rv;
}
@ -1387,15 +1432,14 @@ static int acm_reset_resume(struct usb_interface *intf)
struct acm *acm = usb_get_intfdata(intf);
struct tty_struct *tty;
mutex_lock(&acm->mutex);
if (acm->port.count) {
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
tty = tty_port_tty_get(&acm->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
mutex_unlock(&acm->mutex);
return acm_resume(intf);
}
@ -1604,8 +1648,10 @@ static struct usb_driver acm_driver = {
*/
static const struct tty_operations acm_ops = {
.install = acm_tty_install,
.open = acm_tty_open,
.close = acm_tty_close,
.cleanup = acm_tty_cleanup,
.hangup = acm_tty_hangup,
.write = acm_tty_write,
.write_room = acm_tty_write_room,

View File

@ -101,6 +101,7 @@ struct acm {
int transmitting;
spinlock_t write_lock;
struct mutex mutex;
bool disconnected;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */

View File

@ -86,6 +86,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
unsigned int mem_usage;
int status;
u32 secid;
u8 bulk_addr;
@ -108,8 +109,44 @@ enum snoop_when {
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
#define MAX_USBFS_BUFFER_SIZE 16384
/* Limit on the total amount of memory we can allocate for transfers */
static unsigned usbfs_memory_mb = 16;
module_param(usbfs_memory_mb, uint, 0644);
MODULE_PARM_DESC(usbfs_memory_mb,
"maximum MB allowed for usbfs buffers (0 = no limit)");
/* Hard limit, necessary to avoid aithmetic overflow */
#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
static atomic_t usbfs_memory_usage; /* Total memory currently allocated */
/* Check whether it's okay to allocate more memory for a transfer */
static int usbfs_increase_memory_usage(unsigned amount)
{
unsigned lim;
/*
* Convert usbfs_memory_mb to bytes, avoiding overflows.
* 0 means use the hard limit (effectively unlimited).
*/
lim = ACCESS_ONCE(usbfs_memory_mb);
if (lim == 0 || lim > (USBFS_XFER_MAX >> 20))
lim = USBFS_XFER_MAX;
else
lim <<= 20;
atomic_add(amount, &usbfs_memory_usage);
if (atomic_read(&usbfs_memory_usage) <= lim)
return 0;
atomic_sub(amount, &usbfs_memory_usage);
return -ENOMEM;
}
/* Memory for a transfer is being deallocated */
static void usbfs_decrease_memory_usage(unsigned amount)
{
atomic_sub(amount, &usbfs_memory_usage);
}
static int connected(struct dev_state *ps)
{
@ -249,10 +286,12 @@ static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as)
{
put_pid(as->pid);
put_cred(as->cred);
if (as->cred)
put_cred(as->cred);
kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
usbfs_decrease_memory_usage(as->mem_usage);
kfree(as);
}
@ -792,9 +831,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
if (wLength > PAGE_SIZE)
return -EINVAL;
ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
sizeof(struct usb_ctrlrequest));
if (ret)
return ret;
tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!tbuf)
return -ENOMEM;
if (!tbuf) {
ret = -ENOMEM;
goto done;
}
tmo = ctrl.timeout;
snoop(&dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
@ -806,8 +851,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (ctrl.bRequestType & 0x80) {
if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EINVAL;
ret = -EINVAL;
goto done;
}
pipe = usb_rcvctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
@ -821,15 +866,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
tbuf, max(i, 0));
if ((i > 0) && ctrl.wLength) {
if (copy_to_user(ctrl.data, tbuf, i)) {
free_page((unsigned long)tbuf);
return -EFAULT;
ret = -EFAULT;
goto done;
}
}
} else {
if (ctrl.wLength) {
if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EFAULT;
ret = -EFAULT;
goto done;
}
}
pipe = usb_sndctrlpipe(dev, 0);
@ -843,14 +888,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
}
free_page((unsigned long)tbuf);
if (i < 0 && i != -EPIPE) {
dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
"failed cmd %s rqt %u rq %u len %u ret %d\n",
current->comm, ctrl.bRequestType, ctrl.bRequest,
ctrl.wLength, i);
}
return i;
ret = i;
done:
free_page((unsigned long) tbuf);
usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
sizeof(struct usb_ctrlrequest));
return ret;
}
static int proc_bulk(struct dev_state *ps, void __user *arg)
@ -877,15 +926,20 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
return -EINVAL;
len1 = bulk.len;
if (len1 > MAX_USBFS_BUFFER_SIZE)
if (len1 >= USBFS_XFER_MAX)
return -EINVAL;
if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
return -ENOMEM;
ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
if (ret)
return ret;
if (!(tbuf = kmalloc(len1, GFP_KERNEL))) {
ret = -ENOMEM;
goto done;
}
tmo = bulk.timeout;
if (bulk.ep & 0x80) {
if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
kfree(tbuf);
return -EINVAL;
ret = -EINVAL;
goto done;
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
@ -896,15 +950,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf);
return -EFAULT;
ret = -EFAULT;
goto done;
}
}
} else {
if (len1) {
if (copy_from_user(tbuf, bulk.data, len1)) {
kfree(tbuf);
return -EFAULT;
ret = -EFAULT;
goto done;
}
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
@ -914,10 +968,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
}
ret = (i < 0 ? i : len2);
done:
kfree(tbuf);
if (i < 0)
return i;
return len2;
usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
return ret;
}
static int proc_resetep(struct dev_state *ps, void __user *arg)
@ -1062,7 +1117,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
{
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_host_endpoint *ep;
struct async *as;
struct async *as = NULL;
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
@ -1095,32 +1150,30 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
}
if (!ep)
return -ENOENT;
u = 0;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet,
* max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 ||
uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
/* min 8 byte setup packet */
if (uurb->buffer_length < 8)
return -EINVAL;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!dr)
return -ENOMEM;
if (copy_from_user(dr, uurb->buffer, 8)) {
kfree(dr);
return -EFAULT;
ret = -EFAULT;
goto error;
}
if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
kfree(dr);
return -EINVAL;
ret = -EINVAL;
goto error;
}
ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
le16_to_cpup(&dr->wIndex));
if (ret) {
kfree(dr);
return ret;
}
if (ret)
goto error;
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
@ -1138,6 +1191,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
__le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
u = sizeof(struct usb_ctrlrequest);
break;
case USBDEVFS_URB_TYPE_BULK:
@ -1151,8 +1205,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
goto interrupt_urb;
}
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
@ -1160,8 +1212,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL;
interrupt_urb:
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
case USBDEVFS_URB_TYPE_ISO:
@ -1176,50 +1226,53 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
return -ENOMEM;
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
kfree(isopkt);
return -EFAULT;
ret = -EFAULT;
goto error;
}
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
/* arbitrary limit,
* sufficient for USB 2.0 high-bandwidth iso */
if (isopkt[u].length > 8192) {
kfree(isopkt);
return -EINVAL;
ret = -EINVAL;
goto error;
}
totlen += isopkt[u].length;
}
/* 3072 * 64 microframes */
if (totlen > 196608) {
kfree(isopkt);
return -EINVAL;
}
u *= sizeof(struct usb_iso_packet_descriptor);
uurb->buffer_length = totlen;
break;
default:
return -EINVAL;
}
if (uurb->buffer_length >= USBFS_XFER_MAX) {
ret = -EINVAL;
goto error;
}
if (uurb->buffer_length > 0 &&
!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length)) {
kfree(isopkt);
kfree(dr);
return -EFAULT;
ret = -EFAULT;
goto error;
}
as = alloc_async(uurb->number_of_packets);
if (!as) {
kfree(isopkt);
kfree(dr);
return -ENOMEM;
ret = -ENOMEM;
goto error;
}
u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
ret = usbfs_increase_memory_usage(u);
if (ret)
goto error;
as->mem_usage = u;
if (uurb->buffer_length > 0) {
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
GFP_KERNEL);
if (!as->urb->transfer_buffer) {
kfree(isopkt);
kfree(dr);
free_async(as);
return -ENOMEM;
ret = -ENOMEM;
goto error;
}
/* Isochronous input data may end up being discontiguous
* if some of the packets are short. Clear the buffer so
@ -1253,6 +1306,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char *)dr;
dr = NULL;
as->urb->start_frame = uurb->start_frame;
as->urb->number_of_packets = uurb->number_of_packets;
if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
@ -1268,6 +1322,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
totlen += isopkt[u].length;
}
kfree(isopkt);
isopkt = NULL;
as->ps = ps;
as->userurb = arg;
if (is_in && uurb->buffer_length > 0)
@ -1282,8 +1337,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if (!is_in && uurb->buffer_length > 0) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
uurb->buffer_length)) {
free_async(as);
return -EFAULT;
ret = -EFAULT;
goto error;
}
}
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
@ -1329,10 +1384,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
0, ret, COMPLETE, NULL, 0);
async_removepending(as);
free_async(as);
return ret;
goto error;
}
return 0;
error:
kfree(isopkt);
kfree(dr);
if (as)
free_async(as);
return ret;
}
static int proc_submiturb(struct dev_state *ps, void __user *arg)

View File

@ -45,10 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
struct usb_dynid *dynid;
u32 idVendor = 0;
u32 idProduct = 0;
unsigned int bInterfaceClass = 0;
int fields = 0;
int retval = 0;
fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
&bInterfaceClass);
if (fields < 2)
return -EINVAL;
@ -60,6 +62,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
dynid->id.idVendor = idVendor;
dynid->id.idProduct = idProduct;
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
if (fields == 3) {
dynid->id.bInterfaceClass = (u8)bInterfaceClass;
dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
}
spin_lock(&dynids->lock);
list_add_tail(&dynid->node, &dynids->list);
@ -1073,17 +1079,10 @@ static int usb_suspend_interface(struct usb_device *udev,
goto done;
driver = to_usb_driver(intf->dev.driver);
if (driver->suspend) {
status = driver->suspend(intf, msg);
if (status && !PMSG_IS_AUTO(msg))
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
/* Later we will unbind the driver and reprobe */
intf->needs_binding = 1;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"suspend", driver->name);
}
/* at this time we know the driver supports suspend */
status = driver->suspend(intf, msg);
if (status && !PMSG_IS_AUTO(msg))
dev_err(&intf->dev, "suspend error %d\n", status);
done:
dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
@ -1132,16 +1131,9 @@ static int usb_resume_interface(struct usb_device *udev,
"reset_resume", driver->name);
}
} else {
if (driver->resume) {
status = driver->resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"resume", status);
} else {
intf->needs_binding = 1;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"resume", driver->name);
}
status = driver->resume(intf);
if (status)
dev_err(&intf->dev, "resume error %d\n", status);
}
done:

View File

@ -453,10 +453,6 @@ static int resume_common(struct device *dev, int event)
pci_set_master(pci_dev);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
if (event != PM_EVENT_AUTO_RESUME)
wait_for_companions(pci_dev, hcd);

View File

@ -658,7 +658,7 @@ error:
len > offsetof(struct usb_device_descriptor,
bDeviceProtocol))
((struct usb_device_descriptor *) ubuf)->
bDeviceProtocol = 1;
bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
}
/* any errors get returned through the urb completion */
@ -1168,20 +1168,6 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
if (urb->unlinked)
return -EBUSY;
urb->unlinked = status;
/* IRQ setup can easily be broken so that USB controllers
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {
dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
}
return 0;
}
EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
@ -1412,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
ret = -EAGAIN;
else
urb->transfer_flags |= URB_DMA_MAP_SG;
if (n != urb->num_sgs) {
urb->num_sgs = n;
urb->num_mapped_sgs = n;
if (n != urb->num_sgs)
urb->transfer_flags |=
URB_DMA_SG_COMBINED;
}
} else if (urb->sg) {
struct scatterlist *sg = urb->sg;
urb->transfer_dma = dma_map_page(
@ -2148,16 +2133,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
*/
local_irq_save(flags);
if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
else if (hcd->driver->irq(hcd) == IRQ_NONE)
rc = IRQ_NONE;
} else {
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->shared_hcd)
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
else
rc = IRQ_HANDLED;
}
local_irq_restore(flags);
return rc;

View File

@ -84,7 +84,7 @@ struct usb_hub {
static inline int hub_is_superspeed(struct usb_device *hdev)
{
return (hdev->descriptor.bDeviceProtocol == 3);
return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
}
/* Protect struct usb_device->state and ->children members
@ -1041,58 +1041,58 @@ static int hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "standalone hub\n");
switch (wHubCharacteristics & HUB_CHAR_LPSM) {
case 0x00:
dev_dbg(hub_dev, "ganged power switching\n");
break;
case 0x01:
dev_dbg(hub_dev, "individual port power switching\n");
break;
case 0x02:
case 0x03:
dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
break;
case HUB_CHAR_COMMON_LPSM:
dev_dbg(hub_dev, "ganged power switching\n");
break;
case HUB_CHAR_INDV_PORT_LPSM:
dev_dbg(hub_dev, "individual port power switching\n");
break;
case HUB_CHAR_NO_LPSM:
case HUB_CHAR_LPSM:
dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
break;
}
switch (wHubCharacteristics & HUB_CHAR_OCPM) {
case 0x00:
dev_dbg(hub_dev, "global over-current protection\n");
break;
case 0x08:
dev_dbg(hub_dev, "individual port over-current protection\n");
break;
case 0x10:
case 0x18:
dev_dbg(hub_dev, "no over-current protection\n");
break;
case HUB_CHAR_COMMON_OCPM:
dev_dbg(hub_dev, "global over-current protection\n");
break;
case HUB_CHAR_INDV_PORT_OCPM:
dev_dbg(hub_dev, "individual port over-current protection\n");
break;
case HUB_CHAR_NO_OCPM:
case HUB_CHAR_OCPM:
dev_dbg(hub_dev, "no over-current protection\n");
break;
}
spin_lock_init (&hub->tt.lock);
INIT_LIST_HEAD (&hub->tt.clear_list);
INIT_WORK(&hub->tt.clear_work, hub_tt_work);
switch (hdev->descriptor.bDeviceProtocol) {
case 0:
break;
case 1:
dev_dbg(hub_dev, "Single TT\n");
hub->tt.hub = hdev;
break;
case 2:
ret = usb_set_interface(hdev, 0, 1);
if (ret == 0) {
dev_dbg(hub_dev, "TT per port\n");
hub->tt.multi = 1;
} else
dev_err(hub_dev, "Using single TT (err %d)\n",
ret);
hub->tt.hub = hdev;
break;
case 3:
/* USB 3.0 hubs don't have a TT */
break;
default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
hdev->descriptor.bDeviceProtocol);
break;
case USB_HUB_PR_FS:
break;
case USB_HUB_PR_HS_SINGLE_TT:
dev_dbg(hub_dev, "Single TT\n");
hub->tt.hub = hdev;
break;
case USB_HUB_PR_HS_MULTI_TT:
ret = usb_set_interface(hdev, 0, 1);
if (ret == 0) {
dev_dbg(hub_dev, "TT per port\n");
hub->tt.multi = 1;
} else
dev_err(hub_dev, "Using single TT (err %d)\n",
ret);
hub->tt.hub = hdev;
break;
case USB_HUB_PR_SS:
/* USB 3.0 hubs don't have a TT */
break;
default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
hdev->descriptor.bDeviceProtocol);
break;
}
/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
@ -1360,7 +1360,6 @@ descriptor_error:
return -ENODEV;
}
/* No BKL needed */
static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{

View File

@ -117,9 +117,12 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
/* Guillemot Webcam Hercules Dualpix Exchange*/
/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
/* Guillemot Webcam Hercules Dualpix Exchange*/
{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },

View File

@ -132,20 +132,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
for_devices;
}
/* translate USB error codes to codes user space understands */
static inline int usb_translate_errors(int error_code)
{
switch (error_code) {
case 0:
case -ENOMEM:
case -ENODEV:
return error_code;
default:
return -EIO;
}
}
/* for labeling diagnostics */
extern const char *usbcore_name;

View File

@ -1,7 +1,10 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET)
depends on (USB && USB_GADGET)
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
select USB_XHCI_PLATFORM
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.

View File

@ -4,10 +4,8 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
ifneq ($(CONFIG_USB_GADGET_DWC3),)
dwc3-y += gadget.o ep0.o
endif
dwc3-y += host.o
dwc3-y += gadget.o ep0.o
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o

View File

@ -59,6 +59,60 @@
#include "debug.h"
static char *maximum_speed = "super";
module_param(maximum_speed, charp, 0);
MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
/* -------------------------------------------------------------------------- */
#define DWC3_DEVS_POSSIBLE 32
static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
int dwc3_get_device_id(void)
{
int id;
again:
id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE);
if (id < DWC3_DEVS_POSSIBLE) {
int old;
old = test_and_set_bit(id, dwc3_devs);
if (old)
goto again;
} else {
pr_err("dwc3: no space for new device\n");
id = -ENOMEM;
}
return 0;
}
EXPORT_SYMBOL_GPL(dwc3_get_device_id);
void dwc3_put_device_id(int id)
{
int ret;
if (id < 0)
return;
ret = test_bit(id, dwc3_devs);
WARN(!ret, "dwc3: ID %d not in use\n", id);
clear_bit(id, dwc3_devs);
}
EXPORT_SYMBOL_GPL(dwc3_put_device_id);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
/**
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure
@ -150,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
struct dwc3_event_buffer *evt;
int i;
for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
for (i = 0; i < dwc->num_event_buffers; i++) {
evt = dwc->ev_buffs[i];
if (evt) {
dwc3_free_one_event_buffer(dwc, evt);
@ -162,17 +216,25 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
/**
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
* @dwc: Pointer to out controller context structure
* @num: number of event buffers to allocate
* @length: size of event buffer
*
* Returns 0 on success otherwise negative errno. In error the case, dwc
* may contain some buffers allocated but not all which were requested.
*/
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
unsigned length)
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
{
int num;
int i;
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
dwc->num_event_buffers = num;
dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL);
if (!dwc->ev_buffs) {
dev_err(dwc->dev, "can't allocate event buffers array\n");
return -ENOMEM;
}
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
@ -198,7 +260,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
for (n = 0; n < dwc->num_event_buffers; n++) {
evt = dwc->ev_buffs[n];
dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
evt->buf, (unsigned long long) evt->dma,
@ -221,7 +283,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
for (n = 0; n < dwc->num_event_buffers; n++) {
evt = dwc->ev_buffs[n];
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
@ -285,8 +347,32 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
cpu_relax();
} while (true);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
DWC3_EVENT_BUFFERS_SIZE);
dwc3_cache_hwparams(dwc);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN(3);
reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break;
default:
dev_dbg(dwc->dev, "No power optimization available\n");
}
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* when The device fails to connect at SuperSpeed
* and falls back to high-speed mode which causes
* the device to enter in a Connect/Disconnect loop
*/
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
ret = -ENOMEM;
@ -299,8 +385,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
goto err1;
}
dwc3_cache_hwparams(dwc);
return 0;
err1:
@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
static int __devinit dwc3_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
struct resource *res;
struct dwc3 *dwc;
void __iomem *regs;
unsigned int features = id->driver_data;
int ret = -ENOMEM;
int irq;
void __iomem *regs;
void *mem;
u8 mode;
mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
dev_err(&pdev->dev, "not enough memory\n");
@ -343,6 +429,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
goto err1;
}
dwc->res = res;
res = request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev));
if (!res) {
@ -370,6 +458,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc->dev = &pdev->dev;
dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
else if (!strncmp("high", maximum_speed, 4))
dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
else if (!strncmp("full", maximum_speed, 4))
dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
else if (!strncmp("low", maximum_speed, 3))
dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
else
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_forbid(&pdev->dev);
@ -380,13 +479,44 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
goto err3;
}
if (features & DWC3_HAS_PERIPHERAL) {
mode = DWC3_MODE(dwc->hwparams.hwparams0);
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialized gadget\n");
dev_err(&pdev->dev, "failed to initialize gadget\n");
goto err4;
}
break;
case DWC3_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize host\n");
goto err4;
}
break;
case DWC3_MODE_DRD:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize host\n");
goto err4;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize gadget\n");
goto err4;
}
break;
default:
dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
goto err4;
}
dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
@ -399,8 +529,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
return 0;
err5:
if (features & DWC3_HAS_PERIPHERAL)
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
break;
case DWC3_MODE_HOST:
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
default:
/* do nothing */
break;
}
err4:
dwc3_core_exit(dwc);
@ -420,10 +563,8 @@ err0:
static int __devexit dwc3_remove(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
struct dwc3 *dwc = platform_get_drvdata(pdev);
struct resource *res;
unsigned int features = id->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -432,8 +573,21 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
dwc3_debugfs_exit(dwc);
if (features & DWC3_HAS_PERIPHERAL)
switch (dwc->mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
break;
case DWC3_MODE_HOST:
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
default:
/* do nothing */
break;
}
dwc3_core_exit(dwc);
release_mem_region(res->start, resource_size(res));
@ -443,30 +597,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id dwc3_id_table[] __devinitconst = {
{
.name = "dwc3-omap",
.driver_data = (DWC3_HAS_PERIPHERAL
| DWC3_HAS_XHCI
| DWC3_HAS_OTG),
},
{
.name = "dwc3-pci",
.driver_data = DWC3_HAS_PERIPHERAL,
},
{ }, /* Terminating Entry */
};
MODULE_DEVICE_TABLE(platform, dwc3_id_table);
static struct platform_driver dwc3_driver = {
.probe = dwc3_probe,
.remove = __devexit_p(dwc3_remove),
.driver = {
.name = "dwc3",
},
.id_table = dwc3_id_table,
};
MODULE_ALIAS("platform:dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");

View File

@ -41,6 +41,7 @@
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
@ -52,7 +53,6 @@
/* Global constants */
#define DWC3_ENDPOINTS_NUM 32
#define DWC3_EVENT_BUFFERS_NUM 2
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
#define DWC3_EVENT_TYPE_MASK 0xfe
@ -153,6 +153,7 @@
#define DWC3_GCTL_CLK_PIPEHALF (2)
#define DWC3_GCTL_CLK_MASK (3)
#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12)
#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
#define DWC3_GCTL_PRTCAP_HOST 1
#define DWC3_GCTL_PRTCAP_DEVICE 2
@ -347,6 +348,7 @@ struct dwc3_ep {
u32 free_slot;
u32 busy_slot;
const struct usb_endpoint_descriptor *desc;
const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc;
unsigned flags;
@ -536,6 +538,31 @@ struct dwc3_hwparams {
u32 hwparams8;
};
/* HWPARAMS0 */
#define DWC3_MODE(n) ((n) & 0x7)
#define DWC3_MODE_DEVICE 0
#define DWC3_MODE_HOST 1
#define DWC3_MODE_DRD 2
#define DWC3_MODE_HUB 3
/* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
u8 epnum;
struct dwc3_trb_hw *trb;
dma_addr_t trb_dma;
unsigned direction:1;
unsigned mapped:1;
unsigned queued:1;
};
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
@ -549,19 +576,24 @@ struct dwc3_hwparams {
* @ep0_bounce_addr: dma address of ep0_bounce
* @lock: for synchronizing
* @dev: pointer to our struct device
* @xhci: pointer to our xHCI child
* @event_buffer_list: a list of event buffers
* @gadget: device side representation of the peripheral controller
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
* @irq: IRQ number
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @mode: mode of operation
* @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup
* @ep0_status_pending: ep0 status response without a req is pending
* @ep0_bounced: true when we used bounce buffer
* @ep0_expect_in: true when we expect a DATA IN transfer
* @start_config_issued: true when StartConfig command has been issued
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@ -579,12 +611,15 @@ struct dwc3 {
dma_addr_t ep0_trb_addr;
dma_addr_t setup_buf_addr;
dma_addr_t ep0_bounce_addr;
struct usb_request ep0_usb_req;
struct dwc3_request ep0_usb_req;
/* device lock */
spinlock_t lock;
struct device *dev;
struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
struct platform_device *xhci;
struct resource *res;
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
struct usb_gadget gadget;
@ -595,7 +630,11 @@ struct dwc3 {
int irq;
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
u32 revision;
u32 mode;
#define DWC3_REVISION_173A 0x5533173a
#define DWC3_REVISION_175A 0x5533175a
@ -607,10 +646,11 @@ struct dwc3 {
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
unsigned ep0_status_pending:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
unsigned start_config_issued:1;
unsigned setup_packet_pending:1;
unsigned delayed_status:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@ -765,4 +805,16 @@ union dwc3_event {
#define DWC3_HAS_XHCI BIT(1)
#define DWC3_HAS_OTG BIT(3)
/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
#endif /* __DRIVERS_USB_DWC3_CORE_H */

View File

@ -44,12 +44,12 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include "core.h"
#include "gadget.h"
#include "io.h"
#include "debug.h"
#define dump_register(nm) \
{ \
@ -395,6 +395,75 @@ static const struct file_operations dwc3_regdump_fops = {
.release = single_release,
};
static int dwc3_mode_show(struct seq_file *s, void *unused)
{
struct dwc3 *dwc = s->private;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
spin_unlock_irqrestore(&dwc->lock, flags);
switch (DWC3_GCTL_PRTCAP(reg)) {
case DWC3_GCTL_PRTCAP_HOST:
seq_printf(s, "host\n");
break;
case DWC3_GCTL_PRTCAP_DEVICE:
seq_printf(s, "device\n");
break;
case DWC3_GCTL_PRTCAP_OTG:
seq_printf(s, "OTG\n");
break;
default:
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
}
return 0;
}
static int dwc3_mode_open(struct inode *inode, struct file *file)
{
return single_open(file, dwc3_mode_show, inode->i_private);
}
static ssize_t dwc3_mode_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
unsigned long flags;
u32 mode = 0;
char buf[32];
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (!strncmp(buf, "host", 4))
mode |= DWC3_GCTL_PRTCAP_HOST;
if (!strncmp(buf, "device", 6))
mode |= DWC3_GCTL_PRTCAP_DEVICE;
if (!strncmp(buf, "otg", 3))
mode |= DWC3_GCTL_PRTCAP_OTG;
if (mode) {
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_mode(dwc, mode);
spin_unlock_irqrestore(&dwc->lock, flags);
}
return count;
}
static const struct file_operations dwc3_mode_fops = {
.open = dwc3_mode_open,
.write = dwc3_mode_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
@ -402,7 +471,7 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
int ret;
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
if (IS_ERR(root)){
if (IS_ERR(root)) {
ret = PTR_ERR(root);
goto err0;
}
@ -415,6 +484,14 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
ret = PTR_ERR(file);
goto err1;
}
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto err1;
}
return 0;
err1:

View File

@ -48,6 +48,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include "core.h"
#include "io.h"
/*
@ -200,6 +201,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
struct dwc3_omap *omap;
struct resource *res;
int devid;
int ret = -ENOMEM;
int irq;
@ -236,16 +238,20 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
goto err1;
}
dwc3 = platform_device_alloc("dwc3-omap", -1);
devid = dwc3_get_device_id();
if (devid < 0)
goto err2;
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
goto err2;
goto err3;
}
context = kzalloc(resource_size(res), GFP_KERNEL);
if (!context) {
dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
goto err3;
goto err4;
}
spin_lock_init(&omap->lock);
@ -299,7 +305,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
goto err4;
goto err5;
}
/* enable all IRQs */
@ -322,26 +328,29 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
goto err5;
goto err6;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
goto err5;
goto err6;
}
return 0;
err5:
err6:
free_irq(omap->irq, omap);
err4:
err5:
kfree(omap->context);
err3:
err4:
platform_device_put(dwc3);
err3:
dwc3_put_device_id(devid);
err2:
iounmap(base);
@ -358,6 +367,7 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
platform_device_unregister(omap->dwc3);
dwc3_put_device_id(omap->dwc3->id);
free_irq(omap->irq, omap);
iounmap(omap->base);
@ -384,18 +394,9 @@ static struct platform_driver dwc3_omap_driver = {
},
};
module_platform_driver(dwc3_omap_driver);
MODULE_ALIAS("platform:omap-dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
static int __devinit dwc3_omap_init(void)
{
return platform_driver_register(&dwc3_omap_driver);
}
module_init(dwc3_omap_init);
static void __exit dwc3_omap_exit(void)
{
platform_driver_unregister(&dwc3_omap_driver);
}
module_exit(dwc3_omap_exit);

View File

@ -42,52 +42,17 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include "core.h"
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define DWC3_PCI_DEVS_POSSIBLE 32
struct dwc3_pci {
struct device *dev;
struct platform_device *dwc3;
};
static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
{
int id;
again:
id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
if (id < DWC3_PCI_DEVS_POSSIBLE) {
int old;
old = test_and_set_bit(id, dwc3_pci_devs);
if (old)
goto again;
} else {
dev_err(glue->dev, "no space for new device\n");
id = -ENOMEM;
}
return 0;
}
static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
{
int ret;
if (id < 0)
return;
ret = test_bit(id, dwc3_pci_devs);
WARN(!ret, "Device: %s\nID %d not in use\n",
dev_driver_string(glue->dev), id);
clear_bit(id, dwc3_pci_devs);
}
static int __devinit dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
@ -114,11 +79,11 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
devid = dwc3_pci_get_device_id(glue);
devid = dwc3_get_device_id();
if (devid < 0)
goto err2;
dwc3 = platform_device_alloc("dwc3-pci", devid);
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
goto err3;
@ -163,13 +128,13 @@ err4:
platform_device_put(dwc3);
err3:
dwc3_pci_put_device_id(glue, devid);
dwc3_put_device_id(devid);
err2:
pci_disable_device(pci);
err1:
kfree(pci);
kfree(glue);
err0:
return ret;
@ -179,7 +144,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
dwc3_pci_put_device_id(glue, glue->dwc3->id);
dwc3_put_device_id(glue->dwc3->id);
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
pci_disable_device(pci);
@ -196,7 +161,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
static struct pci_driver dwc3_pci_driver = {
.name = "pci-dwc3",
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = __devexit_p(dwc3_pci_remove),

View File

@ -48,13 +48,13 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include "core.h"
#include "gadget.h"
#include "io.h"
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
{
@ -125,6 +125,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
u32 type;
int ret = 0;
req->request.actual = 0;
@ -143,9 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
* IRQ we were waiting for is long gone.
*/
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
struct dwc3 *dwc = dep->dwc;
unsigned direction;
u32 type;
direction = !!(dep->flags & DWC3_EP0_DIR_IN);
@ -165,6 +165,13 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
req->request.dma, req->request.length, type);
dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
DWC3_EP0_DIR_IN);
} else if (dwc->delayed_status) {
dwc->delayed_status = false;
if (dwc->ep0state == EP0_STATUS_PHASE)
dwc3_ep0_do_control_status(dwc, 1);
else
dev_dbg(dwc->dev, "too early for delayed status\n");
}
return ret;
@ -190,9 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
}
/* we share one TRB for ep0/1 */
if (!list_empty(&dwc->eps[0]->request_list) ||
!list_empty(&dwc->eps[1]->request_list) ||
dwc->ep0_status_pending) {
if (!list_empty(&dep->request_list)) {
ret = -EBUSY;
goto out;
}
@ -214,8 +219,9 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
struct dwc3_ep *dep = dwc->eps[0];
/* stall is always issued on EP0 */
__dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
dwc->eps[0]->flags = DWC3_EP_ENABLED;
__dwc3_gadget_ep_set_halt(dep, 1);
dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false;
if (!list_empty(&dep->request_list)) {
struct dwc3_request *req;
@ -254,17 +260,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
return NULL;
}
static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
{
dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
dwc->ep0_usb_req.length,
DWC3_TRBCTL_CONTROL_DATA);
}
/*
* ch 9.4.5
*/
static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
static int dwc3_ep0_handle_status(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl)
{
struct dwc3_ep *dep;
u32 recip;
@ -291,7 +294,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl
case USB_RECIP_ENDPOINT:
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
if (!dep)
return -EINVAL;
return -EINVAL;
if (dep->flags & DWC3_EP_STALL)
usb_status = 1 << USB_ENDPOINT_HALT;
@ -302,10 +305,14 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl
response_pkt = (__le16 *) dwc->setup_buf;
*response_pkt = cpu_to_le16(usb_status);
dwc->ep0_usb_req.length = sizeof(*response_pkt);
dwc->ep0_status_pending = 1;
return 0;
dep = dwc->eps[0];
dwc->ep0_usb_req.dep = dep;
dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
}
static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
@ -396,8 +403,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_RECIP_ENDPOINT:
switch (wValue) {
case USB_ENDPOINT_HALT:
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
dep = dwc3_wIndex_to_dep(dwc, wIndex);
if (!dep)
return -EINVAL;
ret = __dwc3_gadget_ep_set_halt(dep, set);
@ -422,8 +428,15 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
u32 reg;
addr = le16_to_cpu(ctrl->wValue);
if (addr > 127)
if (addr > 127) {
dev_dbg(dwc->dev, "invalid device address %d\n", addr);
return -EINVAL;
}
if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
dev_dbg(dwc->dev, "trying to set address when configured\n");
return -EINVAL;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
@ -473,8 +486,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
if (!cfg)
dwc->dev_state = DWC3_ADDRESS_STATE;
break;
default:
ret = -EINVAL;
}
return 0;
return ret;
}
static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
@ -537,6 +552,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
else
ret = dwc3_ep0_delegate_req(dwc, ctrl);
if (ret == USB_GADGET_DELAYED_STATUS)
dwc->delayed_status = true;
if (ret >= 0)
return;
@ -550,27 +568,21 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct dwc3_request *r = NULL;
struct usb_request *ur;
struct dwc3_trb trb;
struct dwc3_ep *dep;
struct dwc3_ep *ep0;
u32 transferred;
u8 epnum;
epnum = event->endpoint_number;
dep = dwc->eps[epnum];
ep0 = dwc->eps[0];
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
if (!dwc->ep0_status_pending) {
r = next_request(&dwc->eps[0]->request_list);
ur = &r->request;
} else {
ur = &dwc->ep0_usb_req;
dwc->ep0_status_pending = 0;
}
r = next_request(&ep0->request_list);
ur = &r->request;
dwc3_trb_to_nat(dwc->ep0_trb, &trb);
if (dwc->ep0_bounced) {
struct dwc3_ep *ep0 = dwc->eps[0];
transferred = min_t(u32, ur->length,
ep0->endpoint.maxpacket - trb.length);
@ -591,7 +603,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
* seems to be case when req.length > maxpacket. Could it be?
*/
if (r)
dwc3_gadget_giveback(dep, r, 0);
dwc3_gadget_giveback(ep0, r, 0);
}
}
@ -619,6 +631,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
dep->flags &= ~DWC3_EP_BUSY;
dwc->setup_packet_pending = false;
switch (dwc->ep0state) {
case EP0_SETUP_PHASE:
@ -643,7 +656,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
}
@ -655,12 +667,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
int ret;
dep = dwc->eps[0];
dwc->ep0state = EP0_DATA_PHASE;
if (dwc->ep0_status_pending) {
dwc3_ep0_send_status_response(dwc);
return;
}
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
@ -674,7 +680,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
req = next_request(&dep->request_list);
req->direction = !!event->endpoint_number;
dwc->ep0state = EP0_DATA_PHASE;
if (req->request.length == 0) {
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
dwc->ctrl_req_addr, 0,
@ -706,35 +711,79 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
WARN_ON(ret < 0);
}
static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
u32 type;
int ret;
dwc->ep0state = EP0_STATUS_PHASE;
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
: DWC3_TRBCTL_CONTROL_STATUS2;
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
return dwc3_ep0_start_trans(dwc, dep->number,
dwc->ctrl_req_addr, 0, type);
}
WARN_ON(ret < 0);
static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
{
struct dwc3_ep *dep = dwc->eps[epnum];
WARN_ON(dwc3_ep0_start_control_status(dep));
}
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
dwc->setup_packet_pending = true;
/*
* This part is very tricky: If we has just handled
* XferNotReady(Setup) and we're now expecting a
* XferComplete but, instead, we receive another
* XferNotReady(Setup), we should STALL and restart
* the state machine.
*
* In all other cases, we just continue waiting
* for the XferComplete event.
*
* We are a little bit unsafe here because we're
* not trying to ensure that last event was, indeed,
* XferNotReady(Setup).
*
* Still, we don't expect any condition where that
* should happen and, even if it does, it would be
* another error condition.
*/
if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
switch (event->status) {
case DEPEVT_STATUS_CONTROL_SETUP:
dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
dwc3_ep0_stall_and_restart(dwc);
break;
case DEPEVT_STATUS_CONTROL_DATA:
/* FALLTHROUGH */
case DEPEVT_STATUS_CONTROL_STATUS:
/* FALLTHROUGH */
default:
dev_vdbg(dwc->dev, "waiting for XferComplete\n");
}
return;
}
switch (event->status) {
case DEPEVT_STATUS_CONTROL_SETUP:
dev_vdbg(dwc->dev, "Control Setup\n");
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_do_control_setup(dwc, event);
break;
case DEPEVT_STATUS_CONTROL_DATA:
dev_vdbg(dwc->dev, "Control Data\n");
dwc->ep0state = EP0_DATA_PHASE;
if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
dev_vdbg(dwc->dev, "Expected %d got %d\n",
dwc->ep0_next_event,
@ -764,6 +813,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
case DEPEVT_STATUS_CONTROL_STATUS:
dev_vdbg(dwc->dev, "Control Status\n");
dwc->ep0state = EP0_STATUS_PHASE;
if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
dev_vdbg(dwc->dev, "Expected %d got %d\n",
dwc->ep0_next_event,
@ -772,12 +823,19 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
dwc3_ep0_stall_and_restart(dwc);
return;
}
dwc3_ep0_do_control_status(dwc, event);
if (dwc->delayed_status) {
WARN_ON_ONCE(event->endpoint_number != 1);
dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
return;
}
dwc3_ep0_do_control_status(dwc, event->endpoint_number);
}
}
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const const struct dwc3_event_depevt *event)
const struct dwc3_event_depevt *event)
{
u8 epnum = event->endpoint_number;

View File

@ -65,6 +65,22 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req)
return;
}
if (req->request.num_sgs) {
int mapped;
mapped = dma_map_sg(dwc->dev, req->request.sg,
req->request.num_sgs,
req->direction ? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
if (mapped < 0) {
dev_err(dwc->dev, "failed to map SGs\n");
return;
}
req->request.num_mapped_sgs = mapped;
return;
}
if (req->request.dma == DMA_ADDR_INVALID) {
req->request.dma = dma_map_single(dwc->dev, req->request.buf,
req->request.length, req->direction
@ -82,6 +98,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
return;
}
if (req->request.num_mapped_sgs) {
req->request.dma = DMA_ADDR_INVALID;
dma_unmap_sg(dwc->dev, req->request.sg,
req->request.num_sgs,
req->direction ? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
req->request.num_mapped_sgs = 0;
return;
}
if (req->mapped) {
dma_unmap_single(dwc->dev, req->request.dma,
req->request.length, req->direction
@ -97,7 +124,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
struct dwc3 *dwc = dep->dwc;
if (req->queued) {
dep->busy_slot++;
if (req->request.num_mapped_sgs)
dep->busy_slot += req->request.num_mapped_sgs;
else
dep->busy_slot++;
/*
* Skip LINK TRB. We can't use req->trb and check for
* DWC3_TRBCTL_LINK_TRB because it points the TRB we just
@ -108,6 +139,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
dep->busy_slot++;
}
list_del(&req->list);
req->trb = NULL;
if (req->request.status == -EINPROGRESS)
req->request.status = status;
@ -251,7 +283,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
}
static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
const struct usb_endpoint_descriptor *desc)
const struct usb_endpoint_descriptor *desc,
const struct usb_ss_ep_comp_descriptor *comp_desc)
{
struct dwc3_gadget_ep_cmd_params params;
@ -264,7 +297,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
| DWC3_DEPCFG_XFER_NOT_READY_EN;
if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
| DWC3_DEPCFG_STREAM_EVENT_EN;
dep->stream_capable = true;
@ -317,7 +350,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
* Caller should take care of locking
*/
static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
const struct usb_endpoint_descriptor *desc)
const struct usb_endpoint_descriptor *desc,
const struct usb_ss_ep_comp_descriptor *comp_desc)
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
@ -329,7 +363,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return ret;
}
ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
if (ret)
return ret;
@ -343,6 +377,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return ret;
dep->desc = desc;
dep->comp_desc = comp_desc;
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
@ -405,6 +440,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dep->stream_capable = false;
dep->desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
dep->flags = 0;
@ -473,7 +509,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_enable(dep, desc);
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@ -539,6 +575,85 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
kfree(req);
}
/**
* dwc3_prepare_one_trb - setup one TRB from one request
* @dep: endpoint for which this request is prepared
* @req: dwc3_request pointer
*/
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb_hw *trb_hw;
struct dwc3_trb trb;
unsigned int cur_slot;
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
dep->name, req, (unsigned long long) dma,
length, last ? " last" : "",
chain ? " chain" : "");
trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
cur_slot = dep->free_slot;
dep->free_slot++;
/* Skip the LINK-TRB on ISOC */
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->desc))
return;
memset(&trb, 0, sizeof(trb));
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
req->trb = trb_hw;
req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
}
if (usb_endpoint_xfer_isoc(dep->desc)) {
trb.isp_imi = true;
trb.csp = true;
} else {
trb.chn = chain;
trb.lst = last;
}
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
trb.sid_sofn = req->request.stream_id;
switch (usb_endpoint_type(dep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
trb.ioc = last;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
trb.trbctl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
* This is only possible with faulty memory because we
* checked it already :)
*/
BUG();
}
trb.length = length;
trb.bplh = dma;
trb.hwo = true;
dwc3_trb_to_hw(&trb, trb_hw);
}
/*
* dwc3_prepare_trbs - setup TRBs from requests
* @dep: endpoint for which requests are being prepared
@ -548,18 +663,17 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
* transfers. The functions returns once there are not more TRBs available or
* it run out of requests.
*/
static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
bool starting)
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
{
struct dwc3_request *req, *n, *ret = NULL;
struct dwc3_trb_hw *trb_hw;
struct dwc3_trb trb;
struct dwc3_request *req, *n;
u32 trbs_left;
unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
/* the first request must not be queued */
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
/*
* if busy & slot are equal than it is either full or empty. If we are
* starting to proceed requests then we are empty. Otherwise we ar
@ -567,7 +681,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
*/
if (!trbs_left) {
if (!starting)
return NULL;
return;
trbs_left = DWC3_TRB_NUM;
/*
* In case we start from scratch, we queue the ISOC requests
@ -591,94 +705,62 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
/* The last TRB is a link TRB, not used for xfer */
if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
return NULL;
return;
list_for_each_entry_safe(req, n, &dep->request_list, list) {
unsigned int last_one = 0;
unsigned int cur_slot;
unsigned length;
dma_addr_t dma;
trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
cur_slot = dep->free_slot;
dep->free_slot++;
if (req->request.num_mapped_sgs > 0) {
struct usb_request *request = &req->request;
struct scatterlist *sg = request->sg;
struct scatterlist *s;
int i;
/* Skip the LINK-TRB on ISOC */
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->desc))
continue;
for_each_sg(sg, s, request->num_mapped_sgs, i) {
unsigned chain = true;
dwc3_gadget_move_request_queued(req);
memset(&trb, 0, sizeof(trb));
trbs_left--;
length = sg_dma_len(s);
dma = sg_dma_address(s);
/* Is our TRB pool empty? */
if (!trbs_left)
last_one = 1;
/* Is this the last request? */
if (list_empty(&dep->request_list))
last_one = 1;
if (i == (request->num_mapped_sgs - 1)
|| sg_is_last(s)) {
last_one = true;
chain = false;
}
/*
* FIXME we shouldn't need to set LST bit always but we are
* facing some weird problem with the Hardware where it doesn't
* complete even though it has been previously started.
*
* While we're debugging the problem, as a workaround to
* multiple TRBs handling, use only one TRB at a time.
*/
last_one = 1;
trbs_left--;
if (!trbs_left)
last_one = true;
req->trb = trb_hw;
if (!ret)
ret = req;
if (last_one)
chain = false;
trb.bplh = req->request.dma;
dwc3_prepare_one_trb(dep, req, dma, length,
last_one, chain);
if (usb_endpoint_xfer_isoc(dep->desc)) {
trb.isp_imi = true;
trb.csp = true;
if (last_one)
break;
}
} else {
trb.lst = last_one;
dma = req->request.dma;
length = req->request.length;
trbs_left--;
if (!trbs_left)
last_one = 1;
/* Is this the last request? */
if (list_is_last(&req->list, &dep->request_list))
last_one = 1;
dwc3_prepare_one_trb(dep, req, dma, length,
last_one, false);
if (last_one)
break;
}
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
trb.sid_sofn = req->request.stream_id;
switch (usb_endpoint_type(dep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
trb.ioc = last_one;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
trb.trbctl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
* This is only possible with faulty memory because we
* checked it already :)
*/
BUG();
}
trb.length = req->request.length;
trb.hwo = true;
dwc3_trb_to_hw(&trb, trb_hw);
req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
if (last_one)
break;
}
return ret;
}
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
@ -707,11 +789,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
/* req points to the first request which will be sent */
req = next_request(&dep->req_queued);
} else {
dwc3_prepare_trbs(dep, start_new);
/*
* req points to the first request where HWO changed
* from 0 to 1
*/
req = dwc3_prepare_trbs(dep, start_new);
req = next_request(&dep->req_queued);
}
if (!req) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
@ -745,8 +829,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
dep->flags |= DWC3_EP_BUSY;
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
dep->number);
if (!dep->res_trans_idx)
printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
WARN_ON_ONCE(!dep->res_trans_idx);
return 0;
}
@ -1155,35 +1240,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->gadget_driver = driver;
dwc->gadget.dev.driver = &driver->driver;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN(3);
reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
reg &= ~DWC3_GCTL_DISSCRAMBLE;
reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break;
default:
dev_dbg(dwc->dev, "No power optimization available\n");
}
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* when The device fails to connect at SuperSpeed
* and falls back to high-speed mode which causes
* the device to enter in a Connect/Disconnect loop
*/
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
reg |= DWC3_DCFG_SUPERSPEED;
reg |= dwc->maximum_speed;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc->start_config_issued = false;
@ -1192,14 +1251,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err0;
}
dep = dwc->eps[1];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err1;
@ -1290,11 +1349,10 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
&dwc->gadget.ep_list);
ret = dwc3_alloc_trb_pool(dep);
if (ret) {
dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
if (ret)
return ret;
}
}
INIT_LIST_HEAD(&dep->request_list);
INIT_LIST_HEAD(&dep->req_queued);
}
@ -1334,8 +1392,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
do {
req = next_request(&dep->req_queued);
if (!req)
break;
if (!req) {
WARN_ON_ONCE(1);
return 1;
}
dwc3_trb_to_nat(req->trb, &trb);
@ -1400,6 +1460,31 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
dep->flags &= ~DWC3_EP_BUSY;
dep->res_trans_idx = 0;
}
/*
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
* See dwc3_gadget_linksts_change_interrupt() for 1st half.
*/
if (dwc->revision < DWC3_REVISION_183A) {
u32 reg;
int i;
for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
struct dwc3_ep *dep = dwc->eps[i];
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
if (!list_empty(&dep->req_queued))
return;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= dwc->u1u2;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->u1u2 = 0;
}
}
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@ -1639,6 +1724,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc->start_config_issued = false;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false;
}
static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
@ -1675,6 +1761,40 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dev_vdbg(dwc->dev, "%s\n", __func__);
/*
* WORKAROUND: DWC3 revisions <1.88a have an issue which
* would cause a missing Disconnect Event if there's a
* pending Setup Packet in the FIFO.
*
* There's no suggested workaround on the official Bug
* report, which states that "unless the driver/application
* is doing any special handling of a disconnect event,
* there is no functional issue".
*
* Unfortunately, it turns out that we _do_ some special
* handling of a disconnect event, namely complete all
* pending transfers, notify gadget driver of the
* disconnection, and so on.
*
* Our suggested workaround is to follow the Disconnect
* Event steps here, instead, based on a setup_packet_pending
* flag. Such flag gets set whenever we have a XferNotReady
* event on EP0 and gets cleared on XferComplete for the
* same endpoint.
*
* Refers to:
*
* STAR#9000466709: RTL: Device : Disconnect event not
* generated if setup packet pending in FIFO
*/
if (dwc->revision < DWC3_REVISION_188A) {
if (dwc->setup_packet_pending)
dwc3_gadget_disconnect_interrupt(dwc);
}
/* after reset -> Default State */
dwc->dev_state = DWC3_DEFAULT_STATE;
/* Enable PHYs */
dwc3_gadget_usb2_phy_power(dwc, true);
dwc3_gadget_usb3_phy_power(dwc, true);
@ -1755,6 +1875,22 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
switch (speed) {
case DWC3_DCFG_SUPERSPEED:
/*
* WORKAROUND: DWC3 revisions <1.90a have an issue which
* would cause a missing USB3 Reset event.
*
* In such situations, we should force a USB3 Reset
* event by calling our dwc3_gadget_reset_interrupt()
* routine.
*
* Refers to:
*
* STAR#9000483510: RTL: SS : USB3 reset event may
* not be generated always when the link enters poll
*/
if (dwc->revision < DWC3_REVISION_190A)
dwc3_gadget_reset_interrupt(dwc);
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dwc->gadget.ep0->maxpacket = 512;
dwc->gadget.speed = USB_SPEED_SUPER;
@ -1781,14 +1917,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
return;
}
dep = dwc->eps[1];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
return;
@ -1818,8 +1954,55 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
/* The fith bit says SuperSpeed yes or no. */
dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
/*
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
* on the link partner, the USB session might do multiple entry/exit
* of low power states before a transfer takes place.
*
* Due to this problem, we might experience lower throughput. The
* suggested workaround is to disable DCTL[12:9] bits if we're
* transitioning from U1/U2 to U0 and enable those bits again
* after a transfer completes and there are no pending transfers
* on any of the enabled endpoints.
*
* This is the first half of that workaround.
*
* Refers to:
*
* STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
* core send LGO_Ux entering U0
*/
if (dwc->revision < DWC3_REVISION_183A) {
if (next == DWC3_LINK_STATE_U0) {
u32 u1u2;
u32 reg;
switch (dwc->link_state) {
case DWC3_LINK_STATE_U1:
case DWC3_LINK_STATE_U2:
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
u1u2 = reg & (DWC3_DCTL_INITU2ENA
| DWC3_DCTL_ACCEPTU2ENA
| DWC3_DCTL_INITU1ENA
| DWC3_DCTL_ACCEPTU1ENA);
if (!dwc->u1u2)
dwc->u1u2 = reg & u1u2;
reg &= ~u1u2;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
default:
/* do nothing */
break;
}
}
}
dwc->link_state = next;
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
}
@ -1925,7 +2108,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
spin_lock(&dwc->lock);
for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
for (i = 0; i < dwc->num_event_buffers; i++) {
irqreturn_t status;
status = dwc3_process_event_buf(dwc, i);
@ -1986,9 +2169,10 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
dev_set_name(&dwc->gadget.dev, "gadget");
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.is_dualspeed = true;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.dev.parent = dwc->dev;
dwc->gadget.sg_supported = true;
dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
@ -2076,7 +2260,6 @@ err0:
void dwc3_gadget_exit(struct dwc3 *dwc)
{
int irq;
int i;
usb_del_gadget_udc(&dwc->gadget);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
@ -2084,9 +2267,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
free_irq(irq, dwc);
for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
__dwc3_gadget_ep_disable(dwc->eps[i]);
dwc3_gadget_free_endpoints(dwc);
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,

View File

@ -79,19 +79,6 @@ struct dwc3_gadget_ep_cmd_params {
/* -------------------------------------------------------------------------- */
struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
u8 epnum;
struct dwc3_trb_hw *trb;
dma_addr_t trb_dma;
unsigned direction:1;
unsigned mapped:1;
unsigned queued:1;
};
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
static inline struct dwc3_request *next_request(struct list_head *list)
@ -110,23 +97,11 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
list_move_tail(&req->list, &dep->req_queued);
}
#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
return 0;
}
#endif
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);

102
drivers/usb/dwc3/host.c Normal file
View File

@ -0,0 +1,102 @@
/**
* host.c - DesignWare USB3 DRD Controller Host Glue
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/platform_device.h>
#include "core.h"
static struct resource generic_resources[] = {
{
.flags = IORESOURCE_IRQ,
},
{
.flags = IORESOURCE_MEM,
},
};
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
int ret;
xhci = platform_device_alloc("xhci", -1);
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
ret = -ENOMEM;
goto err0;
}
dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
xhci->dev.parent = dwc->dev;
xhci->dev.dma_mask = dwc->dev->dma_mask;
xhci->dev.dma_parms = dwc->dev->dma_parms;
dwc->xhci = xhci;
/* setup resources */
generic_resources[0].start = dwc->irq;
generic_resources[1].start = dwc->res->start;
generic_resources[1].end = dwc->res->start + 0x7fff;
ret = platform_device_add_resources(xhci, generic_resources,
ARRAY_SIZE(generic_resources));
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;
}
ret = platform_device_add(xhci);
if (ret) {
dev_err(dwc->dev, "failed to register xHCI device\n");
goto err1;
}
return 0;
err1:
platform_device_put(xhci);
err0:
return ret;
}
void dwc3_host_exit(struct dwc3 *dwc)
{
platform_device_unregister(dwc->xhci);
}

View File

@ -39,7 +39,7 @@
#ifndef __DRIVERS_USB_DWC3_IO_H
#define __DRIVERS_USB_DWC3_IO_H
#include <asm/io.h>
#include <linux/io.h>
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{

View File

@ -15,6 +15,7 @@
menuconfig USB_GADGET
tristate "USB Gadget Support"
select NLS
help
USB is a master/slave protocol, organized with one master
host (such as a PC) controlling up to 127 peripheral devices.
@ -124,7 +125,6 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
#
choice
prompt "USB Peripheral Controller"
depends on USB_GADGET
help
A USB device uses a controller to talk to its host.
Systems should have only one such upstream link.
@ -234,7 +234,6 @@ config USB_R8A66597
config USB_RENESAS_USBHS_UDC
tristate 'Renesas USBHS controller'
depends on SUPERH || ARCH_SHMOBILE
depends on USB_RENESAS_USBHS
select USB_GADGET_DUALSPEED
help
@ -309,25 +308,13 @@ config USB_S3C_HSUDC
This driver has been tested on S3C2416 and S3C2450 processors.
config USB_PXA_U2O
tristate "PXA9xx Processor USB2.0 controller"
depends on ARCH_MMP
config USB_MV_UDC
tristate "Marvell USB2.0 Device Controller"
select USB_GADGET_DUALSPEED
help
PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral.
config USB_GADGET_DWC3
tristate "DesignWare USB3.0 (DRD) Controller"
depends on USB_DWC3
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
help
DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
which can be configured for peripheral-only, host-only, hub-only
and Dual-Role operation. This Controller was first integrated into
the OMAP5 series of processors. More information about the OMAP5
version of this controller, refer to http://www.ti.com/omap5.
Marvell Socs (including PXA and MMP series) include a high speed
USB2.0 OTG controller, which can be configured as high speed or
full speed USB peripheral.
#
# Controllers available in both integrated and discrete versions
@ -543,12 +530,10 @@ endchoice
# Selected by UDC drivers that support high-speed operation.
config USB_GADGET_DUALSPEED
bool
depends on USB_GADGET
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
bool
depends on USB_GADGET
depends on USB_GADGET_DUALSPEED
#
@ -556,7 +541,6 @@ config USB_GADGET_SUPERSPEED
#
choice
tristate "USB Gadget Drivers"
depends on USB_GADGET
default USB_ETH
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller

View File

@ -27,7 +27,7 @@ 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
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o

View File

@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver,
u32 tmp;
if (!driver || !bind || !driver->setup
|| driver->speed < USB_SPEED_HIGH)
|| driver->max_speed < USB_SPEED_HIGH)
return -EINVAL;
if (!dev)
return -ENODEV;
@ -3349,7 +3349,7 @@ static int udc_probe(struct udc *dev)
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
dev->gadget.max_speed = USB_SPEED_HIGH;
/* init registers, interrupts, ... */
startup_registers(dev);

View File

@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver,
unsigned long flags;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind
|| !driver->setup) {
DBG("bad parameter.\n");

View File

@ -1038,7 +1038,7 @@ static struct usba_udc the_udc = {
.gadget = {
.ops = &usba_udc_ops,
.ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list),
.is_dualspeed = 1,
.max_speed = USB_SPEED_HIGH,
.name = "atmel_usba_udc",
.dev = {
.init_name = "gadget",

View File

@ -182,6 +182,16 @@ static inline int hw_ep_bit(int num, int dir)
return num + (dir ? 16 : 0);
}
static int ep_to_bit(int n)
{
int fill = 16 - hw_ep_max / 2;
if (n >= hw_ep_max / 2)
n += fill;
return n;
}
/**
* hw_aread: reads from register bitfield
* @addr: address relative to bus map
@ -440,12 +450,13 @@ static int hw_ep_get_halt(int num, int dir)
/**
* hw_test_and_clear_setup_status: test & clear setup status (execute without
* interruption)
* @n: bit number (endpoint)
* @n: endpoint number
*
* This function returns setup status
*/
static int hw_test_and_clear_setup_status(int n)
{
n = ep_to_bit(n);
return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
}
@ -641,12 +652,13 @@ static int hw_register_write(u16 addr, u32 data)
/**
* hw_test_and_clear_complete: test & clear complete status (execute without
* interruption)
* @n: bit number (endpoint)
* @n: endpoint number
*
* This function returns complete status
*/
static int hw_test_and_clear_complete(int n)
{
n = ep_to_bit(n);
return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
}
@ -754,8 +766,11 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr,
n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
gadget->speed);
n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
gadget->max_speed);
/* TODO: Scheduled for removal in 3.8. */
n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
gadget->is_dualspeed);
gadget_is_dualspeed(gadget));
n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
gadget->is_otg);
n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
@ -798,7 +813,7 @@ static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
(driver->function ? driver->function : ""));
n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
driver->speed);
driver->max_speed);
return n;
}
@ -2563,9 +2578,7 @@ static int ci13xxx_start(struct usb_gadget_driver *driver,
if (driver == NULL ||
bind == NULL ||
driver->setup == NULL ||
driver->disconnect == NULL ||
driver->suspend == NULL ||
driver->resume == NULL)
driver->disconnect == NULL)
return -EINVAL;
else if (udc == NULL)
return -ENODEV;
@ -2693,8 +2706,6 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver)
driver->unbind == NULL ||
driver->setup == NULL ||
driver->disconnect == NULL ||
driver->suspend == NULL ||
driver->resume == NULL ||
driver != udc->driver)
return -EINVAL;
@ -2793,7 +2804,7 @@ static irqreturn_t udc_irq(void)
isr_statistics.pci++;
udc->gadget.speed = hw_port_is_high_speed() ?
USB_SPEED_HIGH : USB_SPEED_FULL;
if (udc->suspended) {
if (udc->suspended && udc->driver->resume) {
spin_unlock(udc->lock);
udc->driver->resume(&udc->gadget);
spin_lock(udc->lock);
@ -2807,7 +2818,8 @@ static irqreturn_t udc_irq(void)
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr) {
if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
udc->driver->suspend) {
udc->suspended = 1;
spin_unlock(udc->lock);
udc->driver->suspend(&udc->gadget);
@ -2871,7 +2883,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
udc->gadget.ops = &usb_gadget_ops;
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.is_dualspeed = 1;
udc->gadget.max_speed = USB_SPEED_HIGH;
udc->gadget.is_otg = 0;
udc->gadget.name = driver->name;

View File

@ -127,7 +127,7 @@ struct ci13xxx {
struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
u32 ep0_dir; /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in ci13xxx_ep[16]
#define ep0in ci13xxx_ep[hw_ep_max / 2]
u8 remote_wakeup; /* Is remote wakeup feature
enabled by the host? */
u8 suspended; /* suspended by the host */

View File

@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget)
static struct usb_gadget_driver composite_driver = {
#ifdef CONFIG_USB_GADGET_SUPERSPEED
.speed = USB_SPEED_SUPER,
.max_speed = USB_SPEED_SUPER,
#else
.speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_HIGH,
#endif
.unbind = composite_unbind,
@ -1584,8 +1584,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
composite_driver.speed = min((u8)composite_driver.speed,
(u8)driver->max_speed);
composite_driver.max_speed =
min_t(u8, composite_driver.max_speed, driver->max_speed);
composite = driver;
composite_gadget_bind = bind;

View File

@ -404,7 +404,7 @@ fail:
static struct usb_gadget_driver dbgp_driver = {
.function = "dbgp",
.speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_HIGH,
.unbind = dbgp_unbind,
.setup = dbgp_setup,
.disconnect = dbgp_disconnect,

View File

@ -823,19 +823,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
if (value && dum->driver) {
if (mod_data.is_super_speed)
dum->gadget.speed = dum->driver->speed;
dum->gadget.speed = dum->driver->max_speed;
else if (mod_data.is_high_speed)
dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
dum->driver->speed);
dum->driver->max_speed);
else
dum->gadget.speed = USB_SPEED_FULL;
dummy_udc_udpate_ep0(dum);
if (dum->gadget.speed < dum->driver->speed)
if (dum->gadget.speed < dum->driver->max_speed)
dev_dbg(udc_dev(dum), "This device can perform faster"
" if you connect it to a %s port...\n",
(dum->driver->speed == USB_SPEED_SUPER ?
"SuperSpeed" : "HighSpeed"));
" if you connect it to a %s port...\n",
usb_speed_string(dum->driver->max_speed));
}
dum_hcd = gadget_to_dummy_hcd(_gadget);
@ -898,7 +897,7 @@ static int dummy_udc_start(struct usb_gadget *g,
struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g);
struct dummy *dum = dum_hcd->dum;
if (driver->speed == USB_SPEED_UNKNOWN)
if (driver->max_speed == USB_SPEED_UNKNOWN)
return -EINVAL;
/*
@ -977,7 +976,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops;
dum->gadget.is_dualspeed = 1;
dum->gadget.max_speed = USB_SPEED_SUPER;
dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev;

View File

@ -149,7 +149,7 @@ ep_matches (
switch (type) {
case USB_ENDPOINT_XFER_INT:
/* INT: limit 64 bytes full speed, 1024 high/super speed */
if (!gadget->is_dualspeed && max > 64)
if (!gadget_is_dualspeed(gadget) && max > 64)
return 0;
/* FALLTHROUGH */
@ -157,12 +157,12 @@ ep_matches (
/* ISO: limit 1023 bytes full speed, 1024 high/super speed */
if (ep->maxpacket < max)
return 0;
if (!gadget->is_dualspeed && max > 1023)
if (!gadget_is_dualspeed(gadget) && max > 1023)
return 0;
/* BOTH: "high bandwidth" works only at high speed */
if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
return 0;
/* configure your hardware with enough buffering!! */
}

View File

@ -1399,7 +1399,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
ENTER();
count = ffs->eps_count;
epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL);
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
if (!epfiles)
return -ENOMEM;

View File

@ -1873,17 +1873,14 @@ static int check_command(struct fsg_common *common, int cmnd_size,
common->lun, lun);
/* Check the LUN */
if (common->lun < common->nluns) {
curlun = &common->luns[common->lun];
common->curlun = curlun;
curlun = common->curlun;
if (curlun) {
if (common->cmnd[0] != REQUEST_SENSE) {
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
curlun->info_valid = 0;
}
} else {
common->curlun = NULL;
curlun = NULL;
common->bad_lun_okay = 0;
/*
@ -1929,6 +1926,17 @@ static int check_command(struct fsg_common *common, int cmnd_size,
return 0;
}
/* wrapper of check_command for data size in blocks handling */
static int check_command_size_in_blocks(struct fsg_common *common,
int cmnd_size, enum data_direction data_dir,
unsigned int mask, int needs_medium, const char *name)
{
if (common->curlun)
common->data_size_from_cmnd <<= common->curlun->blkbits;
return check_command(common, cmnd_size, data_dir,
mask, needs_medium, name);
}
static int do_scsi_command(struct fsg_common *common)
{
struct fsg_buffhd *bh;
@ -2011,9 +2019,9 @@ static int do_scsi_command(struct fsg_common *common)
case READ_6:
i = common->cmnd[4];
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_TO_HOST,
common->data_size_from_cmnd = (i == 0) ? 256 : i;
reply = check_command_size_in_blocks(common, 6,
DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)");
if (reply == 0)
@ -2022,9 +2030,9 @@ static int do_scsi_command(struct fsg_common *common)
case READ_10:
common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) <<
common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_TO_HOST,
get_unaligned_be16(&common->cmnd[7]);
reply = check_command_size_in_blocks(common, 10,
DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)");
if (reply == 0)
@ -2033,9 +2041,9 @@ static int do_scsi_command(struct fsg_common *common)
case READ_12:
common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) <<
common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_TO_HOST,
get_unaligned_be32(&common->cmnd[6]);
reply = check_command_size_in_blocks(common, 12,
DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)");
if (reply == 0)
@ -2134,9 +2142,9 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_6:
i = common->cmnd[4];
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
common->data_size_from_cmnd = (i == 0) ? 256 : i;
reply = check_command_size_in_blocks(common, 6,
DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)");
if (reply == 0)
@ -2145,9 +2153,9 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_10:
common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) <<
common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
get_unaligned_be16(&common->cmnd[7]);
reply = check_command_size_in_blocks(common, 10,
DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
if (reply == 0)
@ -2156,9 +2164,9 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_12:
common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) <<
common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
get_unaligned_be32(&common->cmnd[6]);
reply = check_command_size_in_blocks(common, 12,
DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)");
if (reply == 0)
@ -2273,6 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
if (common->data_size == 0)
common->data_dir = DATA_DIR_NONE;
common->lun = cbw->Lun;
if (common->lun >= 0 && common->lun < common->nluns)
common->curlun = &common->luns[common->lun];
else
common->curlun = NULL;
common->tag = cbw->Tag;
return 0;
}
@ -2763,7 +2775,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
* Create the LUNs, open their backing files, and register the
* LUN devices in sysfs.
*/
curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
if (unlikely(!curlun)) {
rc = -ENOMEM;
goto error_release;

View File

@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
DBG(fsg, "using LUN %d from CBW, "
"not LUN %d from CDB\n",
fsg->lun, lun);
} else
fsg->lun = lun; // Use LUN from the command
}
/* Check the LUN */
if (fsg->lun < fsg->nluns) {
fsg->curlun = curlun = &fsg->luns[fsg->lun];
curlun = fsg->curlun;
if (curlun) {
if (fsg->cmnd[0] != REQUEST_SENSE) {
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
curlun->info_valid = 0;
}
} else {
fsg->curlun = curlun = NULL;
fsg->bad_lun_okay = 0;
/* INQUIRY and REQUEST SENSE commands are explicitly allowed
@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
return 0;
}
/* wrapper of check_command for data size in blocks handling */
static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
enum data_direction data_dir, unsigned int mask,
int needs_medium, const char *name)
{
if (fsg->curlun)
fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
return check_command(fsg, cmnd_size, data_dir,
mask, needs_medium, name);
}
static int do_scsi_command(struct fsg_dev *fsg)
{
@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_6:
i = fsg->cmnd[4];
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
if ((reply = check_command_size_in_blocks(fsg, 6,
DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)")) == 0)
reply = do_read(fsg);
break;
case READ_10:
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command_size_in_blocks(fsg, 10,
DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)")) == 0)
reply = do_read(fsg);
break;
case READ_12:
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
if ((reply = check_command_size_in_blocks(fsg, 12,
DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)")) == 0)
reply = do_read(fsg);
@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_6:
i = fsg->cmnd[4];
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
if ((reply = check_command_size_in_blocks(fsg, 6,
DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)")) == 0)
reply = do_write(fsg);
break;
case WRITE_10:
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command_size_in_blocks(fsg, 10,
DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)")) == 0)
reply = do_write(fsg);
break;
case WRITE_12:
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
if ((reply = check_command_size_in_blocks(fsg, 12,
DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)")) == 0)
reply = do_write(fsg);
@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg)
memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
fsg->cbbuf_cmnd_size = 0;
spin_unlock_irq(&fsg->lock);
/* Use LUN from the command */
fsg->lun = fsg->cmnd[1] >> 5;
}
/* Update current lun */
if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
fsg->curlun = &fsg->luns[fsg->lun];
else
fsg->curlun = NULL;
return rc;
}
@ -3584,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver fsg_driver = {
.speed = USB_SPEED_SUPER,
.max_speed = USB_SPEED_SUPER,
.function = (char *) fsg_string_product,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,

View File

@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,
if (!udc_controller)
return -ENODEV;
if (!driver || driver->speed < USB_SPEED_FULL
if (!driver || driver->max_speed < USB_SPEED_FULL
|| !bind || !driver->disconnect || !driver->setup)
return -EINVAL;
@ -2350,7 +2350,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,
/* hook up the driver */
udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed);
udc_controller->gadget.speed = driver->max_speed;
spin_unlock_irqrestore(&udc_controller->lock, flags);
retval = bind(&udc_controller->gadget);
@ -2814,20 +2814,7 @@ static struct platform_driver udc_driver = {
#endif
};
static int __init qe_udc_init(void)
{
printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc,
DRIVER_VERSION);
return platform_driver_register(&udc_driver);
}
static void __exit qe_udc_exit(void)
{
platform_driver_unregister(&udc_driver);
}
module_init(qe_udc_init);
module_exit(qe_udc_exit);
module_platform_driver(udc_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);

View File

@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver,
if (!udc_controller)
return -ENODEV;
if (!driver || driver->speed < USB_SPEED_FULL
if (!driver || driver->max_speed < USB_SPEED_FULL
|| !bind || !driver->disconnect || !driver->setup)
return -EINVAL;
@ -2525,7 +2525,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
/* Setup gadget structure */
udc_controller->gadget.ops = &fsl_gadget_ops;
udc_controller->gadget.is_dualspeed = 1;
udc_controller->gadget.max_speed = USB_SPEED_HIGH;
udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
udc_controller->gadget.speed = USB_SPEED_UNKNOWN;

View File

@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver,
int retval;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind
|| !driver->setup)
return -EINVAL;
@ -1463,7 +1463,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
dev_set_name(&fusb300->gadget.dev, "gadget");
fusb300->gadget.is_dualspeed = 1;
fusb300->gadget.max_speed = USB_SPEED_HIGH;
fusb300->gadget.dev.parent = &pdev->dev;
fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
fusb300->gadget.dev.release = pdev->dev.release;

View File

@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver,
int retval;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind
|| !driver->disconnect
|| !driver->setup)
@ -1796,6 +1796,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &goku_ops;
dev->gadget.max_speed = USB_SPEED_FULL;
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");

View File

@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver,
int retval;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind
|| !driver->disconnect
|| !driver->setup)

View File

@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
static struct usb_gadget_driver gadgetfs_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
.max_speed = USB_SPEED_FULL,
#endif
.function = (char *) driver_desc,
.unbind = gadgetfs_unbind,
@ -1792,7 +1792,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget)
}
static struct usb_gadget_driver probe_driver = {
.speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_HIGH,
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,

View File

@ -3267,7 +3267,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */
INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */
dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
dev->gadget.is_dualspeed = 1; /* support dual speed */
dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
#ifdef OTG_TRANSCEIVER
dev->gadget.is_otg = 1; /* support otg mode */
#endif

View File

@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver,
int retval;
if (!driver
|| driver->speed < USB_SPEED_HIGH
|| driver->max_speed < USB_SPEED_HIGH
|| !bind
|| !driver->setup)
return -EINVAL;
@ -1653,7 +1653,7 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->gadget.ops = &m66592_gadget_ops;
device_initialize(&m66592->gadget.dev);
dev_set_name(&m66592->gadget.dev, "gadget");
m66592->gadget.is_dualspeed = 1;
m66592->gadget.max_speed = USB_SPEED_HIGH;
m66592->gadget.dev.parent = &pdev->dev;
m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
m66592->gadget.dev.release = pdev->dev.release;

View File

@ -180,7 +180,7 @@ struct mv_udc {
struct mv_cap_regs __iomem *cap_regs;
struct mv_op_regs __iomem *op_regs;
unsigned int phy_regs;
void __iomem *phy_regs;
unsigned int max_eps;
struct mv_dqh *ep_dqh;
size_t ep_dqh_size;
@ -211,11 +211,14 @@ struct mv_udc {
softconnected:1,
force_fs:1,
clock_gating:1,
active:1;
active:1,
stopped:1; /* stop bit is setted */
struct work_struct vbus_work;
struct workqueue_struct *qwork;
struct otg_transceiver *transceiver;
struct mv_usb_platform_data *pdata;
/* some SOC has mutiple clock sources for USB*/

View File

@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
{
u32 tmp, epstatus, bit_pos, direction;
struct mv_udc *udc;
struct mv_dqh *dqh;
u32 bit_pos, direction;
u32 usbcmd, epstatus;
unsigned int loops;
int readsafe, retval = 0;
int retval = 0;
udc = ep->udc;
direction = ep_dir(ep);
@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
lastreq->tail->dtd_next =
req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
if (readl(&udc->op_regs->epprime) & bit_pos) {
loops = LOOPS(PRIME_TIMEOUT);
while (readl(&udc->op_regs->epprime) & bit_pos) {
if (loops == 0) {
retval = -ETIME;
goto done;
}
udelay(LOOPS_USEC);
loops--;
}
if (readl(&udc->op_regs->epstatus) & bit_pos)
goto done;
}
readsafe = 0;
wmb();
if (readl(&udc->op_regs->epprime) & bit_pos)
goto done;
loops = LOOPS(READSAFE_TIMEOUT);
while (readsafe == 0) {
if (loops == 0) {
retval = -ETIME;
goto done;
}
while (1) {
/* start with setting the semaphores */
tmp = readl(&udc->op_regs->usbcmd);
tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
writel(tmp, &udc->op_regs->usbcmd);
usbcmd = readl(&udc->op_regs->usbcmd);
usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
writel(usbcmd, &udc->op_regs->usbcmd);
/* read the endpoint status */
epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
* primed.
*/
if (readl(&udc->op_regs->usbcmd)
& USBCMD_ATDTW_TRIPWIRE_SET) {
readsafe = 1;
}
& USBCMD_ATDTW_TRIPWIRE_SET)
break;
loops--;
if (loops == 0) {
dev_err(&udc->dev->dev,
"Timeout for ATDTW_TRIPWIRE...\n");
retval = -ETIME;
goto done;
}
udelay(LOOPS_USEC);
}
/* Clear the semaphore */
tmp = readl(&udc->op_regs->usbcmd);
tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
writel(tmp, &udc->op_regs->usbcmd);
usbcmd = readl(&udc->op_regs->usbcmd);
usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
writel(usbcmd, &udc->op_regs->usbcmd);
/* If endpoint is not active, we activate it now. */
if (!epstatus) {
if (direction == EP_DIR_IN) {
struct mv_dtd *curr_dtd = dma_to_virt(
&udc->dev->dev, dqh->curr_dtd_ptr);
loops = LOOPS(DTD_TIMEOUT);
while (curr_dtd->size_ioc_sts
& DTD_STATUS_ACTIVE) {
if (loops == 0) {
retval = -ETIME;
goto done;
}
loops--;
udelay(LOOPS_USEC);
}
}
/* No other transfers on the queue */
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
dqh->size_ioc_int_sts = 0;
/*
* Ensure that updates to the QH will
* occur before priming.
*/
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
}
} else {
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
dqh->size_ioc_int_sts = 0;
/* Ensure that updates to the QH will occur before priming. */
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
if (direction == EP_DIR_IN) {
/* FIXME add status check after prime the IN ep */
int prime_again;
u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
loops = LOOPS(DTD_TIMEOUT);
prime_again = 0;
while ((curr_dtd_ptr != req->head->td_dma)) {
curr_dtd_ptr = dqh->curr_dtd_ptr;
if (loops == 0) {
dev_err(&udc->dev->dev,
"failed to prime %s\n",
ep->name);
retval = -ETIME;
goto done;
}
loops--;
udelay(LOOPS_USEC);
if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
if (prime_again)
goto done;
dev_info(&udc->dev->dev,
"prime again\n");
writel(bit_pos,
&udc->op_regs->epprime);
prime_again = 1;
}
}
}
if (epstatus)
goto done;
}
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
/* clear active and halt bit, in case set from a previous error */
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
/* Ensure that updates to the QH will occure before priming. */
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
done:
return retval;
}
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
dma_addr_t *dma, int *is_last)
{
@ -841,6 +778,27 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0;
}
static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
{
struct mv_dqh *dqh = ep->dqh;
u32 bit_pos;
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
/* clear active and halt bit, in case set from a previous error */
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
/* Ensure that updates to the QH will occure before priming. */
wmb();
bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
/* Prime the Endpoint */
writel(bit_pos, &ep->udc->op_regs->epprime);
}
/* dequeues (cancels, unlinks) an I/O request from an endpoint */
static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
@ -883,15 +841,13 @@ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
/* The request isn't the last request in this ep queue */
if (req->queue.next != &ep->queue) {
struct mv_dqh *qh;
struct mv_req *next_req;
qh = ep->dqh;
next_req = list_entry(req->queue.next, struct mv_req,
queue);
next_req = list_entry(req->queue.next,
struct mv_req, queue);
/* Point the QH to the first TD of next request */
writel((u32) next_req->head, &qh->curr_dtd_ptr);
mv_prime_ep(ep, next_req);
} else {
struct mv_dqh *qh;
@ -1056,6 +1012,8 @@ static void udc_stop(struct mv_udc *udc)
USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
writel(tmp, &udc->op_regs->usbintr);
udc->stopped = 1;
/* Reset the Run the bit in the command register to stop VUSB */
tmp = readl(&udc->op_regs->usbcmd);
tmp &= ~USBCMD_RUN_STOP;
@ -1072,6 +1030,8 @@ static void udc_start(struct mv_udc *udc)
/* Enable interrupts */
writel(usbintr, &udc->op_regs->usbintr);
udc->stopped = 0;
/* Set the Run bit in the command register */
writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
}
@ -1134,11 +1094,11 @@ static int udc_reset(struct mv_udc *udc)
return 0;
}
static int mv_udc_enable(struct mv_udc *udc)
static int mv_udc_enable_internal(struct mv_udc *udc)
{
int retval;
if (udc->clock_gating == 0 || udc->active)
if (udc->active)
return 0;
dev_dbg(&udc->dev->dev, "enable udc\n");
@ -1157,9 +1117,17 @@ static int mv_udc_enable(struct mv_udc *udc)
return 0;
}
static void mv_udc_disable(struct mv_udc *udc)
static int mv_udc_enable(struct mv_udc *udc)
{
if (udc->clock_gating && udc->active) {
if (udc->clock_gating)
return mv_udc_enable_internal(udc);
return 0;
}
static void mv_udc_disable_internal(struct mv_udc *udc)
{
if (udc->active) {
dev_dbg(&udc->dev->dev, "disable udc\n");
if (udc->pdata->phy_deinit)
udc->pdata->phy_deinit(udc->phy_regs);
@ -1168,6 +1136,12 @@ static void mv_udc_disable(struct mv_udc *udc)
}
}
static void mv_udc_disable(struct mv_udc *udc)
{
if (udc->clock_gating)
mv_udc_disable_internal(udc);
}
static int mv_udc_get_frame(struct usb_gadget *gadget)
{
struct mv_udc *udc;
@ -1178,7 +1152,7 @@ static int mv_udc_get_frame(struct usb_gadget *gadget)
udc = container_of(gadget, struct mv_udc, gadget);
retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS;
retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
return retval;
}
@ -1212,10 +1186,11 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct mv_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
udc->vbus_active = (is_active != 0);
dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
__func__, udc->softconnect, udc->vbus_active);
udc->vbus_active = (is_active != 0);
if (udc->driver && udc->softconnect && udc->vbus_active) {
retval = mv_udc_enable(udc);
if (retval == 0) {
@ -1244,10 +1219,11 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
udc = container_of(gadget, struct mv_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
udc->softconnect = (is_on != 0);
dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
__func__, udc->softconnect, udc->vbus_active);
udc->softconnect = (is_on != 0);
if (udc->driver && udc->softconnect && udc->vbus_active) {
retval = mv_udc_enable(udc);
if (retval == 0) {
@ -1407,6 +1383,20 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
return retval;
}
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
if (retval) {
dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n");
if (driver->unbind) {
driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
}
return retval;
}
}
/* pullup is always on */
mv_udc_pullup(&udc->gadget, 1);
@ -2026,6 +2016,10 @@ static irqreturn_t mv_udc_irq(int irq, void *dev)
struct mv_udc *udc = (struct mv_udc *)dev;
u32 status, intr;
/* Disable ISR when stopped bit is set */
if (udc->stopped)
return IRQ_NONE;
spin_lock(&udc->lock);
status = readl(&udc->op_regs->usbsts);
@ -2109,7 +2103,12 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
destroy_workqueue(udc->qwork);
}
if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
/*
* If we have transceiver inited,
* then vbus irq will not be requested in udc driver.
*/
if (udc->pdata && udc->pdata->vbus
&& udc->clock_gating && udc->transceiver == NULL)
free_irq(udc->pdata->vbus->irq, &dev->dev);
/* free memory allocated in probe */
@ -2129,11 +2128,9 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
if (udc->cap_regs)
iounmap(udc->cap_regs);
udc->cap_regs = NULL;
if (udc->phy_regs)
iounmap((void *)udc->phy_regs);
udc->phy_regs = 0;
iounmap(udc->phy_regs);
if (udc->status_req) {
kfree(udc->status_req->req.buf);
@ -2182,6 +2179,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
udc->dev = dev;
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG)
udc->transceiver = otg_get_transceiver();
#endif
udc->clknum = pdata->clknum;
for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
@ -2213,24 +2215,20 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
goto err_iounmap_capreg;
}
udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
if (udc->phy_regs == 0) {
udc->phy_regs = ioremap(r->start, resource_size(r));
if (udc->phy_regs == NULL) {
dev_err(&dev->dev, "failed to map phy I/O memory\n");
retval = -EBUSY;
goto err_iounmap_capreg;
}
/* we will acces controller register, so enable the clk */
udc_clock_enable(udc);
if (pdata->phy_init) {
retval = pdata->phy_init(udc->phy_regs);
if (retval) {
dev_err(&dev->dev, "phy init error %d\n", retval);
goto err_iounmap_phyreg;
}
}
retval = mv_udc_enable_internal(udc);
if (retval)
goto err_iounmap_phyreg;
udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
udc->op_regs =
(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
+ (readl(&udc->cap_regs->caplength_hciversion)
& CAPLENGTH_MASK));
udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
@ -2312,7 +2310,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */
INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */
udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
udc->gadget.is_dualspeed = 1; /* support dual speed */
udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&udc->gadget.dev, "gadget");
@ -2328,7 +2326,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
eps_init(udc);
/* VBUS detect: we can disable/enable clock on demand.*/
if (pdata->vbus) {
if (udc->transceiver)
udc->clock_gating = 1;
else if (pdata->vbus) {
udc->clock_gating = 1;
retval = request_threaded_irq(pdata->vbus->irq, NULL,
mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
@ -2354,11 +2354,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
* If not, it means that VBUS detection is not supported, we
* have to enable vbus active all the time to let controller work.
*/
if (udc->clock_gating) {
if (udc->pdata->phy_deinit)
udc->pdata->phy_deinit(udc->phy_regs);
udc_clock_disable(udc);
} else
if (udc->clock_gating)
mv_udc_disable_internal(udc);
else
udc->vbus_active = 1;
retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
@ -2371,7 +2369,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
return 0;
err_unregister:
if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
if (udc->pdata && udc->pdata->vbus
&& udc->clock_gating && udc->transceiver == NULL)
free_irq(pdata->vbus->irq, &dev->dev);
device_unregister(&udc->gadget.dev);
err_free_irq:
@ -2387,11 +2386,9 @@ err_free_dma:
dma_free_coherent(&dev->dev, udc->ep_dqh_size,
udc->ep_dqh, udc->ep_dqh_dma);
err_disable_clock:
if (udc->pdata->phy_deinit)
udc->pdata->phy_deinit(udc->phy_regs);
udc_clock_disable(udc);
mv_udc_disable_internal(udc);
err_iounmap_phyreg:
iounmap((void *)udc->phy_regs);
iounmap(udc->phy_regs);
err_iounmap_capreg:
iounmap(udc->cap_regs);
err_put_clk:
@ -2407,7 +2404,30 @@ static int mv_udc_suspend(struct device *_dev)
{
struct mv_udc *udc = the_controller;
udc_stop(udc);
/* if OTG is enabled, the following will be done in OTG driver*/
if (udc->transceiver)
return 0;
if (udc->pdata->vbus && udc->pdata->vbus->poll)
if (udc->pdata->vbus->poll() == VBUS_HIGH) {
dev_info(&udc->dev->dev, "USB cable is connected!\n");
return -EAGAIN;
}
/*
* only cable is unplugged, udc can suspend.
* So do not care about clock_gating == 1.
*/
if (!udc->clock_gating) {
udc_stop(udc);
spin_lock_irq(&udc->lock);
/* stop all usb activities */
stop_activity(udc, udc->driver);
spin_unlock_irq(&udc->lock);
mv_udc_disable_internal(udc);
}
return 0;
}
@ -2417,20 +2437,22 @@ static int mv_udc_resume(struct device *_dev)
struct mv_udc *udc = the_controller;
int retval;
if (udc->pdata->phy_init) {
retval = udc->pdata->phy_init(udc->phy_regs);
if (retval) {
dev_err(&udc->dev->dev,
"init phy error %d when resume back\n",
retval);
/* if OTG is enabled, the following will be done in OTG driver*/
if (udc->transceiver)
return 0;
if (!udc->clock_gating) {
retval = mv_udc_enable_internal(udc);
if (retval)
return retval;
if (udc->driver && udc->softconnect) {
udc_reset(udc);
ep0_reset(udc);
udc_start(udc);
}
}
udc_reset(udc);
ep0_reset(udc);
udc_start(udc);
return 0;
}
@ -2457,30 +2479,16 @@ static struct platform_driver udc_driver = {
.shutdown = mv_udc_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "pxa-u2o",
.name = "mv-udc",
#ifdef CONFIG_PM
.pm = &mv_udc_pm_ops,
#endif
},
};
MODULE_ALIAS("platform:pxa-u2o");
module_platform_driver(udc_driver);
MODULE_ALIAS("platform:mv-udc");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
static int __init init(void)
{
return platform_driver_register(&udc_driver);
}
module_init(init);
static void __exit cleanup(void)
{
platform_driver_unregister(&udc_driver);
}
module_exit(cleanup);

View File

@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget,
unsigned i;
if (!driver || !driver->unbind || !driver->setup ||
driver->speed != USB_SPEED_HIGH)
driver->max_speed != USB_SPEED_HIGH)
return -EINVAL;
dev = container_of(_gadget, struct net2272, gadget);
@ -2235,7 +2235,7 @@ net2272_probe_init(struct device *dev, unsigned int irq)
ret->irq = irq;
ret->dev = dev;
ret->gadget.ops = &net2272_ops;
ret->gadget.is_dualspeed = 1;
ret->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&ret->gadget.dev, "gadget");

View File

@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget,
* (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
* "must not be used in normal operation"
*/
if (!driver || driver->speed < USB_SPEED_HIGH
if (!driver || driver->max_speed < USB_SPEED_HIGH
|| !driver->setup)
return -EINVAL;
@ -2698,7 +2698,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init (&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &net2280_ops;
dev->gadget.is_dualspeed = 1;
dev->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");

View File

@ -2110,7 +2110,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
return -ENODEV;
if (!driver
// FIXME if otg, check: driver->is_otg
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind || !driver->setup)
return -EINVAL;
@ -2676,6 +2676,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
INIT_LIST_HEAD(&udc->gadget.ep_list);
INIT_LIST_HEAD(&udc->iso);
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_FULL;
udc->gadget.name = driver_name;
device_initialize(&udc->gadget.dev);

View File

@ -2693,7 +2693,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
struct pch_udc_dev *dev = pch_udc;
int retval;
if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind ||
if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind ||
!driver->setup || !driver->unbind || !driver->disconnect) {
dev_err(&dev->pdev->dev,
"%s: invalid driver parameter\n", __func__);
@ -2941,7 +2941,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
dev->gadget.dev.release = gadget_release;
dev->gadget.name = KBUILD_MODNAME;
dev->gadget.is_dualspeed = 1;
dev->gadget.max_speed = USB_SPEED_HIGH;
retval = device_register(&dev->gadget.dev);
if (retval)

View File

@ -1141,7 +1141,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
/*
* assumes ep0 uses the same value for both
@ -1155,7 +1155,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
/* FALLTHROUGH */
#endif /* CONFIG_USB_GADGET_DUALSPEED */
@ -1535,7 +1535,7 @@ fail:
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver printer_driver = {
.speed = DEVSPEED,
.max_speed = DEVSPEED,
.function = (char *) driver_desc,
.unbind = printer_unbind,

View File

@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver,
int retval;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| driver->max_speed < USB_SPEED_FULL
|| !bind
|| !driver->disconnect
|| !driver->setup)

View File

@ -1807,7 +1807,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
struct pxa_udc *udc = the_controller;
int retval;
if (!driver || driver->speed < USB_SPEED_FULL || !bind
if (!driver || driver->max_speed < USB_SPEED_FULL || !bind
|| !driver->disconnect || !driver->setup)
return -EINVAL;
if (!udc)

View File

@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget,
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
if (!driver
|| driver->speed < USB_SPEED_HIGH
|| driver->max_speed < USB_SPEED_HIGH
|| !driver->setup)
return -EINVAL;
if (!r8a66597)
@ -1911,7 +1911,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->gadget.ops = &r8a66597_gadget_ops;
dev_set_name(&r8a66597->gadget.dev, "gadget");
r8a66597->gadget.is_dualspeed = 1;
r8a66597->gadget.max_speed = USB_SPEED_HIGH;
r8a66597->gadget.dev.parent = &pdev->dev;
r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
r8a66597->gadget.dev.release = pdev->dev.release;

View File

@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
return -EINVAL;
}
if (driver->speed < USB_SPEED_FULL)
if (driver->max_speed < USB_SPEED_FULL)
dev_err(hsotg->dev, "%s: bad speed\n", __func__);
if (!bind || !driver->setup) {
@ -3362,7 +3362,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
dev_set_name(&hsotg->gadget.dev, "gadget");
hsotg->gadget.is_dualspeed = 1;
hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev);
@ -3467,18 +3467,7 @@ static struct platform_driver s3c_hsotg_driver = {
.resume = s3c_hsotg_resume,
};
static int __init s3c_hsotg_modinit(void)
{
return platform_driver_register(&s3c_hsotg_driver);
}
static void __exit s3c_hsotg_modexit(void)
{
platform_driver_unregister(&s3c_hsotg_driver);
}
module_init(s3c_hsotg_modinit);
module_exit(s3c_hsotg_modexit);
module_platform_driver(s3c_hsotg_driver);
MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");

View File

@ -28,9 +28,10 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/prefetch.h>
#include <linux/platform_data/s3c-hsudc.h>
#include <linux/regulator/consumer.h>
#include <mach/regs-s3c2443-clock.h>
#include <plat/udc.h>
#define S3C_HSUDC_REG(x) (x)
@ -87,6 +88,12 @@
#define DATA_STATE_XMIT (1)
#define DATA_STATE_RECV (2)
static const char * const s3c_hsudc_supply_names[] = {
"vdda", /* analog phy supply, 3.3V */
"vddi", /* digital phy supply, 1.2V */
"vddosc", /* oscillator supply, 1.8V - 3.3V */
};
/**
* struct s3c_hsudc_ep - Endpoint representation used by driver.
* @ep: USB gadget layer representation of device endpoint.
@ -139,6 +146,7 @@ struct s3c_hsudc {
struct device *dev;
struct s3c24xx_hsudc_platdata *pd;
struct otg_transceiver *transceiver;
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
spinlock_t lock;
void __iomem *regs;
struct resource *mem_rsrc;
@ -153,7 +161,6 @@ struct s3c_hsudc {
#define ep_index(_ep) ((_ep)->bEndpointAddress & \
USB_ENDPOINT_NUMBER_MASK)
static struct s3c_hsudc *the_controller;
static const char driver_name[] = "s3c-udc";
static const char ep0name[] = "ep0-control";
@ -282,8 +289,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
* All the endpoints are stopped and any pending transfer requests if any on
* the endpoint are terminated.
*/
static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
struct usb_gadget_driver *driver)
static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
{
struct s3c_hsudc_ep *hsep;
int epnum;
@ -295,10 +301,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
hsep->stopped = 1;
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
}
spin_unlock(&hsudc->lock);
driver->disconnect(&hsudc->gadget);
spin_lock(&hsudc->lock);
}
/**
@ -1135,16 +1137,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
return IRQ_HANDLED;
}
static int s3c_hsudc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
static int s3c_hsudc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
struct s3c_hsudc *hsudc = the_controller;
struct s3c_hsudc *hsudc = to_hsudc(gadget);
int ret;
if (!driver
|| driver->speed < USB_SPEED_FULL
|| !bind
|| !driver->unbind || !driver->disconnect || !driver->setup)
|| driver->max_speed < USB_SPEED_FULL
|| !driver->setup)
return -EINVAL;
if (!hsudc)
@ -1155,21 +1156,12 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
hsudc->driver = driver;
hsudc->gadget.dev.driver = &driver->driver;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
ret = device_add(&hsudc->gadget.dev);
if (ret) {
dev_err(hsudc->dev, "failed to probe gadget device");
return ret;
}
ret = bind(&hsudc->gadget);
if (ret) {
dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
device_del(&hsudc->gadget.dev);
hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
hsudc->supplies);
if (ret != 0) {
dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
goto err_supplies;
}
/* connect to bus through transceiver */
@ -1178,13 +1170,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
if (ret) {
dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
hsudc->gadget.name);
driver->unbind(&hsudc->gadget);
device_del(&hsudc->gadget.dev);
hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
return ret;
goto err_otg;
}
}
@ -1197,34 +1183,43 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
hsudc->pd->gpio_init();
return 0;
err_otg:
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
return ret;
}
static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
static int s3c_hsudc_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
struct s3c_hsudc *hsudc = the_controller;
struct s3c_hsudc *hsudc = to_hsudc(gadget);
unsigned long flags;
if (!hsudc)
return -ENODEV;
if (!driver || driver != hsudc->driver || !driver->unbind)
if (!driver || driver != hsudc->driver)
return -EINVAL;
spin_lock_irqsave(&hsudc->lock, flags);
hsudc->driver = 0;
hsudc->driver = NULL;
hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
if (hsudc->pd->gpio_uninit)
hsudc->pd->gpio_uninit();
s3c_hsudc_stop_activity(hsudc, driver);
s3c_hsudc_stop_activity(hsudc);
spin_unlock_irqrestore(&hsudc->lock, flags);
if (hsudc->transceiver)
(void) otg_set_peripheral(hsudc->transceiver, NULL);
driver->unbind(&hsudc->gadget);
device_del(&hsudc->gadget.dev);
disable_irq(hsudc->irq);
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
driver->driver.name);
return 0;
@ -1242,7 +1237,7 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
struct s3c_hsudc *hsudc = the_controller;
struct s3c_hsudc *hsudc = to_hsudc(gadget);
if (!hsudc)
return -ENODEV;
@ -1255,18 +1250,18 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
.get_frame = s3c_hsudc_gadget_getframe,
.start = s3c_hsudc_start,
.stop = s3c_hsudc_stop,
.udc_start = s3c_hsudc_start,
.udc_stop = s3c_hsudc_stop,
.vbus_draw = s3c_hsudc_vbus_draw,
};
static int s3c_hsudc_probe(struct platform_device *pdev)
static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct s3c_hsudc *hsudc;
struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
int ret;
int ret, i;
hsudc = kzalloc(sizeof(struct s3c_hsudc) +
sizeof(struct s3c_hsudc_ep) * pd->epnum,
@ -1276,13 +1271,22 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
return -ENOMEM;
}
the_controller = hsudc;
platform_set_drvdata(pdev, dev);
hsudc->dev = dev;
hsudc->pd = pdev->dev.platform_data;
hsudc->transceiver = otg_get_transceiver();
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
hsudc->supplies);
if (ret != 0) {
dev_err(dev, "failed to request supplies: %d\n", ret);
goto err_supplies;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "unable to obtain driver resource data\n");
@ -1307,10 +1311,9 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
spin_lock_init(&hsudc->lock);
device_initialize(&hsudc->gadget.dev);
dev_set_name(&hsudc->gadget.dev, "gadget");
hsudc->gadget.is_dualspeed = 1;
hsudc->gadget.max_speed = USB_SPEED_HIGH;
hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
hsudc->gadget.name = dev_name(dev);
hsudc->gadget.dev.parent = dev;
@ -1319,6 +1322,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
hsudc->gadget.is_otg = 0;
hsudc->gadget.is_a_peripheral = 0;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_setup_ep(hsudc);
@ -1348,12 +1352,20 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
disable_irq(hsudc->irq);
local_irq_enable();
ret = device_register(&hsudc->gadget.dev);
if (ret) {
put_device(&hsudc->gadget.dev);
goto err_add_device;
}
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
if (ret)
goto err_add_udc;
return 0;
err_add_udc:
device_unregister(&hsudc->gadget.dev);
err_add_device:
clk_disable(hsudc->uclk);
clk_put(hsudc->uclk);
err_clk:
@ -1362,10 +1374,13 @@ err_irq:
iounmap(hsudc->regs);
err_remap:
release_resource(hsudc->mem_rsrc);
kfree(hsudc->mem_rsrc);
release_mem_region(res->start, resource_size(res));
err_res:
if (hsudc->transceiver)
otg_put_transceiver(hsudc->transceiver);
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
kfree(hsudc);
return ret;
}
@ -1377,21 +1392,10 @@ static struct platform_driver s3c_hsudc_driver = {
},
.probe = s3c_hsudc_probe,
};
MODULE_ALIAS("platform:s3c-hsudc");
static int __init s3c_hsudc_modinit(void)
{
return platform_driver_register(&s3c_hsudc_driver);
}
static void __exit s3c_hsudc_modexit(void)
{
platform_driver_unregister(&s3c_hsudc_driver);
}
module_init(s3c_hsudc_modinit);
module_exit(s3c_hsudc_modexit);
module_platform_driver(s3c_hsudc_driver);
MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c-hsudc");

View File

@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver,
if (udc->driver)
return -EBUSY;
if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) {
if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
bind, driver->setup, driver->speed);
bind, driver->setup, driver->max_speed);
return -EINVAL;
}
#if defined(MODULE)

View File

@ -371,14 +371,28 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
static ssize_t usb_udc_speed_show(struct device *dev,
#define USB_UDC_SPEED_ATTR(name, param) \
ssize_t usb_udc_##param##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
/* TODO: Scheduled for removal in 3.8. */
static ssize_t usb_udc_is_dualspeed_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
return snprintf(buf, PAGE_SIZE, "%s\n",
usb_speed_string(udc->gadget->speed));
return snprintf(buf, PAGE_SIZE, "%d\n",
gadget_is_dualspeed(udc->gadget));
}
static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL);
static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL);
#define USB_UDC_ATTR(name) \
ssize_t usb_udc_##name##_show(struct device *dev, \
@ -391,7 +405,6 @@ ssize_t usb_udc_##name##_show(struct device *dev, \
} \
static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL)
static USB_UDC_ATTR(is_dualspeed);
static USB_UDC_ATTR(is_otg);
static USB_UDC_ATTR(is_a_peripheral);
static USB_UDC_ATTR(b_hnp_enable);
@ -401,7 +414,8 @@ static USB_UDC_ATTR(a_alt_hnp_support);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
&dev_attr_soft_connect.attr,
&dev_attr_speed.attr,
&dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr,
&dev_attr_is_dualspeed.attr,
&dev_attr_is_otg.attr,

View File

@ -13,82 +13,17 @@
#include <linux/string.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/nls.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <asm/unaligned.h>
static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
{
int count = 0;
u8 c;
u16 uchar;
/* this insists on correct encodings, though not minimal ones.
* BUT it currently rejects legit 4-byte UTF-8 code points,
* which need surrogate pairs. (Unicode 3.1 can use them.)
*/
while (len != 0 && (c = (u8) *s++) != 0) {
if (unlikely(c & 0x80)) {
// 2-byte sequence:
// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
if ((c & 0xe0) == 0xc0) {
uchar = (c & 0x1f) << 6;
c = (u8) *s++;
if ((c & 0xc0) != 0x80)
goto fail;
c &= 0x3f;
uchar |= c;
// 3-byte sequence (most CJKV characters):
// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
} else if ((c & 0xf0) == 0xe0) {
uchar = (c & 0x0f) << 12;
c = (u8) *s++;
if ((c & 0xc0) != 0x80)
goto fail;
c &= 0x3f;
uchar |= c << 6;
c = (u8) *s++;
if ((c & 0xc0) != 0x80)
goto fail;
c &= 0x3f;
uchar |= c;
/* no bogus surrogates */
if (0xd800 <= uchar && uchar <= 0xdfff)
goto fail;
// 4-byte sequence (surrogate pairs, currently rare):
// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
// = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
// (uuuuu = wwww + 1)
// FIXME accept the surrogate code points (only)
} else
goto fail;
} else
uchar = c;
put_unaligned_le16(uchar, cp++);
count++;
len--;
}
return count;
fail:
return -1;
}
/**
* usb_gadget_get_string - fill out a string descriptor
* @table: of c strings encoded using UTF-8
* @id: string id, from low byte of wValue in get string descriptor
* @buf: at least 256 bytes
* @buf: at least 256 bytes, must be 16-bit aligned
*
* Finds the UTF-8 string matching the ID, and converts it into a
* string descriptor in utf16-le.
@ -125,8 +60,8 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
/* string descriptors have length, tag, then UTF16-LE text */
len = min ((size_t) 126, strlen (s->s));
memset (buf + 2, 0, 2 * len); /* zero all the bytes */
len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
(wchar_t *) &buf[2], 126);
if (len < 0)
return -EINVAL;
buf [0] = (len + 1) * 2;

View File

@ -194,6 +194,15 @@ config USB_EHCI_S5P
help
Enable support for the S5P SOC's on-chip EHCI controller.
config USB_EHCI_MV
bool "EHCI support for Marvell on-chip controller"
depends on USB_EHCI_HCD
select USB_EHCI_ROOT_HUB_TT
---help---
Enables support for Marvell (including PXA and MMP series) on-chip
USB SPH and OTG controller. SPH is a single port host, and it can
only be EHCI host. OTG is controller that can switch to host mode.
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
depends on USB_EHCI_HCD && ARCH_W90X900

View File

@ -23,6 +23,7 @@ static int au1xxx_ehci_setup(struct usb_hcd *hcd)
int ret = ehci_init(hcd);
ehci->need_io_watchdog = 0;
ehci_reset(ehci);
return ret;
}

View File

@ -48,6 +48,10 @@
#include <asm/system.h>
#include <asm/unaligned.h>
#if defined(CONFIG_PPC_PS3)
#include <asm/firmware.h>
#endif
/*-------------------------------------------------------------------------*/
/*
@ -230,12 +234,58 @@ static int ehci_halt (struct ehci_hcd *ehci)
STS_HALT, STS_HALT, 16 * 125);
}
#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
/*
* The EHCI controller of the Cell Super Companion Chip used in the
* PS3 will stop the root hub after all root hub ports are suspended.
* When in this condition handshake will return -ETIMEDOUT. The
* STS_HLT bit will not be set, so inspection of the frame index is
* used here to test for the condition. If the condition is found
* return success to allow the USB suspend to complete.
*/
static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
void __iomem *ptr, u32 mask, u32 done,
int usec)
{
unsigned int old_index;
int error;
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ETIMEDOUT;
old_index = ehci_read_frame_index(ehci);
error = handshake(ehci, ptr, mask, done, usec);
if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
return 0;
return error;
}
#else
static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
void __iomem *ptr, u32 mask, u32 done,
int usec)
{
return -ETIMEDOUT;
}
#endif
static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
u32 mask, u32 done, int usec)
{
int error;
error = handshake(ehci, ptr, mask, done, usec);
if (error == -ETIMEDOUT)
error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
usec);
if (error) {
ehci_halt(ehci);
ehci->rh_state = EHCI_RH_HALTED;
@ -620,6 +670,7 @@ static int ehci_init(struct usb_hcd *hcd)
hw = ehci->async->hw;
hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7)); /* I = 1 */
hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
hw->hw_qtd_next = EHCI_LIST_END(ehci);
ehci->async->qh_state = QH_STATE_LINKED;
@ -677,22 +728,13 @@ static int ehci_init(struct usb_hcd *hcd)
static int ehci_run (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int retval;
u32 temp;
u32 hcc_params;
hcd->uses_new_polling = 1;
/* EHCI spec section 4.1 */
/*
* TDI driver does the ehci_reset in their reset callback.
* Don't reset here, because configuration settings will
* vanish.
*/
if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
@ -1324,11 +1366,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_pxa168_driver
#endif
#ifdef CONFIG_NLM_XLR
#ifdef CONFIG_CPU_XLR
#include "ehci-xls.c"
#define PLATFORM_DRIVER ehci_xls_driver
#endif
#ifdef CONFIG_USB_EHCI_MV
#include "ehci-mv.c"
#define PLATFORM_DRIVER ehci_mv_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)

391
drivers/usb/host/ehci-mv.c Normal file
View File

@ -0,0 +1,391 @@
/*
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
* Author: Chao Xie <chao.xie@marvell.com>
* Neil Zhang <zhangwm@marvell.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/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
#define CAPLENGTH_MASK (0xff)
struct ehci_hcd_mv {
struct usb_hcd *hcd;
/* Which mode does this ehci running OTG/Host ? */
int mode;
void __iomem *phy_regs;
void __iomem *cap_regs;
void __iomem *op_regs;
struct otg_transceiver *otg;
struct mv_usb_platform_data *pdata;
/* clock source and total clock number */
unsigned int clknum;
struct clk *clk[0];
};
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
{
unsigned int i;
for (i = 0; i < ehci_mv->clknum; i++)
clk_enable(ehci_mv->clk[i]);
}
static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
{
unsigned int i;
for (i = 0; i < ehci_mv->clknum; i++)
clk_disable(ehci_mv->clk[i]);
}
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
{
int retval;
ehci_clock_enable(ehci_mv);
if (ehci_mv->pdata->phy_init) {
retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
if (retval)
return retval;
}
return 0;
}
static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
{
if (ehci_mv->pdata->phy_deinit)
ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
ehci_clock_disable(ehci_mv);
}
static int mv_ehci_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct device *dev = hcd->self.controller;
struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
int retval;
if (ehci_mv == NULL) {
dev_err(dev, "Can not find private ehci data\n");
return -ENODEV;
}
/*
* data structure init
*/
retval = ehci_init(hcd);
if (retval) {
dev_err(dev, "ehci_init failed %d\n", retval);
return retval;
}
hcd->has_tt = 1;
ehci->sbrn = 0x20;
retval = ehci_reset(ehci);
if (retval) {
dev_err(dev, "ehci_reset failed %d\n", retval);
return retval;
}
return 0;
}
static const struct hc_driver mv_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Marvell EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = mv_ehci_reset,
.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,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
};
static int mv_ehci_probe(struct platform_device *pdev)
{
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct ehci_hcd_mv *ehci_mv;
struct resource *r;
int clk_i, retval = -ENODEV;
u32 offset;
size_t size;
if (!pdata) {
dev_err(&pdev->dev, "missing platform_data\n");
return -ENODEV;
}
if (usb_disabled())
return -ENODEV;
hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
if (!hcd)
return -ENOMEM;
size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
ehci_mv = kzalloc(size, GFP_KERNEL);
if (ehci_mv == NULL) {
dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
retval = -ENOMEM;
goto err_put_hcd;
}
platform_set_drvdata(pdev, ehci_mv);
ehci_mv->pdata = pdata;
ehci_mv->hcd = hcd;
ehci_mv->clknum = pdata->clknum;
for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
ehci_mv->clk[clk_i] =
clk_get(&pdev->dev, pdata->clkname[clk_i]);
if (IS_ERR(ehci_mv->clk[clk_i])) {
dev_err(&pdev->dev, "error get clck \"%s\"\n",
pdata->clkname[clk_i]);
retval = PTR_ERR(ehci_mv->clk[clk_i]);
goto err_put_clk;
}
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
if (r == NULL) {
dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
retval = -ENODEV;
goto err_put_clk;
}
ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
if (ehci_mv->phy_regs == 0) {
dev_err(&pdev->dev, "failed to map phy I/O memory\n");
retval = -EFAULT;
goto err_put_clk;
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
if (!r) {
dev_err(&pdev->dev, "no I/O memory resource defined\n");
retval = -ENODEV;
goto err_iounmap_phyreg;
}
ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
if (ehci_mv->cap_regs == NULL) {
dev_err(&pdev->dev, "failed to map I/O memory\n");
retval = -EFAULT;
goto err_iounmap_phyreg;
}
retval = mv_ehci_enable(ehci_mv);
if (retval) {
dev_err(&pdev->dev, "init phy error %d\n", retval);
goto err_iounmap_capreg;
}
offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
ehci_mv->op_regs =
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
hcd->rsrc_start = r->start;
hcd->rsrc_len = r->end - r->start + 1;
hcd->regs = ehci_mv->op_regs;
hcd->irq = platform_get_irq(pdev, 0);
if (!hcd->irq) {
dev_err(&pdev->dev, "Cannot get irq.");
retval = -ENODEV;
goto err_disable_clk;
}
ehci = hcd_to_ehci(hcd);
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
#ifdef CONFIG_USB_OTG_UTILS
ehci_mv->otg = otg_get_transceiver();
if (!ehci_mv->otg) {
dev_err(&pdev->dev,
"unable to find transceiver\n");
retval = -ENODEV;
goto err_disable_clk;
}
retval = otg_set_host(ehci_mv->otg, &hcd->self);
if (retval < 0) {
dev_err(&pdev->dev,
"unable to register with transceiver\n");
retval = -ENODEV;
goto err_put_transceiver;
}
/* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv);
#else
dev_info(&pdev->dev, "MV_USB_MODE_OTG "
"must have CONFIG_USB_OTG_UTILS enabled\n");
goto err_disable_clk;
#endif
} else {
if (pdata->set_vbus)
pdata->set_vbus(1);
retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
if (retval) {
dev_err(&pdev->dev,
"failed to add hcd with err %d\n", retval);
goto err_set_vbus;
}
}
if (pdata->private_init)
pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
dev_info(&pdev->dev,
"successful find EHCI device with regs 0x%p irq %d"
" working in %s mode\n", hcd->regs, hcd->irq,
ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
return 0;
err_set_vbus:
if (pdata->set_vbus)
pdata->set_vbus(0);
#ifdef CONFIG_USB_OTG_UTILS
err_put_transceiver:
if (ehci_mv->otg)
otg_put_transceiver(ehci_mv->otg);
#endif
err_disable_clk:
mv_ehci_disable(ehci_mv);
err_iounmap_capreg:
iounmap(ehci_mv->cap_regs);
err_iounmap_phyreg:
iounmap(ehci_mv->phy_regs);
err_put_clk:
for (clk_i--; clk_i >= 0; clk_i--)
clk_put(ehci_mv->clk[clk_i]);
platform_set_drvdata(pdev, NULL);
kfree(ehci_mv);
err_put_hcd:
usb_put_hcd(hcd);
return retval;
}
static int mv_ehci_remove(struct platform_device *pdev)
{
struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_mv->hcd;
int clk_i;
if (hcd->rh_registered)
usb_remove_hcd(hcd);
if (ehci_mv->otg) {
otg_set_host(ehci_mv->otg, NULL);
otg_put_transceiver(ehci_mv->otg);
}
if (ehci_mv->mode == MV_USB_MODE_HOST) {
if (ehci_mv->pdata->set_vbus)
ehci_mv->pdata->set_vbus(0);
mv_ehci_disable(ehci_mv);
}
iounmap(ehci_mv->cap_regs);
iounmap(ehci_mv->phy_regs);
for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
clk_put(ehci_mv->clk[clk_i]);
platform_set_drvdata(pdev, NULL);
kfree(ehci_mv);
usb_put_hcd(hcd);
return 0;
}
MODULE_ALIAS("mv-ehci");
static const struct platform_device_id ehci_id_table[] = {
{"pxa-u2oehci", PXA_U2OEHCI},
{"pxa-sph", PXA_SPH},
{"mmp3-hsic", MMP3_HSIC},
{"mmp3-fsic", MMP3_FSIC},
{},
};
static void mv_ehci_shutdown(struct platform_device *pdev)
{
struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_mv->hcd;
if (!hcd->rh_registered)
return;
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
static struct platform_driver ehci_mv_driver = {
.probe = mv_ehci_probe,
.remove = mv_ehci_remove,
.shutdown = mv_ehci_shutdown,
.driver = {
.name = "mv-ehci",
.bus = &platform_bus_type,
},
.id_table = ehci_id_table,
};

View File

@ -155,6 +155,8 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_reset(ehci);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);

View File

@ -228,6 +228,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
ehci_reset(omap_ehci);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_err(dev, "failed to add hcd with err %d\n", ret);

View File

@ -21,6 +21,34 @@
#include <asm/firmware.h>
#include <asm/ps3.h>
static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
{
/* PS3 HC internal setup register offsets. */
enum ps3_ehci_hc_insnreg {
ps3_ehci_hc_insnreg01 = 0x084,
ps3_ehci_hc_insnreg02 = 0x088,
ps3_ehci_hc_insnreg03 = 0x08c,
};
/* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
* internal INSNREGXX setup regs back to the chip default values
* on Host Controller Reset (CMD_RESET) or Light Host Controller
* Reset (CMD_LRESET). The work-around for this is for the HC
* driver to re-initialise these regs when ever the HC is reset.
*/
/* Set burst transfer counts to 256 out, 32 in. */
writel_be(0x01000020, (void __iomem *)ehci->regs +
ps3_ehci_hc_insnreg01);
/* Enable burst transfer counts. */
writel_be(0x00000001, (void __iomem *)ehci->regs +
ps3_ehci_hc_insnreg03);
}
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
{
int result;
@ -49,6 +77,8 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
ehci_reset(ehci);
ps3_ehci_setup_insnreg(ehci);
return result;
}

View File

@ -299,7 +299,7 @@ static int __devinit ehci_pxa168_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

@ -373,6 +373,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
retry_xacterr:
if ((token & QTD_STS_ACTIVE) == 0) {
/* Report Data Buffer Error: non-fatal but useful */
if (token & QTD_STS_DBE)
ehci_dbg(ehci,
"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
urb,
usb_endpoint_num(&urb->ep->desc),
usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out",
urb->transfer_buffer_length,
qtd,
qh);
/* on STALL, error, and short reads this urb must
* complete and all its qtds must be recycled.
*/
@ -647,7 +658,7 @@ qh_urb_transaction (
/*
* data transfer stage: buffer setup
*/
i = urb->num_sgs;
i = urb->num_mapped_sgs;
if (len > 0 && i > 0) {
sg = urb->sg;
buf = sg_dma_address(sg);

View File

@ -14,8 +14,6 @@
#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>
@ -136,6 +134,8 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
ehci_reset(ehci);
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");

View File

@ -132,6 +132,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
ehci_port_power(ehci, 1);
ehci_reset(ehci);
ret = usb_add_hcd(hcd, pdev->resource[1].start,
IRQF_SHARED);
if (ret == 0) {

View File

@ -78,6 +78,8 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
if (irq < 0)
goto err4;
ehci_reset(ehci);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
goto err4;

View File

@ -69,7 +69,7 @@ int ehci_xls_probe_internal(const struct hc_driver *driver,
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = res->end - res->start + 1;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {

View File

@ -824,17 +824,7 @@ static struct platform_driver of_fhci_driver = {
.remove = __devexit_p(of_fhci_remove),
};
static int __init fhci_module_init(void)
{
return platform_driver_register(&of_fhci_driver);
}
module_init(fhci_module_init);
static void __exit fhci_module_exit(void)
{
platform_driver_unregister(&of_fhci_driver);
}
module_exit(fhci_module_exit);
module_platform_driver(of_fhci_driver);
MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver");
MODULE_AUTHOR("Shlomi Gridish <gridish@freescale.com>, "

View File

@ -297,17 +297,7 @@ static struct platform_driver fsl_usb2_mph_dr_driver = {
.remove = __devexit_p(fsl_usb2_mph_dr_of_remove),
};
static int __init fsl_usb2_mph_dr_init(void)
{
return platform_driver_register(&fsl_usb2_mph_dr_driver);
}
module_init(fsl_usb2_mph_dr_init);
static void __exit fsl_usb2_mph_dr_exit(void)
{
platform_driver_unregister(&fsl_usb2_mph_dr_driver);
}
module_exit(fsl_usb2_mph_dr_exit);
module_platform_driver(fsl_usb2_mph_dr_driver);
MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");

View File

@ -776,7 +776,6 @@ static int hwahc_probe(struct usb_interface *usb_iface,
goto error_alloc;
}
usb_hcd->wireless = 1;
set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);
wusbhc = usb_hcd_to_wusbhc(usb_hcd);
hwahc = container_of(wusbhc, struct hwahc, wusbhc);
hwahc_init(hwahc);

View File

@ -1924,18 +1924,7 @@ static struct platform_driver imx21_hcd_driver = {
.resume = NULL,
};
static int __init imx21_hcd_init(void)
{
return platform_driver_register(&imx21_hcd_driver);
}
static void __exit imx21_hcd_cleanup(void)
{
platform_driver_unregister(&imx21_hcd_driver);
}
module_init(imx21_hcd_init);
module_exit(imx21_hcd_cleanup);
module_platform_driver(imx21_hcd_driver);
MODULE_DESCRIPTION("i.MX21 USB Host controller");
MODULE_AUTHOR("Martin Fuzzey");

View File

@ -32,6 +32,13 @@ static struct kmem_cache *qtd_cachep;
static struct kmem_cache *qh_cachep;
static struct kmem_cache *urb_listitem_cachep;
enum queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
u32 hcs_params;
spinlock_t lock;
@ -40,7 +47,7 @@ struct isp1760_hcd {
struct slotinfo int_slots[32];
int int_done_map;
struct memory_chunk memory_pool[BLOCKS];
struct list_head controlqhs, bulkqhs, interruptqhs;
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
@ -406,12 +413,12 @@ static int priv_init(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
u32 hcc_params;
int i;
spin_lock_init(&priv->lock);
INIT_LIST_HEAD(&priv->interruptqhs);
INIT_LIST_HEAD(&priv->controlqhs);
INIT_LIST_HEAD(&priv->bulkqhs);
for (i = 0; i < QH_END; i++)
INIT_LIST_HEAD(&priv->qh_list[i]);
/*
* hw default: 1K periodic list heads, one per frame.
@ -930,9 +937,9 @@ void schedule_ptds(struct usb_hcd *hcd)
struct isp1760_hcd *priv;
struct isp1760_qh *qh, *qh_next;
struct list_head *ep_queue;
struct usb_host_endpoint *ep;
LIST_HEAD(urb_list);
struct urb_listitem *urb_listitem, *urb_listitem_next;
int i;
if (!hcd) {
WARN_ON(1);
@ -944,28 +951,13 @@ void schedule_ptds(struct usb_hcd *hcd)
/*
* check finished/retired xfers, transfer payloads, call urb_done()
*/
ep_queue = &priv->interruptqhs;
while (ep_queue) {
for (i = 0; i < QH_END; i++) {
ep_queue = &priv->qh_list[i];
list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
ep = list_entry(qh->qtd_list.next, struct isp1760_qtd,
qtd_list)->urb->ep;
collect_qtds(hcd, qh, &urb_list);
if (list_empty(&qh->qtd_list)) {
if (list_empty(&qh->qtd_list))
list_del(&qh->qh_list);
if (ep->hcpriv == NULL) {
/* Endpoint has been disabled, so we
can free the associated queue head. */
qh_free(qh);
}
}
}
if (ep_queue == &priv->interruptqhs)
ep_queue = &priv->controlqhs;
else if (ep_queue == &priv->controlqhs)
ep_queue = &priv->bulkqhs;
else
ep_queue = NULL;
}
list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
@ -998,17 +990,10 @@ void schedule_ptds(struct usb_hcd *hcd)
*
* I'm sure this scheme could be improved upon!
*/
ep_queue = &priv->controlqhs;
while (ep_queue) {
for (i = 0; i < QH_END; i++) {
ep_queue = &priv->qh_list[i];
list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
enqueue_qtds(hcd, qh);
if (ep_queue == &priv->controlqhs)
ep_queue = &priv->interruptqhs;
else if (ep_queue == &priv->interruptqhs)
ep_queue = &priv->bulkqhs;
else
ep_queue = NULL;
}
}
@ -1543,16 +1528,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
ep_queue = &priv->controlqhs;
ep_queue = &priv->qh_list[QH_CONTROL];
break;
case PIPE_BULK:
ep_queue = &priv->bulkqhs;
ep_queue = &priv->qh_list[QH_BULK];
break;
case PIPE_INTERRUPT:
if (urb->interval < 0)
return -EINVAL;
/* FIXME: Check bandwidth */
ep_queue = &priv->interruptqhs;
ep_queue = &priv->qh_list[QH_INTERRUPT];
break;
case PIPE_ISOCHRONOUS:
dev_err(hcd->self.controller, "%s: isochronous USB packets "
@ -1714,8 +1699,8 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
unsigned long spinflags;
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
struct isp1760_qh *qh, *qh_iter;
int i;
spin_lock_irqsave(&priv->lock, spinflags);
@ -1723,14 +1708,17 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
if (!qh)
goto out;
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
if (qtd->status != QTD_RETIRE) {
dequeue_urb_from_qtd(hcd, qh, qtd);
qtd->urb->status = -ECONNRESET;
}
WARN_ON(!list_empty(&qh->qtd_list));
for (i = 0; i < QH_END; i++)
list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
if (qh_iter == qh) {
list_del(&qh_iter->qh_list);
i = QH_END;
break;
}
qh_free(qh);
ep->hcpriv = NULL;
/* Cannot free qh here since it will be parsed by schedule_ptds() */
schedule_ptds(hcd);

View File

@ -47,23 +47,27 @@ static int of_isp1760_probe(struct platform_device *dev)
int virq;
resource_size_t res_len;
int ret;
const unsigned int *prop;
unsigned int devflags = 0;
enum of_gpio_flags gpio_flags;
u32 bus_width = 0;
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
ret = of_address_to_resource(dp, 0, &memory);
if (ret)
return -ENXIO;
if (ret) {
ret = -ENXIO;
goto free_data;
}
res_len = resource_size(&memory);
res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
if (!res)
return -EBUSY;
if (!res) {
ret = -EBUSY;
goto free_data;
}
if (of_irq_map_one(dp, 0, &oirq)) {
ret = -ENODEV;
@ -77,8 +81,8 @@ static int of_isp1760_probe(struct platform_device *dev)
devflags |= ISP1760_FLAG_ISP1761;
/* Some systems wire up only 16 of the 32 data lines */
prop = of_get_property(dp, "bus-width", NULL);
if (prop && *prop == 16)
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (of_get_property(dp, "port1-otg", NULL) != NULL)
@ -125,6 +129,7 @@ free_gpio:
gpio_free(drvdata->rst_gpio);
release_reg:
release_mem_region(memory.start, res_len);
free_data:
kfree(drvdata);
return ret;
}

View File

@ -173,12 +173,9 @@ static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
*
* This is still racy as hcd->state is manipulated outside of
* any locks =P But that will be a different fix.
*/
spin_lock_irqsave(&ohci->lock, flags);
if (hcd->state != HC_STATE_SUSPENDED) {
if (ohci->rh_state != OHCI_RH_SUSPENDED) {
rc = -EINVAL;
goto bail;
}

View File

@ -127,6 +127,19 @@ static char *hcfs2string (int state)
return "?";
}
static const char *rh_state_string(struct ohci_hcd *ohci)
{
switch (ohci->rh_state) {
case OHCI_RH_HALTED:
return "halted";
case OHCI_RH_SUSPENDED:
return "suspended";
case OHCI_RH_RUNNING:
return "running";
}
return "?";
}
// dump control and status registers
static void
ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
@ -136,9 +149,10 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
temp = ohci_readl (controller, &regs->revision) & 0xff;
ohci_dbg_sw (controller, next, size,
"OHCI %d.%d, %s legacy support registers\n",
"OHCI %d.%d, %s legacy support registers, rh state %s\n",
0x03 & (temp >> 4), (temp & 0x0f),
(temp & 0x0100) ? "with" : "NO");
(temp & 0x0100) ? "with" : "NO",
rh_state_string(controller));
temp = ohci_readl (controller, &regs->control);
ohci_dbg_sw (controller, next, size,

View File

@ -179,8 +179,6 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_
ohci->next_statechange = jiffies;
ep93xx_stop_hc(&pdev->dev);
hcd->state = HC_STATE_SUSPENDED;
return 0;
}

View File

@ -209,7 +209,7 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
if (!HC_IS_RUNNING(hcd->state)) {
if (ohci->rh_state != OHCI_RH_RUNNING) {
retval = -ENODEV;
goto fail;
}
@ -274,7 +274,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc) {
; /* Do nothing */
} else if (HC_IS_RUNNING(hcd->state)) {
} else if (ohci->rh_state == OHCI_RH_RUNNING) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@ -321,7 +321,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
rescan:
spin_lock_irqsave (&ohci->lock, flags);
if (!HC_IS_RUNNING (hcd->state)) {
if (ohci->rh_state != OHCI_RH_RUNNING) {
sanitize:
ed->state = ED_IDLE;
if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
@ -377,6 +377,7 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
ohci->rh_state = OHCI_RH_HALTED;
}
/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
@ -500,7 +501,7 @@ static int ohci_init (struct ohci_hcd *ohci)
if (distrust_firmware)
ohci->flags |= OHCI_QUIRK_HUB_POWER;
disable (ohci);
ohci->rh_state = OHCI_RH_HALTED;
ohci->regs = hcd->regs;
/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
@ -575,7 +576,7 @@ static int ohci_run (struct ohci_hcd *ohci)
int first = ohci->fminterval == 0;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
disable (ohci);
ohci->rh_state = OHCI_RH_HALTED;
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
@ -688,7 +689,7 @@ retry:
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
hcd->state = HC_STATE_RUNNING;
ohci->rh_state = OHCI_RH_RUNNING;
/* wake on ConnectStatusChange, matching external hubs */
ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@ -725,7 +726,6 @@ retry:
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((val >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
if (quirk_zfmicro(ohci)) {
/* Create timer to watch for bad queue state on ZF Micro */
@ -761,7 +761,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
* of dead, unclocked, or unplugged (CardBus...) devices
*/
if (ints == ~(u32)0) {
disable (ohci);
ohci->rh_state = OHCI_RH_HALTED;
ohci_dbg (ohci, "device removed!\n");
usb_hc_died(hcd);
return IRQ_HANDLED;
@ -771,7 +771,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ints &= ohci_readl(ohci, &regs->intrenable);
/* interrupt for some other device? */
if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED))
return IRQ_NOTMINE;
if (ints & OHCI_INTR_UE) {
@ -786,8 +786,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
schedule_work (&ohci->nec_work);
} else {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
ohci->rh_state = OHCI_RH_HALTED;
usb_hc_died(hcd);
}
@ -871,11 +871,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if ((ints & OHCI_INTR_SF) != 0
&& !ohci->ed_rm_list
&& !ohci->ed_to_check
&& HC_IS_RUNNING(hcd->state))
&& ohci->rh_state == OHCI_RH_RUNNING)
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
if (HC_IS_RUNNING(hcd->state)) {
if (ohci->rh_state == OHCI_RH_RUNNING) {
ohci_writel (ohci, ints, &regs->intrstatus);
ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
// flush those writes
@ -929,7 +929,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
struct urb_priv *priv;
spin_lock_irq(&ohci->lock);
disable (ohci);
ohci->rh_state = OHCI_RH_HALTED;
/* Recycle any "live" eds/tds (and urbs). */
if (!list_empty (&ohci->pending))
@ -1111,7 +1111,7 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
#endif
#ifdef CONFIG_NLM_XLR
#ifdef CONFIG_CPU_XLR
#include "ohci-xls.c"
#define PLATFORM_DRIVER ohci_xls_driver
#endif

View File

@ -111,6 +111,7 @@ __acquires(ohci->lock)
if (!autostop) {
ohci->next_statechange = jiffies + msecs_to_jiffies (5);
ohci->autostop = 0;
ohci->rh_state = OHCI_RH_SUSPENDED;
}
done:
@ -140,7 +141,7 @@ __acquires(ohci->lock)
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
/* this can happen after resuming a swsusp snapshot */
if (hcd->state == HC_STATE_RESUMING) {
if (ohci->rh_state != OHCI_RH_RUNNING) {
ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
ohci->hc_control);
status = -EBUSY;
@ -274,6 +275,7 @@ skip_resume:
(void) ohci_readl (ohci, &ohci->regs->control);
}
ohci->rh_state = OHCI_RH_RUNNING;
return 0;
}
@ -336,11 +338,8 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
/* If needed, reinitialize and suspend the root hub */
if (need_reinit) {
spin_lock_irq(&ohci->lock);
hcd->state = HC_STATE_RESUMING;
ohci_rh_resume(ohci);
hcd->state = HC_STATE_QUIESCING;
ohci_rh_suspend(ohci, 0);
hcd->state = HC_STATE_SUSPENDED;
spin_unlock_irq(&ohci->lock);
}

View File

@ -516,7 +516,6 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
ohci->next_statechange = jiffies;
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
return 0;
}

View File

@ -308,12 +308,9 @@ static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
*
* This is still racy as hcd->state is manipulated outside of
* any locks =P But that will be a different fix.
*/
spin_lock_irqsave (&ohci->lock, flags);
if (hcd->state != HC_STATE_SUSPENDED) {
if (ohci->rh_state != OHCI_RH_SUSPENDED) {
rc = -EINVAL;
goto bail;
}

View File

@ -502,8 +502,6 @@ static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)
ohci->ohci.next_statechange = jiffies;
pxa27x_stop_hc(ohci, dev);
hcd->state = HC_STATE_SUSPENDED;
return 0;
}

View File

@ -912,7 +912,7 @@ rescan_all:
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps and EDs with partially retired TDs
*/
if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
if (likely(ohci->rh_state == OHCI_RH_RUNNING)) {
if (tick_before (tick, ed->tick)) {
skip_ed:
last = &ed->ed_next;
@ -1012,7 +1012,7 @@ rescan_this:
/* but if there's work queued, reschedule */
if (!list_empty (&ed->td_list)) {
if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))
if (ohci->rh_state == OHCI_RH_RUNNING)
ed_schedule (ohci, ed);
}
@ -1021,9 +1021,7 @@ rescan_this:
}
/* maybe reenable control and bulk lists */
if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
&& !ohci->ed_rm_list) {
if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) {
u32 command = 0, control = 0;
if (ohci->ed_controltail) {

View File

@ -486,15 +486,66 @@ static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
struct platform_device *pdev = to_platform_device(dev);
unsigned long flags;
int rc = 0;
/*
* Root hub was already suspended. Disable irq emission and
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
*/
spin_lock_irqsave(&ohci->lock, flags);
if (ohci->rh_state != OHCI_RH_SUSPENDED) {
rc = -EINVAL;
goto bail;
}
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
s3c2410_stop_hc(pdev);
bail:
spin_unlock_irqrestore(&ohci->lock, flags);
return rc;
}
static int ohci_hcd_s3c2410_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct platform_device *pdev = to_platform_device(dev);
s3c2410_start_hc(pdev, hcd);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
ohci_finish_controller_resume(hcd);
return 0;
}
#else
#define ohci_hcd_s3c2410_drv_suspend NULL
#define ohci_hcd_s3c2410_drv_resume NULL
#endif
static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = {
.suspend = ohci_hcd_s3c2410_drv_suspend,
.resume = ohci_hcd_s3c2410_drv_resume,
};
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = __devexit_p(ohci_hcd_s3c2410_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-ohci",
.pm = &ohci_hcd_s3c2410_pm_ops,
},
};

View File

@ -29,7 +29,6 @@ static int ohci_sh_start(struct usb_hcd *hcd)
ohci_hcd_init(ohci);
ohci_init(ohci);
ohci_run(ohci);
hcd->state = HC_STATE_RUNNING;
return 0;
}

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