mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (205 commits)
USB: EHCI: Remove SPARC_LEON {read,write}_be definitions from ehci.h
USB: UHCI: Support big endian GRUSBHC HC
sparc: add {read,write}*_be routines
USB: UHCI: Add support for big endian descriptors
USB: UHCI: Use ACCESS_ONCE rather than using a full compiler barrier
USB: UHCI: Add support for big endian mmio
usb-storage: Correct adjust_quirks to include latest flags
usb/isp1760: Fix possible unlink problems
usb/isp1760: Move function isp1760_endpoint_disable() within file.
USB: remove remaining usages of hcd->state from usbcore and fix regression
usb: musb: ux500: add configuration and build options for ux500 dma
usb: musb: ux500: add dma glue layer for ux500
usb: musb: ux500: add dma name for ux500
usb: musb: ux500: add ux500 specific code for gadget side
usb: musb: fix compile error
usb-storage: fix up the unusual_realtek device list
USB: gadget: f_audio: Fix invalid dereference of initdata
EHCI: don't rescan interrupt QHs needlessly
OHCI: fix regression caused by nVidia shutdown workaround
USB: OTG: msm: Free VCCCX regulator even if we can't set the voltage
...
This commit is contained in:
commit
c44dead70a
184 changed files with 14673 additions and 3402 deletions
|
|
@ -65,8 +65,10 @@ config USB_ARCH_HAS_EHCI
|
|||
default y if ARCH_CNS3XXX
|
||||
default y if ARCH_VT8500
|
||||
default y if PLAT_SPEAR
|
||||
default y if PLAT_S5P
|
||||
default y if ARCH_MSM
|
||||
default y if MICROBLAZE
|
||||
default y if SPARC_LEON
|
||||
default PCI
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
|
|
@ -116,6 +118,8 @@ source "drivers/usb/host/Kconfig"
|
|||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/renesas_usbhs/Kconfig"
|
||||
|
||||
source "drivers/usb/class/Kconfig"
|
||||
|
||||
source "drivers/usb/storage/Kconfig"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
|||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
|
||||
|
||||
|
|
@ -45,3 +46,8 @@ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
|
|||
|
||||
obj-$(CONFIG_USB_ATM) += atm/
|
||||
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += musb/
|
||||
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += otg/
|
||||
obj-$(CONFIG_USB_GADGET) += gadget/
|
||||
|
|
|
|||
|
|
@ -7,35 +7,12 @@
|
|||
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
|
||||
* Copyright (c) 2005 David Kubicek <dave@awk.cz>
|
||||
* Copyright (c) 2011 Johan Hovold <jhovold@gmail.com>
|
||||
*
|
||||
* USB Abstract Control Model driver for USB modems and ISDN adapters
|
||||
*
|
||||
* Sponsored by SuSE
|
||||
*
|
||||
* ChangeLog:
|
||||
* v0.9 - thorough cleaning, URBification, almost a rewrite
|
||||
* v0.10 - some more cleanups
|
||||
* v0.11 - fixed flow control, read error doesn't stop reads
|
||||
* v0.12 - added TIOCM ioctls, added break handling, made struct acm
|
||||
* kmalloced
|
||||
* v0.13 - added termios, added hangup
|
||||
* v0.14 - sized down struct acm
|
||||
* v0.15 - fixed flow control again - characters could be lost
|
||||
* v0.16 - added code for modems with swapped data and control interfaces
|
||||
* v0.17 - added new style probing
|
||||
* v0.18 - fixed new style probing for devices with more configurations
|
||||
* v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
|
||||
* v0.20 - switched to probing on interface (rather than device) class
|
||||
* v0.21 - revert to probing on device for devices with multiple configs
|
||||
* v0.22 - probe only the control interface. if usbcore doesn't choose the
|
||||
* config we want, sysadmin changes bConfigurationValue in sysfs.
|
||||
* v0.23 - use softirq for rx processing, as needed by tty layer
|
||||
* v0.24 - change probe method to evaluate CDC union descriptor
|
||||
* v0.25 - downstream tasks paralelized to maximize throughput
|
||||
* v0.26 - multiple write urbs, writesize increased
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
|
|
@ -74,13 +51,7 @@
|
|||
#include "cdc-acm.h"
|
||||
|
||||
|
||||
#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.26"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
|
||||
|
||||
static struct usb_driver acm_driver;
|
||||
|
|
@ -94,12 +65,6 @@ static DEFINE_MUTEX(open_mutex);
|
|||
static const struct tty_port_operations acm_port_ops = {
|
||||
};
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define verbose 1
|
||||
#else
|
||||
#define verbose 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for ACM control messages.
|
||||
*/
|
||||
|
|
@ -111,8 +76,9 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value,
|
|||
request, USB_RT_ACM, value,
|
||||
acm->control->altsetting[0].desc.bInterfaceNumber,
|
||||
buf, len, 5000);
|
||||
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
|
||||
request, value, len, retval);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - rq 0x%02x, val %#x, len %#x, result %d\n",
|
||||
__func__, request, value, len, retval);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +158,9 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
|
|||
|
||||
rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
|
||||
if (rc < 0) {
|
||||
dbg("usb_submit_urb(write bulk) failed: %d", rc);
|
||||
dev_err(&acm->data->dev,
|
||||
"%s - usb_submit_urb(write bulk) failed: %d\n",
|
||||
__func__, rc);
|
||||
acm_write_done(acm, wb);
|
||||
}
|
||||
return rc;
|
||||
|
|
@ -211,7 +179,8 @@ static int acm_write_start(struct acm *acm, int wbn)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
dbg("%s susp_count: %d", __func__, acm->susp_count);
|
||||
dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
|
||||
acm->susp_count);
|
||||
usb_autopm_get_interface_async(acm->control);
|
||||
if (acm->susp_count) {
|
||||
if (!acm->delayed_wb)
|
||||
|
|
@ -287,10 +256,14 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d", __func__, status);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __func__, status);
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - nonzero urb status received: %d\n",
|
||||
__func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -302,8 +275,8 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
data = (unsigned char *)(dr + 1);
|
||||
switch (dr->bNotificationType) {
|
||||
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
||||
dbg("%s network", dr->wValue ?
|
||||
"connected to" : "disconnected from");
|
||||
dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
|
||||
__func__, dr->wValue);
|
||||
break;
|
||||
|
||||
case USB_CDC_NOTIFY_SERIAL_STATE:
|
||||
|
|
@ -313,7 +286,8 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
if (tty) {
|
||||
if (!acm->clocal &&
|
||||
(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
dbg("calling hangup");
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - calling hangup\n", __func__);
|
||||
tty_hangup(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
|
@ -321,7 +295,10 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
|
||||
acm->ctrlin = newctrl;
|
||||
|
||||
dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - input control lines: dcd%c dsr%c break%c "
|
||||
"ring%c framing%c parity%c overrun%c\n",
|
||||
__func__,
|
||||
acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
|
||||
acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
|
||||
acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
|
||||
|
|
@ -332,7 +309,10 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
break;
|
||||
|
||||
default:
|
||||
dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - unknown notification %d received: index %d "
|
||||
"len %d data0 %d data1 %d\n",
|
||||
__func__,
|
||||
dr->bNotificationType, dr->wIndex,
|
||||
dr->wLength, data[0], data[1]);
|
||||
break;
|
||||
|
|
@ -340,166 +320,96 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||
exit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
|
||||
"result %d", __func__, retval);
|
||||
dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
/* data interface returns incoming bytes, or we got unthrottled */
|
||||
static void acm_read_bulk(struct urb *urb)
|
||||
static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
|
||||
{
|
||||
struct acm_rb *buf;
|
||||
struct acm_ru *rcv = urb->context;
|
||||
struct acm *acm = rcv->instance;
|
||||
int status = urb->status;
|
||||
int res;
|
||||
|
||||
dbg("Entering acm_read_bulk with status %d", status);
|
||||
if (!test_and_clear_bit(index, &acm->read_urbs_free))
|
||||
return 0;
|
||||
|
||||
if (!ACM_READY(acm)) {
|
||||
dev_dbg(&acm->data->dev, "Aborting, acm not ready");
|
||||
dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
|
||||
|
||||
res = usb_submit_urb(acm->read_urbs[index], mem_flags);
|
||||
if (res) {
|
||||
if (res != -EPERM) {
|
||||
dev_err(&acm->data->dev,
|
||||
"%s - usb_submit_urb failed: %d\n",
|
||||
__func__, res);
|
||||
}
|
||||
set_bit(index, &acm->read_urbs_free);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
|
||||
{
|
||||
int res;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < acm->rx_buflimit; ++i) {
|
||||
res = acm_submit_read_urb(acm, i, mem_flags);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acm_process_read_urb(struct acm *acm, struct urb *urb)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!urb->actual_length)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static void acm_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct acm_rb *rb = urb->context;
|
||||
struct acm *acm = rb->instance;
|
||||
unsigned long flags;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
|
||||
rb->index, urb->actual_length);
|
||||
set_bit(rb->index, &acm->read_urbs_free);
|
||||
|
||||
if (!acm->dev) {
|
||||
dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
|
||||
return;
|
||||
}
|
||||
usb_mark_last_busy(acm->dev);
|
||||
|
||||
if (status)
|
||||
dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
|
||||
if (urb->status) {
|
||||
dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
|
||||
__func__, urb->status);
|
||||
return;
|
||||
}
|
||||
acm_process_read_urb(acm, urb);
|
||||
|
||||
buf = rcv->buffer;
|
||||
buf->size = urb->actual_length;
|
||||
|
||||
if (likely(status == 0)) {
|
||||
spin_lock(&acm->read_lock);
|
||||
acm->processing++;
|
||||
list_add_tail(&rcv->list, &acm->spare_read_urbs);
|
||||
list_add_tail(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
/* throttle device if requested by tty */
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
acm->throttled = acm->throttle_req;
|
||||
if (!acm->throttled && !acm->susp_count) {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
|
||||
} else {
|
||||
/* we drop the buffer due to an error */
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add_tail(&rcv->list, &acm->spare_read_urbs);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
/* nevertheless the tasklet must be kicked unconditionally
|
||||
so the queue cannot dry up */
|
||||
}
|
||||
if (likely(!acm->susp_count))
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
}
|
||||
|
||||
static void acm_rx_tasklet(unsigned long _acm)
|
||||
{
|
||||
struct acm *acm = (void *)_acm;
|
||||
struct acm_rb *buf;
|
||||
struct tty_struct *tty;
|
||||
struct acm_ru *rcv;
|
||||
unsigned long flags;
|
||||
unsigned char throttled;
|
||||
|
||||
dbg("Entering acm_rx_tasklet");
|
||||
|
||||
if (!ACM_READY(acm)) {
|
||||
dbg("acm_rx_tasklet: ACM not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acm->throttle_lock, flags);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock_irqrestore(&acm->throttle_lock, flags);
|
||||
if (throttled) {
|
||||
dbg("acm_rx_tasklet: throttled");
|
||||
return;
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
|
||||
next_buffer:
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (list_empty(&acm->filled_read_bufs)) {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
goto urbs;
|
||||
}
|
||||
buf = list_entry(acm->filled_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
|
||||
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
|
||||
|
||||
if (tty) {
|
||||
spin_lock_irqsave(&acm->throttle_lock, flags);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock_irqrestore(&acm->throttle_lock, flags);
|
||||
if (!throttled) {
|
||||
tty_insert_flip_string(tty, buf->base, buf->size);
|
||||
tty_flip_buffer_push(tty);
|
||||
} else {
|
||||
tty_kref_put(tty);
|
||||
dbg("Throttling noticed");
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
goto next_buffer;
|
||||
|
||||
urbs:
|
||||
tty_kref_put(tty);
|
||||
|
||||
while (!list_empty(&acm->spare_read_bufs)) {
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (list_empty(&acm->spare_read_urbs)) {
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
rcv = list_entry(acm->spare_read_urbs.next,
|
||||
struct acm_ru, list);
|
||||
list_del(&rcv->list);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
|
||||
buf = list_entry(acm->spare_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
|
||||
rcv->buffer = buf;
|
||||
|
||||
if (acm->is_int_ep)
|
||||
usb_fill_int_urb(rcv->urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
buf->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk, rcv, acm->bInterval);
|
||||
else
|
||||
usb_fill_bulk_urb(rcv->urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
buf->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk, rcv);
|
||||
rcv->urb->transfer_dma = buf->dma;
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
/* This shouldn't kill the driver as unsuccessful URBs are
|
||||
returned to the free-urbs-pool and resubmited ASAP */
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
if (acm->susp_count ||
|
||||
usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
list_add(&rcv->list, &acm->spare_read_urbs);
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
} else {
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
acm->processing = 0;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
}
|
||||
|
||||
/* data interface wrote those outgoing bytes */
|
||||
|
|
@ -509,9 +419,9 @@ static void acm_write_bulk(struct urb *urb)
|
|||
struct acm *acm = wb->instance;
|
||||
unsigned long flags;
|
||||
|
||||
if (verbose || urb->status
|
||||
|| (urb->actual_length != urb->transfer_buffer_length))
|
||||
dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
|
||||
if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
|
||||
dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
|
||||
__func__,
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb->status);
|
||||
|
|
@ -521,8 +431,6 @@ static void acm_write_bulk(struct urb *urb)
|
|||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
if (ACM_READY(acm))
|
||||
schedule_work(&acm->work);
|
||||
else
|
||||
wake_up_interruptible(&acm->drain_wait);
|
||||
}
|
||||
|
||||
static void acm_softint(struct work_struct *work)
|
||||
|
|
@ -530,7 +438,8 @@ static void acm_softint(struct work_struct *work)
|
|||
struct acm *acm = container_of(work, struct acm, work);
|
||||
struct tty_struct *tty;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "tx work\n");
|
||||
dev_vdbg(&acm->data->dev, "%s\n", __func__);
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
|
|
@ -548,8 +457,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct acm *acm;
|
||||
int rv = -ENODEV;
|
||||
int i;
|
||||
dbg("Entering acm_tty_open.");
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
|
||||
|
|
@ -559,6 +466,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
else
|
||||
rv = 0;
|
||||
|
||||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||||
|
||||
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
||||
|
||||
tty->driver_data = acm;
|
||||
|
|
@ -578,38 +487,28 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
acm->ctrlurb->dev = acm->dev;
|
||||
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
|
||||
dbg("usb_submit_urb(ctrl irq) failed");
|
||||
dev_err(&acm->control->dev,
|
||||
"%s - usb_submit_urb(ctrl irq) failed\n", __func__);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
|
||||
(acm->ctrl_caps & USB_CDC_CAP_LINE))
|
||||
goto full_bailout;
|
||||
goto bail_out;
|
||||
|
||||
usb_autopm_put_interface(acm->control);
|
||||
|
||||
INIT_LIST_HEAD(&acm->spare_read_urbs);
|
||||
INIT_LIST_HEAD(&acm->spare_read_bufs);
|
||||
INIT_LIST_HEAD(&acm->filled_read_bufs);
|
||||
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
|
||||
|
||||
acm->throttle = 0;
|
||||
if (acm_submit_read_urbs(acm, GFP_KERNEL))
|
||||
goto bail_out;
|
||||
|
||||
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
||||
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
mutex_unlock(&acm->mutex);
|
||||
out:
|
||||
mutex_unlock(&open_mutex);
|
||||
return rv;
|
||||
|
||||
full_bailout:
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
bail_out:
|
||||
acm->port.count--;
|
||||
mutex_unlock(&acm->mutex);
|
||||
|
|
@ -622,26 +521,24 @@ early_bail:
|
|||
|
||||
static void acm_tty_unregister(struct acm *acm)
|
||||
{
|
||||
int i, nr;
|
||||
int i;
|
||||
|
||||
nr = acm->rx_buflimit;
|
||||
tty_unregister_device(acm_tty_driver, acm->minor);
|
||||
usb_put_intf(acm->control);
|
||||
acm_table[acm->minor] = NULL;
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_free_urb(acm->read_urbs[i]);
|
||||
kfree(acm->country_codes);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
static int acm_tty_chars_in_buffer(struct tty_struct *tty);
|
||||
|
||||
static void acm_port_down(struct acm *acm)
|
||||
{
|
||||
int i, nr = acm->rx_buflimit;
|
||||
int i;
|
||||
|
||||
mutex_lock(&open_mutex);
|
||||
if (acm->dev) {
|
||||
usb_autopm_get_interface(acm->control);
|
||||
|
|
@ -649,10 +546,8 @@ static void acm_port_down(struct acm *acm)
|
|||
usb_kill_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
tasklet_disable(&acm->urb_task);
|
||||
for (i = 0; i < nr; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
tasklet_enable(&acm->urb_task);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_kill_urb(acm->read_urbs[i]);
|
||||
acm->control->needs_remote_wakeup = 0;
|
||||
usb_autopm_put_interface(acm->control);
|
||||
}
|
||||
|
|
@ -698,13 +593,13 @@ static int acm_tty_write(struct tty_struct *tty,
|
|||
int wbn;
|
||||
struct acm_wb *wb;
|
||||
|
||||
dbg("Entering acm_tty_write to write %d bytes,", count);
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return -EINVAL;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
wbn = acm_wb_alloc(acm);
|
||||
if (wbn < 0) {
|
||||
|
|
@ -714,7 +609,7 @@ static int acm_tty_write(struct tty_struct *tty,
|
|||
wb = &acm->wb[wbn];
|
||||
|
||||
count = (count > acm->writesize) ? acm->writesize : count;
|
||||
dbg("Get %d bytes...", count);
|
||||
dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
|
||||
memcpy(wb->buf, buf, count);
|
||||
wb->len = count;
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
|
|
@ -751,22 +646,31 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
|
|||
static void acm_tty_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
spin_lock_bh(&acm->throttle_lock);
|
||||
acm->throttle = 1;
|
||||
spin_unlock_bh(&acm->throttle_lock);
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
acm->throttle_req = 1;
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
}
|
||||
|
||||
static void acm_tty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
unsigned int was_throttled;
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
spin_lock_bh(&acm->throttle_lock);
|
||||
acm->throttle = 0;
|
||||
spin_unlock_bh(&acm->throttle_lock);
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
was_throttled = acm->throttled;
|
||||
acm->throttled = 0;
|
||||
acm->throttle_req = 0;
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
|
||||
if (was_throttled)
|
||||
acm_submit_read_urbs(acm, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int acm_tty_break_ctl(struct tty_struct *tty, int state)
|
||||
|
|
@ -777,7 +681,8 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
|
|||
return -EINVAL;
|
||||
retval = acm_send_break(acm, state ? 0xffff : 0);
|
||||
if (retval < 0)
|
||||
dbg("send break failed");
|
||||
dev_dbg(&acm->control->dev, "%s - send break failed\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -872,7 +777,9 @@ static void acm_tty_set_termios(struct tty_struct *tty,
|
|||
|
||||
if (memcmp(&acm->line, &newline, sizeof newline)) {
|
||||
memcpy(&acm->line, &newline, sizeof newline);
|
||||
dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
|
||||
dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
|
||||
__func__,
|
||||
le32_to_cpu(newline.dwDTERate),
|
||||
newline.bCharFormat, newline.bParityType,
|
||||
newline.bDataBits);
|
||||
acm_set_line(acm, &acm->line);
|
||||
|
|
@ -897,11 +804,11 @@ static void acm_write_buffers_free(struct acm *acm)
|
|||
static void acm_read_buffers_free(struct acm *acm)
|
||||
{
|
||||
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
|
||||
int i, n = acm->rx_buflimit;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_free_coherent(usb_dev, acm->readsize,
|
||||
acm->rb[i].base, acm->rb[i].dma);
|
||||
acm->read_buffers[i].base, acm->read_buffers[i].dma);
|
||||
}
|
||||
|
||||
/* Little helper: write buffers allocate */
|
||||
|
|
@ -946,7 +853,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
u8 ac_management_function = 0;
|
||||
u8 call_management_function = 0;
|
||||
int call_interface_num = -1;
|
||||
int data_interface_num;
|
||||
int data_interface_num = -1;
|
||||
unsigned long quirks;
|
||||
int num_rx_buf;
|
||||
int i;
|
||||
|
|
@ -1030,7 +937,11 @@ next_desc:
|
|||
if (!union_header) {
|
||||
if (call_interface_num > 0) {
|
||||
dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
|
||||
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
|
||||
/* quirks for Droids MuIn LCD */
|
||||
if (quirks & NO_DATA_INTERFACE)
|
||||
data_interface = usb_ifnum_to_if(usb_dev, 0);
|
||||
else
|
||||
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
|
||||
control_interface = intf;
|
||||
} else {
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
|
||||
|
|
@ -1133,7 +1044,7 @@ skip_normal_probe:
|
|||
epwrite = t;
|
||||
}
|
||||
made_compressed_probe:
|
||||
dbg("interfaces are valid");
|
||||
dev_dbg(&intf->dev, "interfaces are valid\n");
|
||||
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
|
||||
|
||||
if (minor == ACM_TTY_MINORS) {
|
||||
|
|
@ -1143,7 +1054,7 @@ made_compressed_probe:
|
|||
|
||||
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
|
||||
if (acm == NULL) {
|
||||
dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
|
|
@ -1162,11 +1073,7 @@ made_compressed_probe:
|
|||
acm->ctrlsize = ctrlsize;
|
||||
acm->readsize = readsize;
|
||||
acm->rx_buflimit = num_rx_buf;
|
||||
acm->urb_task.func = acm_rx_tasklet;
|
||||
acm->urb_task.data = (unsigned long) acm;
|
||||
INIT_WORK(&acm->work, acm_softint);
|
||||
init_waitqueue_head(&acm->drain_wait);
|
||||
spin_lock_init(&acm->throttle_lock);
|
||||
spin_lock_init(&acm->write_lock);
|
||||
spin_lock_init(&acm->read_lock);
|
||||
mutex_init(&acm->mutex);
|
||||
|
|
@ -1179,53 +1086,69 @@ made_compressed_probe:
|
|||
|
||||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
if (!buf) {
|
||||
dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
goto alloc_fail2;
|
||||
}
|
||||
acm->ctrl_buffer = buf;
|
||||
|
||||
if (acm_write_buffers_alloc(acm) < 0) {
|
||||
dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
goto alloc_fail4;
|
||||
}
|
||||
|
||||
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->ctrlurb) {
|
||||
dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
goto alloc_fail5;
|
||||
}
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_ru *rcv = &(acm->ru[i]);
|
||||
struct acm_rb *rb = &(acm->read_buffers[i]);
|
||||
struct urb *urb;
|
||||
|
||||
rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (rcv->urb == NULL) {
|
||||
dev_dbg(&intf->dev,
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
|
||||
&rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_err(&intf->dev, "out of memory "
|
||||
"(read bufs usb_alloc_coherent)\n");
|
||||
goto alloc_fail6;
|
||||
}
|
||||
rb->index = i;
|
||||
rb->instance = acm;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (read urbs usb_alloc_urb)\n");
|
||||
goto alloc_fail6;
|
||||
}
|
||||
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
rcv->instance = acm;
|
||||
}
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_rb *rb = &(acm->rb[i]);
|
||||
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize,
|
||||
GFP_KERNEL, &rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_dbg(&intf->dev,
|
||||
"out of memory (read bufs usb_alloc_coherent)\n");
|
||||
goto alloc_fail7;
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->transfer_dma = rb->dma;
|
||||
if (acm->is_int_ep) {
|
||||
usb_fill_int_urb(urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
rb->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk_callback, rb,
|
||||
acm->bInterval);
|
||||
} else {
|
||||
usb_fill_bulk_urb(urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
rb->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk_callback, rb);
|
||||
}
|
||||
|
||||
acm->read_urbs[i] = urb;
|
||||
__set_bit(i, &acm->read_urbs_free);
|
||||
}
|
||||
for (i = 0; i < ACM_NW; i++) {
|
||||
struct acm_wb *snd = &(acm->wb[i]);
|
||||
|
||||
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (snd->urb == NULL) {
|
||||
dev_dbg(&intf->dev,
|
||||
"out of memory (write urbs usb_alloc_urb)");
|
||||
goto alloc_fail8;
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (write urbs usb_alloc_urb)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_int(epwrite))
|
||||
|
|
@ -1244,7 +1167,7 @@ made_compressed_probe:
|
|||
|
||||
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
|
||||
if (i < 0)
|
||||
goto alloc_fail8;
|
||||
goto alloc_fail7;
|
||||
|
||||
if (cfd) { /* export the country data */
|
||||
acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
|
||||
|
|
@ -1296,14 +1219,13 @@ skip_countries:
|
|||
acm_table[minor] = acm;
|
||||
|
||||
return 0;
|
||||
alloc_fail8:
|
||||
alloc_fail7:
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_free_urb(acm->wb[i].urb);
|
||||
alloc_fail7:
|
||||
acm_read_buffers_free(acm);
|
||||
alloc_fail6:
|
||||
for (i = 0; i < num_rx_buf; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
usb_free_urb(acm->read_urbs[i]);
|
||||
acm_read_buffers_free(acm);
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
alloc_fail5:
|
||||
acm_write_buffers_free(acm);
|
||||
|
|
@ -1318,17 +1240,14 @@ alloc_fail:
|
|||
static void stop_data_traffic(struct acm *acm)
|
||||
{
|
||||
int i;
|
||||
dbg("Entering stop_data_traffic");
|
||||
|
||||
tasklet_disable(&acm->urb_task);
|
||||
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
||||
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
usb_kill_urb(acm->wb[i].urb);
|
||||
for (i = 0; i < acm->rx_buflimit; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
|
||||
tasklet_enable(&acm->urb_task);
|
||||
usb_kill_urb(acm->read_urbs[i]);
|
||||
|
||||
cancel_work_sync(&acm->work);
|
||||
}
|
||||
|
|
@ -1389,11 +1308,9 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
if (message.event & PM_EVENT_AUTO) {
|
||||
int b;
|
||||
|
||||
spin_lock_irq(&acm->read_lock);
|
||||
spin_lock(&acm->write_lock);
|
||||
b = acm->processing + acm->transmitting;
|
||||
spin_unlock(&acm->write_lock);
|
||||
spin_unlock_irq(&acm->read_lock);
|
||||
spin_lock_irq(&acm->write_lock);
|
||||
b = acm->transmitting;
|
||||
spin_unlock_irq(&acm->write_lock);
|
||||
if (b)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
|
@ -1455,7 +1372,7 @@ static int acm_resume(struct usb_interface *intf)
|
|||
if (rv < 0)
|
||||
goto err_out;
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
rv = acm_submit_read_urbs(acm, GFP_NOIO);
|
||||
}
|
||||
|
||||
err_out:
|
||||
|
|
@ -1622,6 +1539,11 @@ static const struct usb_device_id acm_ids[] = {
|
|||
.driver_info = NOT_A_MODEM,
|
||||
},
|
||||
|
||||
/* Support for Droids MuIn LCD */
|
||||
{ USB_DEVICE(0x04d8, 0x000b),
|
||||
.driver_info = NO_DATA_INTERFACE,
|
||||
},
|
||||
|
||||
/* control interfaces without any protocol set */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
|
||||
USB_CDC_PROTO_NONE) },
|
||||
|
|
@ -1716,8 +1638,7 @@ static int __init acm_init(void)
|
|||
return retval;
|
||||
}
|
||||
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
|
||||
DRIVER_DESC "\n");
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,16 +72,10 @@ struct acm_wb {
|
|||
};
|
||||
|
||||
struct acm_rb {
|
||||
struct list_head list;
|
||||
int size;
|
||||
unsigned char *base;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
struct acm_ru {
|
||||
struct list_head list;
|
||||
struct acm_rb *buffer;
|
||||
struct urb *urb;
|
||||
int index;
|
||||
struct acm *instance;
|
||||
};
|
||||
|
||||
|
|
@ -97,35 +91,30 @@ struct acm {
|
|||
unsigned int country_code_size; /* size of this buffer */
|
||||
unsigned int country_rel_date; /* release date of version */
|
||||
struct acm_wb wb[ACM_NW];
|
||||
struct acm_ru ru[ACM_NR];
|
||||
struct acm_rb rb[ACM_NR];
|
||||
unsigned long read_urbs_free;
|
||||
struct urb *read_urbs[ACM_NR];
|
||||
struct acm_rb read_buffers[ACM_NR];
|
||||
int rx_buflimit;
|
||||
int rx_endpoint;
|
||||
spinlock_t read_lock;
|
||||
struct list_head spare_read_urbs;
|
||||
struct list_head spare_read_bufs;
|
||||
struct list_head filled_read_bufs;
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
int processing;
|
||||
int transmitting;
|
||||
spinlock_t write_lock;
|
||||
struct mutex mutex;
|
||||
struct usb_cdc_line_coding line; /* bits, stop, parity */
|
||||
struct work_struct work; /* work queue entry for line discipline waking up */
|
||||
wait_queue_head_t drain_wait; /* close processing */
|
||||
struct tasklet_struct urb_task; /* rx processing */
|
||||
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
|
||||
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
|
||||
unsigned int ctrlout; /* output control lines (DTR, RTS) */
|
||||
unsigned int writesize; /* max packet size for the output bulk endpoint */
|
||||
unsigned int readsize,ctrlsize; /* buffer sizes for freeing */
|
||||
unsigned int minor; /* acm minor number */
|
||||
unsigned char throttle; /* throttled by tty layer */
|
||||
unsigned char clocal; /* termios CLOCAL */
|
||||
unsigned int ctrl_caps; /* control capabilities from the class specific header */
|
||||
unsigned int susp_count; /* number of suspended interfaces */
|
||||
unsigned int combined_interfaces:1; /* control and data collapsed */
|
||||
unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */
|
||||
unsigned int throttled:1; /* actually throttled */
|
||||
unsigned int throttle_req:1; /* throttle requested */
|
||||
u8 bInterval;
|
||||
struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
|
||||
};
|
||||
|
|
@ -137,3 +126,4 @@ struct acm {
|
|||
#define SINGLE_RX_URB 2
|
||||
#define NO_CAP_LINE 4
|
||||
#define NOT_A_MODEM 8
|
||||
#define NO_DATA_INTERFACE 16
|
||||
|
|
|
|||
|
|
@ -542,6 +542,8 @@ static int wdm_open(struct inode *inode, struct file *file)
|
|||
|
||||
mutex_lock(&desc->lock);
|
||||
if (!desc->count++) {
|
||||
desc->werr = 0;
|
||||
desc->rerr = 0;
|
||||
rv = usb_submit_urb(desc->validity, GFP_KERNEL);
|
||||
if (rv < 0) {
|
||||
desc->count--;
|
||||
|
|
@ -853,6 +855,18 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|||
struct wdm_device *desc = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&desc->lock);
|
||||
kill_urbs(desc);
|
||||
|
||||
/*
|
||||
* we notify everybody using poll of
|
||||
* an exceptional situation
|
||||
* must be done before recovery lest a spontaneous
|
||||
* message from the device is lost
|
||||
*/
|
||||
spin_lock_irq(&desc->iuspin);
|
||||
desc->rerr = -EINTR;
|
||||
spin_unlock_irq(&desc->iuspin);
|
||||
wake_up_all(&desc->wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
|
||||
else
|
||||
max_tx = 999999;
|
||||
if (desc->wBytesPerInterval > max_tx) {
|
||||
if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
|
||||
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to %d\n",
|
||||
|
|
|
|||
|
|
@ -64,49 +64,49 @@
|
|||
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
|
||||
#define ALLOW_SERIAL_NUMBER
|
||||
|
||||
static const char *format_topo =
|
||||
static const char format_topo[] =
|
||||
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */
|
||||
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n";
|
||||
|
||||
static const char *format_string_manufacturer =
|
||||
static const char format_string_manufacturer[] =
|
||||
/* S: Manufacturer=xxxx */
|
||||
"S: Manufacturer=%.100s\n";
|
||||
|
||||
static const char *format_string_product =
|
||||
static const char format_string_product[] =
|
||||
/* S: Product=xxxx */
|
||||
"S: Product=%.100s\n";
|
||||
|
||||
#ifdef ALLOW_SERIAL_NUMBER
|
||||
static const char *format_string_serialnumber =
|
||||
static const char format_string_serialnumber[] =
|
||||
/* S: SerialNumber=xxxx */
|
||||
"S: SerialNumber=%.100s\n";
|
||||
#endif
|
||||
|
||||
static const char *format_bandwidth =
|
||||
static const char format_bandwidth[] =
|
||||
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
|
||||
"B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
|
||||
|
||||
static const char *format_device1 =
|
||||
static const char format_device1[] =
|
||||
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
|
||||
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
|
||||
|
||||
static const char *format_device2 =
|
||||
static const char format_device2[] =
|
||||
/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
|
||||
"P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
|
||||
|
||||
static const char *format_config =
|
||||
static const char format_config[] =
|
||||
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
|
||||
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
|
||||
|
||||
static const char *format_iad =
|
||||
static const char format_iad[] =
|
||||
/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
|
||||
"A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
|
||||
|
||||
static const char *format_iface =
|
||||
static const char format_iface[] =
|
||||
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
|
||||
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
|
||||
|
||||
static const char *format_endpt =
|
||||
static const char format_endpt[] =
|
||||
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
|
||||
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
|
||||
|
||||
|
|
|
|||
|
|
@ -236,13 +236,6 @@ EXPORT_SYMBOL_GPL(usb_register_dev);
|
|||
void usb_deregister_dev(struct usb_interface *intf,
|
||||
struct usb_class_driver *class_driver)
|
||||
{
|
||||
int minor_base = class_driver->minor_base;
|
||||
char name[20];
|
||||
|
||||
#ifdef CONFIG_USB_DYNAMIC_MINORS
|
||||
minor_base = 0;
|
||||
#endif
|
||||
|
||||
if (intf->minor == -1)
|
||||
return;
|
||||
|
||||
|
|
@ -252,7 +245,6 @@ void usb_deregister_dev(struct usb_interface *intf,
|
|||
usb_minors[intf->minor] = NULL;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
snprintf(name, sizeof(name), class_driver->name, intf->minor - minor_base);
|
||||
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
|
||||
intf->usb_dev = NULL;
|
||||
intf->minor = -1;
|
||||
|
|
|
|||
|
|
@ -986,7 +986,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
/* Did the HC die before the root hub was registered? */
|
||||
if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT)
|
||||
if (HCD_DEAD(hcd))
|
||||
usb_hc_died (hcd); /* This time clean up */
|
||||
}
|
||||
|
||||
|
|
@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
|
|||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
if (hcd->shared_hcd)
|
||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
|
||||
|
||||
if (unlikely(hcd->state == HC_STATE_HALT))
|
||||
usb_hc_died(hcd);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -2407,6 +2404,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
goto err_set_rh_speed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
|
|||
*status = le16_to_cpu(hub->status->port.wPortStatus);
|
||||
*change = le16_to_cpu(hub->status->port.wPortChange);
|
||||
|
||||
if ((hub->hdev->parent != NULL) &&
|
||||
hub_is_superspeed(hub->hdev)) {
|
||||
/* Translate the USB 3 port status */
|
||||
u16 tmp = *status & USB_SS_PORT_STAT_MASK;
|
||||
if (*status & USB_SS_PORT_STAT_POWER)
|
||||
tmp |= USB_PORT_STAT_POWER;
|
||||
*status = tmp;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&hub->status_mutex);
|
||||
|
|
@ -2160,11 +2151,76 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Warm reset a USB3 protocol port */
|
||||
static int hub_port_warm_reset(struct usb_hub *hub, int port)
|
||||
{
|
||||
int ret;
|
||||
u16 portstatus, portchange;
|
||||
|
||||
if (!hub_is_superspeed(hub->hdev)) {
|
||||
dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Warm reset the port */
|
||||
ret = set_port_feature(hub->hdev,
|
||||
port, USB_PORT_FEAT_BH_PORT_RESET);
|
||||
if (ret) {
|
||||
dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(20);
|
||||
ret = hub_port_status(hub, port, &portstatus, &portchange);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_RESET)
|
||||
clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_BH_RESET)
|
||||
clear_port_feature(hub->hdev, port,
|
||||
USB_PORT_FEAT_C_BH_PORT_RESET);
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_LINK_STATE)
|
||||
clear_port_feature(hub->hdev, port,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if a port is power on */
|
||||
static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if (portstatus & USB_SS_PORT_STAT_POWER)
|
||||
ret = 1;
|
||||
} else {
|
||||
if (portstatus & USB_PORT_STAT_POWER)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \
|
||||
USB_PORT_STAT_SUSPEND)
|
||||
#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION)
|
||||
/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
|
||||
static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if ((portstatus & USB_PORT_STAT_LINK_STATE)
|
||||
== USB_SS_PORT_LS_U3)
|
||||
ret = 1;
|
||||
} else {
|
||||
if (portstatus & USB_PORT_STAT_SUSPEND)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Determine whether the device on a port is ready for a normal resume,
|
||||
* is ready for a reset-resume, or should be disconnected.
|
||||
|
|
@ -2174,7 +2230,9 @@ static int check_port_resume_type(struct usb_device *udev,
|
|||
int status, unsigned portchange, unsigned portstatus)
|
||||
{
|
||||
/* Is the device still present? */
|
||||
if (status || (portstatus & MASK_BITS) != WANT_BITS) {
|
||||
if (status || port_is_suspended(hub, portstatus) ||
|
||||
!port_is_power_on(hub, portstatus) ||
|
||||
!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
if (status >= 0)
|
||||
status = -ENODEV;
|
||||
}
|
||||
|
|
@ -2285,14 +2343,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
}
|
||||
|
||||
/* see 7.1.7.6 */
|
||||
/* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0
|
||||
* external hub.
|
||||
* FIXME: this is a temporary workaround to make the system able
|
||||
* to suspend/resume.
|
||||
*/
|
||||
if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev))
|
||||
status = clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_POWER);
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
status = set_port_feature(hub->hdev,
|
||||
port1 | (USB_SS_PORT_LS_U3 << 3),
|
||||
USB_PORT_FEAT_LINK_STATE);
|
||||
else
|
||||
status = set_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
|
|
@ -2439,7 +2493,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
/* Skip the initial Clear-Suspend step for a remote wakeup */
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
|
||||
if (status == 0 && !port_is_suspended(hub, portstatus))
|
||||
goto SuspendCleared;
|
||||
|
||||
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
|
||||
|
|
@ -2447,8 +2501,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
set_bit(port1, hub->busy_bits);
|
||||
|
||||
/* see 7.1.7.7; affects power usage, but not budgeting */
|
||||
status = clear_port_feature(hub->hdev,
|
||||
port1, USB_PORT_FEAT_SUSPEND);
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
status = set_port_feature(hub->hdev,
|
||||
port1 | (USB_SS_PORT_LS_U0 << 3),
|
||||
USB_PORT_FEAT_LINK_STATE);
|
||||
else
|
||||
status = clear_port_feature(hub->hdev,
|
||||
port1, USB_PORT_FEAT_SUSPEND);
|
||||
if (status) {
|
||||
dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
|
||||
port1, status);
|
||||
|
|
@ -2470,9 +2529,15 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
SuspendCleared:
|
||||
if (status == 0) {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
if (portchange & USB_PORT_STAT_C_LINK_STATE)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
} else {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(port1, hub->busy_bits);
|
||||
|
|
@ -3147,7 +3212,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
|
||||
/* maybe switch power back on (e.g. root hub was reset) */
|
||||
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
|
||||
&& !(portstatus & USB_PORT_STAT_POWER))
|
||||
&& !port_is_power_on(hub, portstatus))
|
||||
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
|
||||
|
||||
if (portstatus & USB_PORT_STAT_ENABLE)
|
||||
|
|
@ -3490,6 +3555,16 @@ static void hub_events(void)
|
|||
USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
|
||||
}
|
||||
|
||||
/* Warm reset a USB3 protocol port if it's in
|
||||
* SS.Inactive state.
|
||||
*/
|
||||
if (hub_is_superspeed(hub->hdev) &&
|
||||
(portstatus & USB_PORT_STAT_LINK_STATE)
|
||||
== USB_SS_PORT_LS_SS_INACTIVE) {
|
||||
dev_dbg(hub_dev, "warm reset port %d\n", i);
|
||||
hub_port_warm_reset(hub, i);
|
||||
}
|
||||
|
||||
if (connect_change)
|
||||
hub_port_connect_change(hub, i,
|
||||
portstatus, portchange);
|
||||
|
|
|
|||
|
|
@ -842,22 +842,19 @@ const struct attribute_group *usb_interface_groups[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
int usb_create_sysfs_intf_files(struct usb_interface *intf)
|
||||
void usb_create_sysfs_intf_files(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
int retval;
|
||||
|
||||
if (intf->sysfs_files_created || intf->unregistering)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (alt->string == NULL &&
|
||||
!(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
alt->string = usb_cache_string(udev, alt->desc.iInterface);
|
||||
if (alt->string)
|
||||
retval = device_create_file(&intf->dev, &dev_attr_interface);
|
||||
if (alt->string && device_create_file(&intf->dev, &dev_attr_interface))
|
||||
; /* We don't actually care if the function fails. */
|
||||
intf->sysfs_files_created = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
|
||||
|
|
|
|||
|
|
@ -953,8 +953,7 @@ static int usb_bus_notify(struct notifier_block *nb, unsigned long action,
|
|||
if (dev->type == &usb_device_type)
|
||||
(void) usb_create_sysfs_dev_files(to_usb_device(dev));
|
||||
else if (dev->type == &usb_if_device_type)
|
||||
(void) usb_create_sysfs_intf_files(
|
||||
to_usb_interface(dev));
|
||||
usb_create_sysfs_intf_files(to_usb_interface(dev));
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_DEL_DEVICE:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
extern int usb_create_sysfs_dev_files(struct usb_device *dev);
|
||||
extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
|
||||
extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern void usb_create_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
|
||||
extern int usb_create_ep_devs(struct device *parent,
|
||||
struct usb_host_endpoint *endpoint,
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ static struct kgdb_io kgdbdbgp_io_ops;
|
|||
#define dbgp_kgdb_mode (0)
|
||||
#endif
|
||||
|
||||
/* Local version of HC_LENGTH macro as ehci struct is not available here */
|
||||
#define EARLY_HC_LENGTH(p) (0x00ff & (p)) /* bits 7 : 0 */
|
||||
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
|
|
@ -892,7 +895,7 @@ int __init early_dbgp_init(char *s)
|
|||
dbgp_printk("ehci_bar: %p\n", ehci_bar);
|
||||
|
||||
ehci_caps = ehci_bar;
|
||||
ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
|
||||
ehci_regs = ehci_bar + EARLY_HC_LENGTH(readl(&ehci_caps->hc_capbase));
|
||||
ehci_debug = ehci_bar + offset;
|
||||
ehci_dev.bus = bus;
|
||||
ehci_dev.slot = slot;
|
||||
|
|
|
|||
|
|
@ -260,6 +260,24 @@ config USB_R8A66597
|
|||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_RENESAS_USBHS
|
||||
boolean "Renesas USBHS"
|
||||
depends on USB_RENESAS_USBHS
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Renesas USBHS is a discrete USB host and peripheral controller
|
||||
chip that supports both full and high speed USB 2.0 data transfers.
|
||||
platform is able to configure endpoint (pipe) style
|
||||
|
||||
Say "y" to enable the gadget specific portion of the USBHS driver.
|
||||
|
||||
|
||||
config USB_RENESAS_USBHS_UDC
|
||||
tristate
|
||||
depends on USB_GADGET_RENESAS_USBHS
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA27X
|
||||
boolean "PXA 27x"
|
||||
depends on ARCH_PXA && (PXA27x || PXA3xx)
|
||||
|
|
@ -338,6 +356,23 @@ config USB_S3C2410_DEBUG
|
|||
boolean "S3C2410 udc debug messages"
|
||||
depends on USB_GADGET_S3C2410
|
||||
|
||||
config USB_GADGET_S3C_HSUDC
|
||||
boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
|
||||
depends on ARCH_S3C2410
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
|
||||
integrated with dual speed USB 2.0 device controller. It has
|
||||
8 endpoints, as well as endpoint zero.
|
||||
|
||||
This driver has been tested on S3C2416 and S3C2450 processors.
|
||||
|
||||
config USB_S3C_HSUDC
|
||||
tristate
|
||||
depends on USB_GADGET_S3C_HSUDC
|
||||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_GADGET_PXA_U2O
|
||||
boolean "PXA9xx Processor USB2.0 controller"
|
||||
select USB_GADGET_DUALSPEED
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
|||
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
|
||||
obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
|
||||
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
|
||||
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
|
||||
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
|
||||
obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
|
||||
|
|
|
|||
|
|
@ -1767,7 +1767,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* newer chips have more FIFO memory than rm9200 */
|
||||
if (cpu_is_at91sam9260()) {
|
||||
if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
udc->ep[4].maxpacket = 512;
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ static int hw_device_reset(struct ci13xxx *udc)
|
|||
udc->udc_driver->notify_event(udc,
|
||||
CI13XXX_CONTROLLER_RESET_EVENT);
|
||||
|
||||
if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING)
|
||||
if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
|
||||
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
|
||||
|
||||
/* USBMODE should be configured step by step */
|
||||
|
|
@ -1634,8 +1634,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
|
|||
gadget_for_each_ep(ep, gadget) {
|
||||
usb_ep_disable(ep);
|
||||
}
|
||||
usb_ep_disable(&udc->ep0out.ep);
|
||||
usb_ep_disable(&udc->ep0in.ep);
|
||||
|
||||
if (udc->status != NULL) {
|
||||
usb_ep_free_request(&udc->ep0in.ep, udc->status);
|
||||
|
|
@ -1678,18 +1676,10 @@ __acquires(udc->lock)
|
|||
if (retval)
|
||||
goto done;
|
||||
|
||||
retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
|
||||
if (retval)
|
||||
goto done;
|
||||
udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
|
||||
if (udc->status == NULL)
|
||||
retval = -ENOMEM;
|
||||
|
||||
retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
|
||||
if (!retval) {
|
||||
udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
|
||||
if (udc->status == NULL) {
|
||||
usb_ep_disable(&udc->ep0out.ep);
|
||||
retval = -ENOMEM;
|
||||
}
|
||||
}
|
||||
spin_lock(udc->lock);
|
||||
|
||||
done:
|
||||
|
|
@ -1843,7 +1833,8 @@ __releases(mEp->lock)
|
|||
__acquires(mEp->lock)
|
||||
{
|
||||
struct ci13xxx_req *mReq, *mReqTemp;
|
||||
int retval;
|
||||
struct ci13xxx_ep *mEpTemp = mEp;
|
||||
int uninitialized_var(retval);
|
||||
|
||||
trace("%p", mEp);
|
||||
|
||||
|
|
@ -1859,12 +1850,15 @@ __acquires(mEp->lock)
|
|||
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
|
||||
if (mReq->req.complete != NULL) {
|
||||
spin_unlock(mEp->lock);
|
||||
mReq->req.complete(&mEp->ep, &mReq->req);
|
||||
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
|
||||
mReq->req.length)
|
||||
mEpTemp = &_udc->ep0in;
|
||||
mReq->req.complete(&mEpTemp->ep, &mReq->req);
|
||||
spin_lock(mEp->lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == EBUSY)
|
||||
if (retval == -EBUSY)
|
||||
retval = 0;
|
||||
if (retval < 0)
|
||||
dbg_event(_usb_addr(mEp), "DONE", retval);
|
||||
|
|
@ -1894,7 +1888,7 @@ __acquires(udc->lock)
|
|||
|
||||
for (i = 0; i < hw_ep_max; i++) {
|
||||
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
|
||||
int type, num, err = -EINVAL;
|
||||
int type, num, dir, err = -EINVAL;
|
||||
struct usb_ctrlrequest req;
|
||||
|
||||
if (mEp->desc == NULL)
|
||||
|
|
@ -1952,7 +1946,10 @@ __acquires(udc->lock)
|
|||
if (req.wLength != 0)
|
||||
break;
|
||||
num = le16_to_cpu(req.wIndex);
|
||||
dir = num & USB_ENDPOINT_DIR_MASK;
|
||||
num &= USB_ENDPOINT_NUMBER_MASK;
|
||||
if (dir) /* TX */
|
||||
num += hw_ep_max/2;
|
||||
if (!udc->ci13xxx_ep[num].wedge) {
|
||||
spin_unlock(udc->lock);
|
||||
err = usb_ep_clear_halt(
|
||||
|
|
@ -2001,7 +1998,10 @@ __acquires(udc->lock)
|
|||
if (req.wLength != 0)
|
||||
break;
|
||||
num = le16_to_cpu(req.wIndex);
|
||||
dir = num & USB_ENDPOINT_DIR_MASK;
|
||||
num &= USB_ENDPOINT_NUMBER_MASK;
|
||||
if (dir) /* TX */
|
||||
num += hw_ep_max/2;
|
||||
|
||||
spin_unlock(udc->lock);
|
||||
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
|
||||
|
|
@ -2110,7 +2110,12 @@ static int ep_enable(struct usb_ep *ep,
|
|||
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
|
||||
mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
|
||||
|
||||
retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
|
||||
/*
|
||||
* Enable endpoints in the HW other than ep0 as ep0
|
||||
* is always enabled
|
||||
*/
|
||||
if (mEp->num)
|
||||
retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
|
||||
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
return retval;
|
||||
|
|
@ -2242,11 +2247,15 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
|
||||
!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
warn("endpoint ctrl %X nuked", _usb_addr(mEp));
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
|
||||
if (req->length)
|
||||
mEp = (_udc->ep0_dir == RX) ?
|
||||
&_udc->ep0out : &_udc->ep0in;
|
||||
if (!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
warn("endpoint ctrl %X nuked", _usb_addr(mEp));
|
||||
}
|
||||
}
|
||||
|
||||
/* first nuke then test link, e.g. previous status has not sent */
|
||||
|
|
@ -2497,6 +2506,15 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
|
||||
|
||||
if (udc->transceiver)
|
||||
return otg_set_power(udc->transceiver, mA);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device operations part of the API to the USB controller hardware,
|
||||
* which don't involve endpoints (or i/o)
|
||||
|
|
@ -2505,6 +2523,7 @@ out:
|
|||
static const struct usb_gadget_ops usb_gadget_ops = {
|
||||
.vbus_session = ci13xxx_vbus_session,
|
||||
.wakeup = ci13xxx_wakeup,
|
||||
.vbus_draw = ci13xxx_vbus_draw,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2595,6 +2614,14 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
}
|
||||
if (retval)
|
||||
goto done;
|
||||
spin_unlock_irqrestore(udc->lock, flags);
|
||||
retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
|
||||
if (retval)
|
||||
return retval;
|
||||
spin_lock_irqsave(udc->lock, flags);
|
||||
|
||||
udc->gadget.ep0 = &udc->ep0in.ep;
|
||||
/* bind gadget */
|
||||
|
|
|
|||
|
|
@ -461,12 +461,23 @@ static int set_config(struct usb_composite_dev *cdev,
|
|||
reset_config(cdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (result == USB_GADGET_DELAYED_STATUS) {
|
||||
DBG(cdev,
|
||||
"%s: interface %d (%s) requested delayed status\n",
|
||||
__func__, tmp, f->name);
|
||||
cdev->delayed_status++;
|
||||
DBG(cdev, "delayed_status count %d\n",
|
||||
cdev->delayed_status);
|
||||
}
|
||||
}
|
||||
|
||||
/* when we return, be sure our power usage is valid */
|
||||
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
done:
|
||||
usb_gadget_vbus_draw(gadget, power);
|
||||
if (result >= 0 && cdev->delayed_status)
|
||||
result = USB_GADGET_DELAYED_STATUS;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -895,6 +906,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
if (w_value && !f->set_alt)
|
||||
break;
|
||||
value = f->set_alt(f, w_index, w_value);
|
||||
if (value == USB_GADGET_DELAYED_STATUS) {
|
||||
DBG(cdev,
|
||||
"%s: interface %d (%s) requested delayed status\n",
|
||||
__func__, intf, f->name);
|
||||
cdev->delayed_status++;
|
||||
DBG(cdev, "delayed_status count %d\n",
|
||||
cdev->delayed_status);
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
|
||||
|
|
@ -958,7 +977,7 @@ unknown:
|
|||
}
|
||||
|
||||
/* respond with data transfer before status phase? */
|
||||
if (value >= 0) {
|
||||
if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
|
||||
req->length = value;
|
||||
req->zero = value < w_length;
|
||||
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
||||
|
|
@ -967,6 +986,10 @@ unknown:
|
|||
req->status = 0;
|
||||
composite_setup_complete(gadget->ep0, req);
|
||||
}
|
||||
} else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
|
||||
WARN(cdev,
|
||||
"%s: Delayed status not supported for w_length != 0",
|
||||
__func__);
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
@ -1289,3 +1312,40 @@ void usb_composite_unregister(struct usb_composite_driver *driver)
|
|||
return;
|
||||
usb_gadget_unregister_driver(&composite_driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_composite_setup_continue() - Continue with the control transfer
|
||||
* @cdev: the composite device who's control transfer was kept waiting
|
||||
*
|
||||
* This function must be called by the USB function driver to continue
|
||||
* with the control transfer's data/status stage in case it had requested to
|
||||
* delay the data/status stages. A USB function's setup handler (e.g. set_alt())
|
||||
* can request the composite framework to delay the setup request's data/status
|
||||
* stages by returning USB_GADGET_DELAYED_STATUS.
|
||||
*/
|
||||
void usb_composite_setup_continue(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int value;
|
||||
struct usb_request *req = cdev->req;
|
||||
unsigned long flags;
|
||||
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
|
||||
if (cdev->delayed_status == 0) {
|
||||
WARN(cdev, "%s: Unexpected call\n", __func__);
|
||||
|
||||
} else if (--cdev->delayed_status == 0) {
|
||||
DBG(cdev, "%s: Completing delayed status\n", __func__);
|
||||
req->length = 0;
|
||||
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0) {
|
||||
DBG(cdev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
composite_setup_complete(cdev->gadget->ep0, req);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -261,8 +261,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
|
|||
o_desc.wMaxPacketSize =
|
||||
__constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
|
||||
|
||||
dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress & 0x7f;
|
||||
dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress & 0x7f;
|
||||
dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
|
||||
dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial->in = dbgp.i_ep;
|
||||
|
|
@ -312,6 +312,7 @@ static int __init dbgp_bind(struct usb_gadget *gadget)
|
|||
|
||||
dbgp.req->length = DBGP_REQ_EP0_LEN;
|
||||
gadget->ep0->driver_data = gadget;
|
||||
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
|
||||
|
|
@ -350,9 +351,9 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
u8 request = ctrl->bRequest;
|
||||
u16 value = le16_to_cpu(ctrl->wValue);
|
||||
u16 length = le16_to_cpu(ctrl->wLength);
|
||||
int err = 0;
|
||||
void *data;
|
||||
u16 len;
|
||||
int err = -EOPNOTSUPP;
|
||||
void *data = NULL;
|
||||
u16 len = 0;
|
||||
|
||||
gadget->ep0->driver_data = gadget;
|
||||
|
||||
|
|
@ -371,10 +372,9 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
default:
|
||||
goto fail;
|
||||
}
|
||||
err = 0;
|
||||
} else if (request == USB_REQ_SET_FEATURE &&
|
||||
value == USB_DEVICE_DEBUG_MODE) {
|
||||
len = 0;
|
||||
data = NULL;
|
||||
dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
|
||||
#ifdef CONFIG_USB_G_DBGP_PRINTK
|
||||
err = dbgp_enable_ep();
|
||||
|
|
|
|||
|
|
@ -892,10 +892,11 @@ static int dummy_udc_probe (struct platform_device *pdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
platform_set_drvdata (pdev, dum);
|
||||
rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
|
||||
if (rc < 0)
|
||||
device_unregister (&dum->gadget.dev);
|
||||
else
|
||||
platform_set_drvdata(pdev, dum);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1995,11 +1996,29 @@ static int __init init (void)
|
|||
retval = platform_device_add(the_hcd_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_hcd;
|
||||
if (!the_controller) {
|
||||
/*
|
||||
* The hcd was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_add_udc;
|
||||
}
|
||||
retval = platform_device_add(the_udc_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_udc;
|
||||
if (!platform_get_drvdata(the_udc_pdev)) {
|
||||
/*
|
||||
* The udc was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_probe_udc;
|
||||
}
|
||||
return retval;
|
||||
|
||||
err_probe_udc:
|
||||
platform_device_del(the_udc_pdev);
|
||||
err_add_udc:
|
||||
platform_device_del(the_hcd_pdev);
|
||||
err_add_hcd:
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
|
|||
};
|
||||
|
||||
/* Standard ISO OUT Endpoint Descriptor */
|
||||
static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor as_out_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ struct fsg_operations {
|
|||
/* Data shared by all the FSG instances. */
|
||||
struct fsg_common {
|
||||
struct usb_gadget *gadget;
|
||||
struct usb_composite_dev *cdev;
|
||||
struct fsg_dev *fsg, *new_fsg;
|
||||
wait_queue_head_t fsg_wait;
|
||||
|
||||
|
|
@ -613,6 +614,11 @@ static int fsg_setup(struct usb_function *f,
|
|||
if (!fsg_is_set(fsg->common))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
++fsg->common->ep0_req_tag; /* Record arrival of a new request */
|
||||
req->context = NULL;
|
||||
req->length = 0;
|
||||
dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
|
||||
|
||||
switch (ctrl->bRequest) {
|
||||
|
||||
case USB_BULK_RESET_REQUEST:
|
||||
|
|
@ -1584,37 +1590,6 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int pad_with_zeros(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill;
|
||||
u32 nkeep = bh->inreq->length;
|
||||
u32 nsend;
|
||||
int rc;
|
||||
|
||||
bh->state = BUF_STATE_EMPTY; /* For the first iteration */
|
||||
fsg->common->usb_amount_left = nkeep + fsg->common->residue;
|
||||
while (fsg->common->usb_amount_left > 0) {
|
||||
|
||||
/* Wait for the next buffer to be free */
|
||||
while (bh->state != BUF_STATE_EMPTY) {
|
||||
rc = sleep_thread(fsg->common);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN);
|
||||
memset(bh->buf + nkeep, 0, nsend - nkeep);
|
||||
bh->inreq->length = nsend;
|
||||
bh->inreq->zero = 0;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
bh = fsg->common->next_buffhd_to_fill = bh->next;
|
||||
fsg->common->usb_amount_left -= nsend;
|
||||
nkeep = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int throw_away_data(struct fsg_common *common)
|
||||
{
|
||||
struct fsg_buffhd *bh;
|
||||
|
|
@ -1702,6 +1677,10 @@ static int finish_reply(struct fsg_common *common)
|
|||
if (common->data_size == 0) {
|
||||
/* Nothing to send */
|
||||
|
||||
/* Don't know what to do if common->fsg is NULL */
|
||||
} else if (!fsg_is_set(common)) {
|
||||
rc = -EIO;
|
||||
|
||||
/* If there's no residue, simply send the last buffer */
|
||||
} else if (common->residue == 0) {
|
||||
bh->inreq->zero = 0;
|
||||
|
|
@ -1710,24 +1689,19 @@ static int finish_reply(struct fsg_common *common)
|
|||
common->next_buffhd_to_fill = bh->next;
|
||||
|
||||
/*
|
||||
* For Bulk-only, if we're allowed to stall then send the
|
||||
* short packet and halt the bulk-in endpoint. If we can't
|
||||
* stall, pad out the remaining data with 0's.
|
||||
* For Bulk-only, mark the end of the data with a short
|
||||
* packet. If we are allowed to stall, halt the bulk-in
|
||||
* endpoint. (Note: This violates the Bulk-Only Transport
|
||||
* specification, which requires us to pad the data if we
|
||||
* don't halt the endpoint. Presumably nobody will mind.)
|
||||
*/
|
||||
} else if (common->can_stall) {
|
||||
} else {
|
||||
bh->inreq->zero = 1;
|
||||
if (!start_in_transfer(common, bh))
|
||||
/* Don't know what to do if
|
||||
* common->fsg is NULL */
|
||||
rc = -EIO;
|
||||
common->next_buffhd_to_fill = bh->next;
|
||||
if (common->fsg)
|
||||
if (common->can_stall)
|
||||
rc = halt_bulk_in_endpoint(common->fsg);
|
||||
} else if (fsg_is_set(common)) {
|
||||
rc = pad_with_zeros(common->fsg);
|
||||
} else {
|
||||
/* Don't know what to do if common->fsg is NULL */
|
||||
rc = -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1910,7 +1884,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
common->lun, lun);
|
||||
|
||||
/* Check the LUN */
|
||||
if (common->lun >= 0 && common->lun < common->nluns) {
|
||||
if (common->lun < common->nluns) {
|
||||
curlun = &common->luns[common->lun];
|
||||
common->curlun = curlun;
|
||||
if (common->cmnd[0] != REQUEST_SENSE) {
|
||||
|
|
@ -2468,7 +2442,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
fsg->common->new_fsg = fsg;
|
||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
||||
return 0;
|
||||
return USB_GADGET_DELAYED_STATUS;
|
||||
}
|
||||
|
||||
static void fsg_disable(struct usb_function *f)
|
||||
|
|
@ -2604,6 +2578,8 @@ static void handle_exception(struct fsg_common *common)
|
|||
|
||||
case FSG_STATE_CONFIG_CHANGE:
|
||||
do_set_interface(common, common->new_fsg);
|
||||
if (common->new_fsg)
|
||||
usb_composite_setup_continue(common->cdev);
|
||||
break;
|
||||
|
||||
case FSG_STATE_EXIT:
|
||||
|
|
@ -2774,6 +2750,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||
common->gadget = gadget;
|
||||
common->ep0 = gadget->ep0;
|
||||
common->ep0req = cdev->req;
|
||||
common->cdev = cdev;
|
||||
|
||||
/* Maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
|
||||
|
|
@ -2800,6 +2777,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||
for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
|
||||
curlun->cdrom = !!lcfg->cdrom;
|
||||
curlun->ro = lcfg->cdrom || lcfg->ro;
|
||||
curlun->initially_ro = curlun->ro;
|
||||
curlun->removable = lcfg->removable;
|
||||
curlun->dev.release = fsg_lun_release;
|
||||
curlun->dev.parent = &gadget->dev;
|
||||
|
|
|
|||
|
|
@ -420,8 +420,7 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
*/
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_SEND_ENCAPSULATED_COMMAND:
|
||||
if (w_length > req->length || w_value
|
||||
|| w_index != rndis->ctrl_id)
|
||||
if (w_value || w_index != rndis->ctrl_id)
|
||||
goto invalid;
|
||||
/* read the request; process it later */
|
||||
value = w_length;
|
||||
|
|
|
|||
|
|
@ -1947,37 +1947,6 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int pad_with_zeros(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
|
||||
u32 nkeep = bh->inreq->length;
|
||||
u32 nsend;
|
||||
int rc;
|
||||
|
||||
bh->state = BUF_STATE_EMPTY; // For the first iteration
|
||||
fsg->usb_amount_left = nkeep + fsg->residue;
|
||||
while (fsg->usb_amount_left > 0) {
|
||||
|
||||
/* Wait for the next buffer to be free */
|
||||
while (bh->state != BUF_STATE_EMPTY) {
|
||||
rc = sleep_thread(fsg);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen);
|
||||
memset(bh->buf + nkeep, 0, nsend - nkeep);
|
||||
bh->inreq->length = nsend;
|
||||
bh->inreq->zero = 0;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
bh = fsg->next_buffhd_to_fill = bh->next;
|
||||
fsg->usb_amount_left -= nsend;
|
||||
nkeep = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int throw_away_data(struct fsg_dev *fsg)
|
||||
{
|
||||
struct fsg_buffhd *bh;
|
||||
|
|
@ -2082,18 +2051,20 @@ static int finish_reply(struct fsg_dev *fsg)
|
|||
}
|
||||
}
|
||||
|
||||
/* For Bulk-only, if we're allowed to stall then send the
|
||||
* short packet and halt the bulk-in endpoint. If we can't
|
||||
* stall, pad out the remaining data with 0's. */
|
||||
/*
|
||||
* For Bulk-only, mark the end of the data with a short
|
||||
* packet. If we are allowed to stall, halt the bulk-in
|
||||
* endpoint. (Note: This violates the Bulk-Only Transport
|
||||
* specification, which requires us to pad the data if we
|
||||
* don't halt the endpoint. Presumably nobody will mind.)
|
||||
*/
|
||||
else {
|
||||
if (mod_data.can_stall) {
|
||||
bh->inreq->zero = 1;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
fsg->next_buffhd_to_fill = bh->next;
|
||||
bh->inreq->zero = 1;
|
||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||
&bh->inreq_busy, &bh->state);
|
||||
fsg->next_buffhd_to_fill = bh->next;
|
||||
if (mod_data.can_stall)
|
||||
rc = halt_bulk_in_endpoint(fsg);
|
||||
} else
|
||||
rc = pad_with_zeros(fsg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2314,7 +2285,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
|||
fsg->lun = lun; // Use LUN from the command
|
||||
|
||||
/* Check the LUN */
|
||||
if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
|
||||
if (fsg->lun < fsg->nluns) {
|
||||
fsg->curlun = curlun = &fsg->luns[fsg->lun];
|
||||
if (fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ struct qe_frame{
|
|||
|
||||
/* Frame status field */
|
||||
/* Receive side */
|
||||
#define FRAME_OK 0x00000000 /* Frame tranmitted or received OK */
|
||||
#define FRAME_OK 0x00000000 /* Frame transmitted or received OK */
|
||||
#define FRAME_ERROR 0x80000000 /* Error occurred on frame */
|
||||
#define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */
|
||||
#define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
/*
|
||||
* Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Li Yang <leoli@freescale.com>
|
||||
* Jiang Bo <tanya.jiang@freescale.com>
|
||||
*
|
||||
* Description:
|
||||
* Freescale high-speed USB SOC DR module device controller driver.
|
||||
* This can be found on MPC8349E/MPC8313E cpus.
|
||||
* This can be found on MPC8349E/MPC8313E/MPC5121E cpus.
|
||||
* The driver is previously named as mpc_udc. Based on bare board
|
||||
* code from Dave Liu and Shlomi Gridish.
|
||||
*
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
#include <asm/system.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "fsl_usb2_udc.h"
|
||||
|
||||
|
|
@ -77,12 +79,64 @@ fsl_ep0_desc = {
|
|||
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
#define fsl_readl(addr) in_le32(addr)
|
||||
#define fsl_writel(val32, addr) out_le32(addr, val32)
|
||||
#else
|
||||
/*
|
||||
* On some SoCs, the USB controller registers can be big or little endian,
|
||||
* depending on the version of the chip. In order to be able to run the
|
||||
* same kernel binary on 2 different versions of an SoC, the BE/LE decision
|
||||
* must be made at run time. _fsl_readl and fsl_writel are pointers to the
|
||||
* BE or LE readl() and writel() functions, and fsl_readl() and fsl_writel()
|
||||
* call through those pointers. Platform code for SoCs that have BE USB
|
||||
* registers should set pdata->big_endian_mmio flag.
|
||||
*
|
||||
* This also applies to controller-to-cpu accessors for the USB descriptors,
|
||||
* since their endianness is also SoC dependant. Platform code for SoCs that
|
||||
* have BE USB descriptors should set pdata->big_endian_desc flag.
|
||||
*/
|
||||
static u32 _fsl_readl_be(const unsigned __iomem *p)
|
||||
{
|
||||
return in_be32(p);
|
||||
}
|
||||
|
||||
static u32 _fsl_readl_le(const unsigned __iomem *p)
|
||||
{
|
||||
return in_le32(p);
|
||||
}
|
||||
|
||||
static void _fsl_writel_be(u32 v, unsigned __iomem *p)
|
||||
{
|
||||
out_be32(p, v);
|
||||
}
|
||||
|
||||
static void _fsl_writel_le(u32 v, unsigned __iomem *p)
|
||||
{
|
||||
out_le32(p, v);
|
||||
}
|
||||
|
||||
static u32 (*_fsl_readl)(const unsigned __iomem *p);
|
||||
static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
|
||||
|
||||
#define fsl_readl(p) (*_fsl_readl)((p))
|
||||
#define fsl_writel(v, p) (*_fsl_writel)((v), (p))
|
||||
|
||||
static inline u32 cpu_to_hc32(const u32 x)
|
||||
{
|
||||
return udc_controller->pdata->big_endian_desc
|
||||
? (__force u32)cpu_to_be32(x)
|
||||
: (__force u32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpu(const u32 x)
|
||||
{
|
||||
return udc_controller->pdata->big_endian_desc
|
||||
? be32_to_cpu((__force __be32)x)
|
||||
: le32_to_cpu((__force __le32)x);
|
||||
}
|
||||
#else /* !CONFIG_PPC32 */
|
||||
#define fsl_readl(addr) readl(addr)
|
||||
#define fsl_writel(val32, addr) writel(val32, addr)
|
||||
#endif
|
||||
#define cpu_to_hc32(x) cpu_to_le32(x)
|
||||
#define hc32_to_cpu(x) le32_to_cpu(x)
|
||||
#endif /* CONFIG_PPC32 */
|
||||
|
||||
/********************************************************************
|
||||
* Internal Used Function
|
||||
|
|
@ -177,7 +231,8 @@ static void nuke(struct fsl_ep *ep, int status)
|
|||
|
||||
static int dr_controller_setup(struct fsl_udc *udc)
|
||||
{
|
||||
unsigned int tmp, portctrl;
|
||||
unsigned int tmp, portctrl, ep_num;
|
||||
unsigned int max_no_of_ep;
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
unsigned int ctrl;
|
||||
#endif
|
||||
|
|
@ -226,9 +281,12 @@ static int dr_controller_setup(struct fsl_udc *udc)
|
|||
|
||||
/* Set the controller as device mode */
|
||||
tmp = fsl_readl(&dr_regs->usbmode);
|
||||
tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
|
||||
tmp |= USB_MODE_CTRL_MODE_DEVICE;
|
||||
/* Disable Setup Lockout */
|
||||
tmp |= USB_MODE_SETUP_LOCK_OFF;
|
||||
if (udc->pdata->es)
|
||||
tmp |= USB_MODE_ES;
|
||||
fsl_writel(tmp, &dr_regs->usbmode);
|
||||
|
||||
/* Clear the setup status */
|
||||
|
|
@ -242,22 +300,34 @@ static int dr_controller_setup(struct fsl_udc *udc)
|
|||
udc->ep_qh, (int)tmp,
|
||||
fsl_readl(&dr_regs->endpointlistaddr));
|
||||
|
||||
max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
|
||||
for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
|
||||
tmp = fsl_readl(&dr_regs->endptctrl[ep_num]);
|
||||
tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
|
||||
tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
|
||||
| (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
|
||||
fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
|
||||
}
|
||||
/* Config control enable i/o output, cpu endian register */
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
ctrl = __raw_readl(&usb_sys_regs->control);
|
||||
ctrl |= USB_CTRL_IOENB;
|
||||
__raw_writel(ctrl, &usb_sys_regs->control);
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
ctrl = __raw_readl(&usb_sys_regs->control);
|
||||
ctrl |= USB_CTRL_IOENB;
|
||||
__raw_writel(ctrl, &usb_sys_regs->control);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
/* Turn on cache snooping hardware, since some PowerPC platforms
|
||||
* wholly rely on hardware to deal with cache coherent. */
|
||||
|
||||
/* Setup Snooping for all the 4GB space */
|
||||
tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop1);
|
||||
tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop2);
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
/* Setup Snooping for all the 4GB space */
|
||||
tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop1);
|
||||
tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
|
||||
__raw_writel(tmp, &usb_sys_regs->snoop2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -293,6 +363,19 @@ static void dr_controller_stop(struct fsl_udc *udc)
|
|||
{
|
||||
unsigned int tmp;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
/* if we're in OTG mode, and the Host is currently using the port,
|
||||
* stop now and don't rip the controller out from under the
|
||||
* ehci driver
|
||||
*/
|
||||
if (udc->gadget.is_otg) {
|
||||
if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
|
||||
pr_debug("udc: Leaving early\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable all INTR */
|
||||
fsl_writel(0, &dr_regs->usbintr);
|
||||
|
||||
|
|
@ -318,12 +401,14 @@ static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
|
|||
if (ep_num)
|
||||
tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
|
||||
tmp_epctrl |= EPCTRL_TX_ENABLE;
|
||||
tmp_epctrl &= ~EPCTRL_TX_TYPE;
|
||||
tmp_epctrl |= ((unsigned int)(ep_type)
|
||||
<< EPCTRL_TX_EP_TYPE_SHIFT);
|
||||
} else {
|
||||
if (ep_num)
|
||||
tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
|
||||
tmp_epctrl |= EPCTRL_RX_ENABLE;
|
||||
tmp_epctrl &= ~EPCTRL_RX_TYPE;
|
||||
tmp_epctrl |= ((unsigned int)(ep_type)
|
||||
<< EPCTRL_RX_EP_TYPE_SHIFT);
|
||||
}
|
||||
|
|
@ -409,7 +494,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
|
|||
if (zlt)
|
||||
tmp |= EP_QUEUE_HEAD_ZLT_SEL;
|
||||
|
||||
p_QH->max_pkt_length = cpu_to_le32(tmp);
|
||||
p_QH->max_pkt_length = cpu_to_hc32(tmp);
|
||||
p_QH->next_dtd_ptr = 1;
|
||||
p_QH->size_ioc_int_sts = 0;
|
||||
}
|
||||
|
|
@ -546,10 +631,13 @@ static int fsl_ep_disable(struct usb_ep *_ep)
|
|||
/* disable ep on controller */
|
||||
ep_num = ep_index(ep);
|
||||
epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
|
||||
if (ep_is_in(ep))
|
||||
epctrl &= ~EPCTRL_TX_ENABLE;
|
||||
else
|
||||
epctrl &= ~EPCTRL_RX_ENABLE;
|
||||
if (ep_is_in(ep)) {
|
||||
epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
|
||||
epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
|
||||
} else {
|
||||
epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
|
||||
epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
|
||||
}
|
||||
fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
|
||||
|
||||
udc = (struct fsl_udc *)ep->udc;
|
||||
|
|
@ -616,7 +704,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
|
|||
struct fsl_req *lastreq;
|
||||
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
|
||||
lastreq->tail->next_td_ptr =
|
||||
cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
|
||||
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
|
||||
/* Read prime bit, if 1 goto done */
|
||||
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
|
||||
goto out;
|
||||
|
|
@ -641,10 +729,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
|
|||
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
dQH->next_dtd_ptr = cpu_to_le32(temp);
|
||||
dQH->next_dtd_ptr = cpu_to_hc32(temp);
|
||||
|
||||
/* Clear active and halt bit */
|
||||
temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
|
||||
temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
|
||||
| EP_QUEUE_HEAD_STATUS_HALT));
|
||||
dQH->size_ioc_int_sts &= temp;
|
||||
|
||||
|
|
@ -682,17 +770,17 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
|
|||
|
||||
dtd->td_dma = *dma;
|
||||
/* Clear reserved field */
|
||||
swap_temp = cpu_to_le32(dtd->size_ioc_sts);
|
||||
swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
|
||||
swap_temp &= ~DTD_RESERVED_FIELDS;
|
||||
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
|
||||
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
|
||||
|
||||
/* Init all of buffer page pointers */
|
||||
swap_temp = (u32) (req->req.dma + req->req.actual);
|
||||
dtd->buff_ptr0 = cpu_to_le32(swap_temp);
|
||||
dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
|
||||
dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
|
||||
dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
|
||||
dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
|
||||
dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
|
||||
dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
|
||||
dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
|
||||
dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
|
||||
dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
|
||||
|
||||
req->req.actual += *length;
|
||||
|
||||
|
|
@ -716,7 +804,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
|
|||
if (*is_last && !req->req.no_interrupt)
|
||||
swap_temp |= DTD_IOC;
|
||||
|
||||
dtd->size_ioc_sts = cpu_to_le32(swap_temp);
|
||||
dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
|
||||
|
||||
mb();
|
||||
|
||||
|
|
@ -743,7 +831,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
|
|||
is_first = 0;
|
||||
req->head = dtd;
|
||||
} else {
|
||||
last_dtd->next_td_ptr = cpu_to_le32(dma);
|
||||
last_dtd->next_td_ptr = cpu_to_hc32(dma);
|
||||
last_dtd->next_td_virt = dtd;
|
||||
}
|
||||
last_dtd = dtd;
|
||||
|
|
@ -751,7 +839,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
|
|||
req->dtd_count++;
|
||||
} while (!is_last);
|
||||
|
||||
dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
|
||||
dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
|
||||
|
||||
req->tail = dtd;
|
||||
|
||||
|
|
@ -962,6 +1050,36 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int fsl_ep_fifo_status(struct usb_ep *_ep)
|
||||
{
|
||||
struct fsl_ep *ep;
|
||||
struct fsl_udc *udc;
|
||||
int size = 0;
|
||||
u32 bitmask;
|
||||
struct ep_queue_head *d_qh;
|
||||
|
||||
ep = container_of(_ep, struct fsl_ep, ep);
|
||||
if (!_ep || (!ep->desc && ep_index(ep) != 0))
|
||||
return -ENODEV;
|
||||
|
||||
udc = (struct fsl_udc *)ep->udc;
|
||||
|
||||
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
|
||||
|
||||
bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
|
||||
(1 << (ep_index(ep)));
|
||||
|
||||
if (fsl_readl(&dr_regs->endptstatus) & bitmask)
|
||||
size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
|
||||
>> DTD_LENGTH_BIT_POS;
|
||||
|
||||
pr_debug("%s %u\n", __func__, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void fsl_ep_fifo_flush(struct usb_ep *_ep)
|
||||
{
|
||||
struct fsl_ep *ep;
|
||||
|
|
@ -1014,6 +1132,7 @@ static struct usb_ep_ops fsl_ep_ops = {
|
|||
.dequeue = fsl_ep_dequeue,
|
||||
|
||||
.set_halt = fsl_ep_set_halt,
|
||||
.fifo_status = fsl_ep_fifo_status,
|
||||
.fifo_flush = fsl_ep_fifo_flush, /* flush fifo */
|
||||
};
|
||||
|
||||
|
|
@ -1228,6 +1347,10 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
|
|||
req = udc->status_req;
|
||||
/* Fill in the reqest structure */
|
||||
*((u16 *) req->req.buf) = cpu_to_le16(tmp);
|
||||
|
||||
/* flush cache for the req buffer */
|
||||
flush_dcache_range((u32)req->req.buf, (u32)req->req.buf + 8);
|
||||
|
||||
req->ep = ep;
|
||||
req->req.length = 2;
|
||||
req->req.status = -EINPROGRESS;
|
||||
|
|
@ -1280,6 +1403,7 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
/* Status phase from udc */
|
||||
{
|
||||
int rc = -EOPNOTSUPP;
|
||||
u16 ptc = 0;
|
||||
|
||||
if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
|
||||
== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
|
||||
|
|
@ -1301,17 +1425,19 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
| USB_TYPE_STANDARD)) {
|
||||
/* Note: The driver has not include OTG support yet.
|
||||
* This will be set when OTG support is added */
|
||||
if (!gadget_is_otg(&udc->gadget))
|
||||
break;
|
||||
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
|
||||
udc->gadget.b_hnp_enable = 1;
|
||||
else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
|
||||
udc->gadget.a_hnp_support = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_ALT_HNP_SUPPORT)
|
||||
udc->gadget.a_alt_hnp_support = 1;
|
||||
else
|
||||
break;
|
||||
if (wValue == USB_DEVICE_TEST_MODE)
|
||||
ptc = wIndex >> 8;
|
||||
else if (gadget_is_otg(&udc->gadget)) {
|
||||
if (setup->bRequest ==
|
||||
USB_DEVICE_B_HNP_ENABLE)
|
||||
udc->gadget.b_hnp_enable = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_HNP_SUPPORT)
|
||||
udc->gadget.a_hnp_support = 1;
|
||||
else if (setup->bRequest ==
|
||||
USB_DEVICE_A_ALT_HNP_SUPPORT)
|
||||
udc->gadget.a_alt_hnp_support = 1;
|
||||
}
|
||||
rc = 0;
|
||||
} else
|
||||
break;
|
||||
|
|
@ -1320,6 +1446,15 @@ static void setup_received_irq(struct fsl_udc *udc,
|
|||
if (ep0_prime_status(udc, EP_DIR_IN))
|
||||
ep0stall(udc);
|
||||
}
|
||||
if (ptc) {
|
||||
u32 tmp;
|
||||
|
||||
mdelay(10);
|
||||
tmp = fsl_readl(&dr_regs->portsc1) | (ptc << 16);
|
||||
fsl_writel(tmp, &dr_regs->portsc1);
|
||||
printk(KERN_INFO "udc: switch to test mode %d.\n", ptc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1394,6 +1529,7 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
|
|||
{
|
||||
u32 temp;
|
||||
struct ep_queue_head *qh;
|
||||
struct fsl_usb2_platform_data *pdata = udc->pdata;
|
||||
|
||||
qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
|
||||
|
||||
|
|
@ -1408,7 +1544,16 @@ static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
|
|||
fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
|
||||
|
||||
/* Copy the setup packet to local buffer */
|
||||
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
|
||||
if (pdata->le_setup_buf) {
|
||||
u32 *p = (u32 *)buffer_ptr;
|
||||
u32 *s = (u32 *)qh->setup_buffer;
|
||||
|
||||
/* Convert little endian setup buffer to CPU endian */
|
||||
*p++ = le32_to_cpu(*s++);
|
||||
*p = le32_to_cpu(*s);
|
||||
} else {
|
||||
memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
|
||||
}
|
||||
} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
|
||||
|
||||
/* Clear Setup Tripwire */
|
||||
|
|
@ -1432,19 +1577,19 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
|||
actual = curr_req->req.length;
|
||||
|
||||
for (j = 0; j < curr_req->dtd_count; j++) {
|
||||
remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
|
||||
remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
|
||||
& DTD_PACKET_SIZE)
|
||||
>> DTD_LENGTH_BIT_POS;
|
||||
actual -= remaining_length;
|
||||
|
||||
if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
|
||||
DTD_ERROR_MASK)) {
|
||||
errors = hc32_to_cpu(curr_td->size_ioc_sts);
|
||||
if (errors & DTD_ERROR_MASK) {
|
||||
if (errors & DTD_STATUS_HALTED) {
|
||||
ERR("dTD error %08x QH=%d\n", errors, pipe);
|
||||
/* Clear the errors and Halt condition */
|
||||
tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
|
||||
tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
|
||||
tmp &= ~errors;
|
||||
curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
|
||||
curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp);
|
||||
status = -EPIPE;
|
||||
/* FIXME: continue with next queued TD? */
|
||||
|
||||
|
|
@ -1462,7 +1607,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
|||
ERR("Unknown error has occurred (0x%x)!\n",
|
||||
errors);
|
||||
|
||||
} else if (le32_to_cpu(curr_td->size_ioc_sts)
|
||||
} else if (hc32_to_cpu(curr_td->size_ioc_sts)
|
||||
& DTD_STATUS_ACTIVE) {
|
||||
VDBG("Request not complete");
|
||||
status = REQ_UNCOMPLETE;
|
||||
|
|
@ -1551,6 +1696,9 @@ static void port_change_irq(struct fsl_udc *udc)
|
|||
{
|
||||
u32 speed;
|
||||
|
||||
if (udc->bus_reset)
|
||||
udc->bus_reset = 0;
|
||||
|
||||
/* Bus resetting is finished */
|
||||
if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
|
||||
/* Get the speed */
|
||||
|
|
@ -1658,6 +1806,8 @@ static void reset_irq(struct fsl_udc *udc)
|
|||
|
||||
if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
|
||||
VDBG("Bus reset");
|
||||
/* Bus is reseting */
|
||||
udc->bus_reset = 1;
|
||||
/* Reset all the queues, include XD, dTD, EP queue
|
||||
* head and TR Queue */
|
||||
reset_queues(udc);
|
||||
|
|
@ -1735,6 +1885,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
|
|||
|
||||
/* Reset Received */
|
||||
if (irq_src & USB_STS_RESET) {
|
||||
VDBG("reset int");
|
||||
reset_irq(udc);
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -1792,11 +1943,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
|
||||
dr_controller_run(udc_controller);
|
||||
udc_controller->usb_state = USB_STATE_ATTACHED;
|
||||
udc_controller->ep0_state = WAIT_FOR_SETUP;
|
||||
udc_controller->ep0_dir = 0;
|
||||
if (udc_controller->transceiver) {
|
||||
/* Suspend the controller until OTG enable it */
|
||||
udc_controller->stopped = 1;
|
||||
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (udc_controller->transceiver) {
|
||||
retval = otg_set_peripheral(udc_controller->transceiver,
|
||||
&udc_controller->gadget);
|
||||
if (retval < 0) {
|
||||
ERR("can't bind to transceiver\n");
|
||||
driver->unbind(&udc_controller->gadget);
|
||||
udc_controller->gadget.dev.driver = 0;
|
||||
udc_controller->driver = 0;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Enable DR IRQ reg and set USBCMD reg Run bit */
|
||||
dr_controller_run(udc_controller);
|
||||
udc_controller->usb_state = USB_STATE_ATTACHED;
|
||||
udc_controller->ep0_state = WAIT_FOR_SETUP;
|
||||
udc_controller->ep0_dir = 0;
|
||||
}
|
||||
printk(KERN_INFO "%s: bind to driver %s\n",
|
||||
udc_controller->gadget.name, driver->driver.name);
|
||||
|
||||
|
|
@ -2044,16 +2214,18 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
|
|||
next += t;
|
||||
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
tmp_reg = usb_sys_regs->snoop1;
|
||||
t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
if (udc->pdata->have_sysif_regs) {
|
||||
tmp_reg = usb_sys_regs->snoop1;
|
||||
t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
|
||||
tmp_reg = usb_sys_regs->control;
|
||||
t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
|
||||
tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
tmp_reg = usb_sys_regs->control;
|
||||
t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
|
||||
tmp_reg);
|
||||
size -= t;
|
||||
next += t;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
|
||||
|
|
@ -2233,6 +2405,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
|
|||
*/
|
||||
static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct resource *res;
|
||||
int ret = -ENODEV;
|
||||
unsigned int i;
|
||||
|
|
@ -2249,20 +2422,35 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
udc_controller->pdata = pdata;
|
||||
spin_lock_init(&udc_controller->lock);
|
||||
udc_controller->stopped = 1;
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
udc_controller->transceiver = otg_get_transceiver();
|
||||
if (!udc_controller->transceiver) {
|
||||
ERR("Can't find OTG driver!\n");
|
||||
ret = -ENODEV;
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENXIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
driver_name)) {
|
||||
ERR("request mem region for %s failed\n", pdev->name);
|
||||
ret = -EBUSY;
|
||||
goto err_kfree;
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
|
||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
driver_name)) {
|
||||
ERR("request mem region for %s failed\n", pdev->name);
|
||||
ret = -EBUSY;
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
|
||||
dr_regs = ioremap(res->start, resource_size(res));
|
||||
|
|
@ -2271,9 +2459,29 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
goto err_release_mem_region;
|
||||
}
|
||||
|
||||
pdata->regs = (void *)dr_regs;
|
||||
|
||||
/*
|
||||
* do platform specific init: check the clock, grab/config pins, etc.
|
||||
*/
|
||||
if (pdata->init && pdata->init(pdev)) {
|
||||
ret = -ENODEV;
|
||||
goto err_iounmap_noclk;
|
||||
}
|
||||
|
||||
/* Set accessors only after pdata->init() ! */
|
||||
if (pdata->big_endian_mmio) {
|
||||
_fsl_readl = _fsl_readl_be;
|
||||
_fsl_writel = _fsl_writel_be;
|
||||
} else {
|
||||
_fsl_readl = _fsl_readl_le;
|
||||
_fsl_writel = _fsl_writel_le;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARCH_MXC
|
||||
usb_sys_regs = (struct usb_sys_interface *)
|
||||
((u32)dr_regs + USB_DR_SYS_OFFSET);
|
||||
if (pdata->have_sysif_regs)
|
||||
usb_sys_regs = (struct usb_sys_interface *)
|
||||
((u32)dr_regs + USB_DR_SYS_OFFSET);
|
||||
#endif
|
||||
|
||||
/* Initialize USB clocks */
|
||||
|
|
@ -2313,9 +2521,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
goto err_free_irq;
|
||||
}
|
||||
|
||||
/* initialize usb hw reg except for regs for EP,
|
||||
* leave usbintr reg untouched */
|
||||
dr_controller_setup(udc_controller);
|
||||
if (!udc_controller->transceiver) {
|
||||
/* initialize usb hw reg except for regs for EP,
|
||||
* leave usbintr reg untouched */
|
||||
dr_controller_setup(udc_controller);
|
||||
}
|
||||
|
||||
fsl_udc_clk_finalize(pdev);
|
||||
|
||||
|
|
@ -2335,6 +2545,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
if (udc_controller->transceiver)
|
||||
udc_controller->gadget.is_otg = 1;
|
||||
|
||||
/* setup QH and epctrl for ep0 */
|
||||
ep0_setup(udc_controller);
|
||||
|
||||
|
|
@ -2373,11 +2586,14 @@ err_unregister:
|
|||
err_free_irq:
|
||||
free_irq(udc_controller->irq, udc_controller);
|
||||
err_iounmap:
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
fsl_udc_clk_release();
|
||||
err_iounmap_noclk:
|
||||
iounmap(dr_regs);
|
||||
err_release_mem_region:
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
err_kfree:
|
||||
kfree(udc_controller);
|
||||
udc_controller = NULL;
|
||||
|
|
@ -2390,6 +2606,7 @@ err_kfree:
|
|||
static int __exit fsl_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
DECLARE_COMPLETION(done);
|
||||
|
||||
|
|
@ -2410,12 +2627,20 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
|
|||
dma_pool_destroy(udc_controller->td_pool);
|
||||
free_irq(udc_controller->irq, udc_controller);
|
||||
iounmap(dr_regs);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
/* free udc --wait for the release() finished */
|
||||
wait_for_completion(&done);
|
||||
|
||||
/*
|
||||
* do platform specific un-initialization:
|
||||
* release iomux pins, etc.
|
||||
*/
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2446,6 +2671,62 @@ static int fsl_udc_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct fsl_udc *udc = udc_controller;
|
||||
u32 mode, usbcmd;
|
||||
|
||||
mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
|
||||
|
||||
pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped);
|
||||
|
||||
/*
|
||||
* If the controller is already stopped, then this must be a
|
||||
* PM suspend. Remember this fact, so that we will leave the
|
||||
* controller stopped at PM resume time.
|
||||
*/
|
||||
if (udc->stopped) {
|
||||
pr_debug("gadget already stopped, leaving early\n");
|
||||
udc->already_stopped = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mode != USB_MODE_CTRL_MODE_DEVICE) {
|
||||
pr_debug("gadget not in device mode, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* stop the controller */
|
||||
usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
|
||||
fsl_writel(usbcmd, &dr_regs->usbcmd);
|
||||
|
||||
udc->stopped = 1;
|
||||
|
||||
pr_info("USB Gadget suspended\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_udc_otg_resume(struct device *dev)
|
||||
{
|
||||
pr_debug("%s(): stopped %d already_stopped %d\n", __func__,
|
||||
udc_controller->stopped, udc_controller->already_stopped);
|
||||
|
||||
/*
|
||||
* If the controller was stopped at suspend time, then
|
||||
* don't resume it now.
|
||||
*/
|
||||
if (udc_controller->already_stopped) {
|
||||
udc_controller->already_stopped = 0;
|
||||
pr_debug("gadget was already stopped, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_info("USB Gadget resume\n");
|
||||
|
||||
return fsl_udc_resume(NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Register entry point for the peripheral controller driver
|
||||
--------------------------------------------------------------------------*/
|
||||
|
|
@ -2458,6 +2739,9 @@ static struct platform_driver udc_driver = {
|
|||
.driver = {
|
||||
.name = (char *)driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
/* udc suspend/resume called from OTG driver */
|
||||
.suspend = fsl_udc_otg_suspend,
|
||||
.resume = fsl_udc_otg_resume,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,9 @@ struct usb_sys_interface {
|
|||
#define USB_MODE_CTRL_MODE_IDLE 0x00000000
|
||||
#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
|
||||
#define USB_MODE_CTRL_MODE_HOST 0x00000003
|
||||
#define USB_MODE_CTRL_MODE_MASK 0x00000003
|
||||
#define USB_MODE_CTRL_MODE_RSV 0x00000001
|
||||
#define USB_MODE_ES 0x00000004 /* Endian Select */
|
||||
#define USB_MODE_SETUP_LOCK_OFF 0x00000008
|
||||
#define USB_MODE_STREAM_DISABLE 0x00000010
|
||||
/* Endpoint Flush Register */
|
||||
|
|
@ -461,6 +463,7 @@ struct fsl_ep {
|
|||
struct fsl_udc {
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct completion *done; /* to make sure release() is done */
|
||||
struct fsl_ep *eps;
|
||||
unsigned int max_ep;
|
||||
|
|
@ -473,6 +476,8 @@ struct fsl_udc {
|
|||
unsigned vbus_active:1;
|
||||
unsigned stopped:1;
|
||||
unsigned remote_wakeup:1;
|
||||
unsigned already_stopped:1;
|
||||
unsigned big_endian_desc:1;
|
||||
|
||||
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
|
||||
struct fsl_req *status_req; /* ep0 status request */
|
||||
|
|
@ -483,6 +488,7 @@ struct fsl_udc {
|
|||
dma_addr_t ep_qh_dma; /* dma address of QH */
|
||||
|
||||
u32 max_pipes; /* Device max pipes */
|
||||
u32 bus_reset; /* Device is bus resetting */
|
||||
u32 resume_state; /* USB state to resume */
|
||||
u32 usb_state; /* USB current state */
|
||||
u32 ep0_state; /* Endpoint zero state */
|
||||
|
|
|
|||
|
|
@ -136,6 +136,12 @@
|
|||
#define gadget_is_s3c_hsotg(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_S3C_HSUDC
|
||||
#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_s3c_hsudc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_EG20T
|
||||
#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
|
||||
#else
|
||||
|
|
@ -148,6 +154,12 @@
|
|||
#define gadget_is_ci13xxx_msm(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
|
||||
#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_renesas_usbhs(g) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* usb_gadget_controller_number - support bcdDevice id convention
|
||||
* @gadget: the controller being driven
|
||||
|
|
@ -207,6 +219,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
|||
return 0x27;
|
||||
else if (gadget_is_ci13xxx_msm(gadget))
|
||||
return 0x28;
|
||||
else if (gadget_is_renesas_usbhs(gadget))
|
||||
return 0x29;
|
||||
else if (gadget_is_s3c_hsudc(gadget))
|
||||
return 0x30;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1189,6 +1189,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
else if (gadget->a_alt_hnp_support)
|
||||
DBG(dev, "HNP needs a different root port\n");
|
||||
value = printer_set_config(dev, wValue);
|
||||
if (!value)
|
||||
value = set_interface(dev, PRINTER_INTERFACE);
|
||||
break;
|
||||
case USB_REQ_GET_CONFIGURATION:
|
||||
if (ctrl->bRequestType != USB_DIR_IN)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
/* linux/drivers/usb/gadget/s3c-hsotg.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
|
|
@ -613,11 +616,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
|
|||
maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
|
||||
} else {
|
||||
maxsize = 64+64;
|
||||
if (hs_ep->dir_in) {
|
||||
if (hs_ep->dir_in)
|
||||
maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
|
||||
} else {
|
||||
else
|
||||
maxpkt = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* we made the constant loading easier above by using +1 */
|
||||
|
|
@ -679,6 +681,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
|||
__func__, readl(hsotg->regs + epctrl_reg), index,
|
||||
hs_ep->dir_in ? "in" : "out");
|
||||
|
||||
/* If endpoint is stalled, we will restart request later */
|
||||
ctrl = readl(hsotg->regs + epctrl_reg);
|
||||
|
||||
if (ctrl & S3C_DxEPCTL_Stall) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
|
||||
return;
|
||||
}
|
||||
|
||||
length = ureq->length - ureq->actual;
|
||||
|
||||
if (0)
|
||||
|
|
@ -731,18 +741,6 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
|||
/* write size / packets */
|
||||
writel(epsize, hsotg->regs + epsize_reg);
|
||||
|
||||
ctrl = readl(hsotg->regs + epctrl_reg);
|
||||
|
||||
if (ctrl & S3C_DxEPCTL_Stall) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
|
||||
|
||||
/* not sure what we can do here, if it is EP0 then we should
|
||||
* get this cleared once the endpoint has transmitted the
|
||||
* STALL packet, otherwise it needs to be cleared by the
|
||||
* host.
|
||||
*/
|
||||
}
|
||||
|
||||
if (using_dma(hsotg)) {
|
||||
unsigned int dma_reg;
|
||||
|
||||
|
|
@ -1047,6 +1045,20 @@ static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg,
|
|||
|
||||
static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value);
|
||||
|
||||
/**
|
||||
* get_ep_head - return the first request on the endpoint
|
||||
* @hs_ep: The controller endpoint to get
|
||||
*
|
||||
* Get the first request on the endpoint.
|
||||
*/
|
||||
static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
|
||||
{
|
||||
if (list_empty(&hs_ep->queue))
|
||||
return NULL;
|
||||
|
||||
return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
|
||||
* @hsotg: The device state
|
||||
|
|
@ -1055,8 +1067,12 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value);
|
|||
static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
|
||||
struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
|
||||
struct s3c_hsotg_req *hs_req;
|
||||
bool restart;
|
||||
bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
|
||||
struct s3c_hsotg_ep *ep;
|
||||
int ret;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
|
||||
__func__, set ? "SET" : "CLEAR");
|
||||
|
|
@ -1072,6 +1088,36 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
|
|||
switch (le16_to_cpu(ctrl->wValue)) {
|
||||
case USB_ENDPOINT_HALT:
|
||||
s3c_hsotg_ep_sethalt(&ep->ep, set);
|
||||
|
||||
ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev,
|
||||
"%s: failed to send reply\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!set) {
|
||||
/*
|
||||
* If we have request in progress,
|
||||
* then complete it
|
||||
*/
|
||||
if (ep->req) {
|
||||
hs_req = ep->req;
|
||||
ep->req = NULL;
|
||||
list_del_init(&hs_req->queue);
|
||||
hs_req->req.complete(&ep->ep,
|
||||
&hs_req->req);
|
||||
}
|
||||
|
||||
/* If we have pending request, then start it */
|
||||
restart = !list_empty(&ep->queue);
|
||||
if (restart) {
|
||||
hs_req = get_ep_head(ep);
|
||||
s3c_hsotg_start_req(hsotg, ep,
|
||||
hs_req, false);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1148,14 +1194,6 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
|
|||
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (!ep0->dir_in) {
|
||||
/* need to generate zlp in reply or take data */
|
||||
/* todo - deal with any data we might be sent? */
|
||||
ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* the request is either unhandlable, or is not formatted correctly
|
||||
* so respond with a STALL for the status stage to indicate failure.
|
||||
*/
|
||||
|
|
@ -1246,20 +1284,6 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_ep_head - return the first request on the endpoint
|
||||
* @hs_ep: The controller endpoint to get
|
||||
*
|
||||
* Get the first request on the endpoint.
|
||||
*/
|
||||
static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
|
||||
{
|
||||
if (list_empty(&hs_ep->queue))
|
||||
return NULL;
|
||||
|
||||
return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_complete_request - complete a request given to us
|
||||
* @hsotg: The device state.
|
||||
|
|
@ -1683,6 +1707,37 @@ bad_mps:
|
|||
dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_txfifo_flush - flush Tx FIFO
|
||||
* @hsotg: The driver state
|
||||
* @idx: The index for the endpoint (0..15)
|
||||
*/
|
||||
static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
|
||||
{
|
||||
int timeout;
|
||||
int val;
|
||||
|
||||
writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh,
|
||||
hsotg->regs + S3C_GRSTCTL);
|
||||
|
||||
/* wait until the fifo is flushed */
|
||||
timeout = 100;
|
||||
|
||||
while (1) {
|
||||
val = readl(hsotg->regs + S3C_GRSTCTL);
|
||||
|
||||
if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0)
|
||||
break;
|
||||
|
||||
if (--timeout == 0) {
|
||||
dev_err(hsotg->dev,
|
||||
"%s: timeout flushing fifo (GRSTCTL=%08x)\n",
|
||||
__func__, val);
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_trytx - check to see if anything needs transmitting
|
||||
|
|
@ -1775,10 +1830,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
|
||||
u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
|
||||
u32 ints;
|
||||
u32 clear = 0;
|
||||
|
||||
ints = readl(hsotg->regs + epint_reg);
|
||||
|
||||
/* Clear endpoint interrupts */
|
||||
writel(ints, hsotg->regs + epint_reg);
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
|
||||
__func__, idx, dir_in ? "in" : "out", ints);
|
||||
|
||||
|
|
@ -1801,19 +1858,28 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
|
||||
s3c_hsotg_handle_outdone(hsotg, idx, false);
|
||||
}
|
||||
|
||||
clear |= S3C_DxEPINT_XferCompl;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_EPDisbld) {
|
||||
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
|
||||
clear |= S3C_DxEPINT_EPDisbld;
|
||||
|
||||
if (dir_in) {
|
||||
int epctl = readl(hsotg->regs + epctl_reg);
|
||||
|
||||
s3c_hsotg_txfifo_flush(hsotg, idx);
|
||||
|
||||
if ((epctl & S3C_DxEPCTL_Stall) &&
|
||||
(epctl & S3C_DxEPCTL_EPType_Bulk)) {
|
||||
int dctl = readl(hsotg->regs + S3C_DCTL);
|
||||
|
||||
dctl |= S3C_DCTL_CGNPInNAK;
|
||||
writel(dctl, hsotg->regs + S3C_DCTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_AHBErr) {
|
||||
if (ints & S3C_DxEPINT_AHBErr)
|
||||
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
|
||||
clear |= S3C_DxEPINT_AHBErr;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */
|
||||
dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__);
|
||||
|
|
@ -1829,14 +1895,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
else
|
||||
s3c_hsotg_handle_outdone(hsotg, 0, true);
|
||||
}
|
||||
|
||||
clear |= S3C_DxEPINT_Setup;
|
||||
}
|
||||
|
||||
if (ints & S3C_DxEPINT_Back2BackSetup) {
|
||||
if (ints & S3C_DxEPINT_Back2BackSetup)
|
||||
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
|
||||
clear |= S3C_DxEPINT_Back2BackSetup;
|
||||
}
|
||||
|
||||
if (dir_in) {
|
||||
/* not sure if this is important, but we'll clear it anyway
|
||||
|
|
@ -1844,14 +1906,12 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
|
||||
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
|
||||
__func__, idx);
|
||||
clear |= S3C_DIEPMSK_INTknTXFEmpMsk;
|
||||
}
|
||||
|
||||
/* this probably means something bad is happening */
|
||||
if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
|
||||
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
|
||||
__func__, idx);
|
||||
clear |= S3C_DIEPMSK_INTknEPMisMsk;
|
||||
}
|
||||
|
||||
/* FIFO has space or is empty (see GAHBCFG) */
|
||||
|
|
@ -1860,11 +1920,8 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|||
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
|
||||
__func__, idx);
|
||||
s3c_hsotg_trytx(hsotg, hs_ep);
|
||||
clear |= S3C_DIEPMSK_TxFIFOEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
writel(clear, hsotg->regs + epint_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2056,7 +2113,6 @@ irq_retry:
|
|||
dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
|
||||
|
||||
writel(otgint, hsotg->regs + S3C_GOTGINT);
|
||||
writel(S3C_GINTSTS_OTGInt, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_DisconnInt) {
|
||||
|
|
@ -2072,8 +2128,9 @@ irq_retry:
|
|||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_EnumDone) {
|
||||
s3c_hsotg_irq_enumdone(hsotg);
|
||||
writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_irq_enumdone(hsotg);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_ConIDStsChng) {
|
||||
|
|
@ -2101,10 +2158,6 @@ irq_retry:
|
|||
if (daint_in & 1)
|
||||
s3c_hsotg_epint(hsotg, ep, 1);
|
||||
}
|
||||
|
||||
writel(daint, hsotg->regs + S3C_DAINT);
|
||||
writel(gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt),
|
||||
hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_USBRst) {
|
||||
|
|
@ -2112,6 +2165,8 @@ irq_retry:
|
|||
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
|
||||
readl(hsotg->regs + S3C_GNPTXSTS));
|
||||
|
||||
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
|
||||
|
||||
/* it seems after a reset we can end up with a situation
|
||||
|
|
@ -2123,8 +2178,6 @@ irq_retry:
|
|||
s3c_hsotg_init_fifo(hsotg);
|
||||
|
||||
s3c_hsotg_enqueue_setup(hsotg);
|
||||
|
||||
writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
/* check both FIFOs */
|
||||
|
|
@ -2138,8 +2191,6 @@ irq_retry:
|
|||
|
||||
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
|
||||
s3c_hsotg_irq_fifoempty(hsotg, false);
|
||||
|
||||
writel(S3C_GINTSTS_NPTxFEmp, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_PTxFEmp) {
|
||||
|
|
@ -2149,8 +2200,6 @@ irq_retry:
|
|||
|
||||
s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
|
||||
s3c_hsotg_irq_fifoempty(hsotg, true);
|
||||
|
||||
writel(S3C_GINTSTS_PTxFEmp, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_RxFLvl) {
|
||||
|
|
@ -2159,7 +2208,6 @@ irq_retry:
|
|||
* set. */
|
||||
|
||||
s3c_hsotg_handle_rx(hsotg);
|
||||
writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_ModeMis) {
|
||||
|
|
@ -2193,19 +2241,17 @@ irq_retry:
|
|||
if (gintsts & S3C_GINTSTS_GOUTNakEff) {
|
||||
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
|
||||
writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
|
||||
writel(S3C_GINTSTS_GOUTNakEff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
}
|
||||
|
||||
if (gintsts & S3C_GINTSTS_GINNakEff) {
|
||||
dev_info(hsotg->dev, "GINNakEff triggered\n");
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
|
||||
writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
|
||||
writel(S3C_GINTSTS_GINNakEff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
s3c_hsotg_dump(hsotg);
|
||||
}
|
||||
|
||||
/* if we've had fifo events, we should try and go around the
|
||||
|
|
@ -2403,11 +2449,6 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
|||
|
||||
dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
|
||||
|
||||
if (hs_req == hs_ep->req) {
|
||||
dev_dbg(hs->dev, "%s: already in progress\n", __func__);
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
|
||||
if (!on_list(hs_ep, hs_req)) {
|
||||
|
|
@ -2429,6 +2470,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
unsigned long irqflags;
|
||||
u32 epreg;
|
||||
u32 epctl;
|
||||
u32 xfertype;
|
||||
|
||||
dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
|
||||
|
||||
|
|
@ -2439,10 +2481,17 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
epreg = S3C_DIEPCTL(index);
|
||||
epctl = readl(hs->regs + epreg);
|
||||
|
||||
if (value)
|
||||
epctl |= S3C_DxEPCTL_Stall;
|
||||
else
|
||||
if (value) {
|
||||
epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK;
|
||||
if (epctl & S3C_DxEPCTL_EPEna)
|
||||
epctl |= S3C_DxEPCTL_EPDis;
|
||||
} else {
|
||||
epctl &= ~S3C_DxEPCTL_Stall;
|
||||
xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
|
||||
if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
|
||||
xfertype == S3C_DxEPCTL_EPType_Intterupt)
|
||||
epctl |= S3C_DxEPCTL_SetD0PID;
|
||||
}
|
||||
|
||||
writel(epctl, hs->regs + epreg);
|
||||
|
||||
|
|
@ -2451,8 +2500,13 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
|
||||
if (value)
|
||||
epctl |= S3C_DxEPCTL_Stall;
|
||||
else
|
||||
else {
|
||||
epctl &= ~S3C_DxEPCTL_Stall;
|
||||
xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
|
||||
if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
|
||||
xfertype == S3C_DxEPCTL_EPType_Intterupt)
|
||||
epctl |= S3C_DxEPCTL_SetD0PID;
|
||||
}
|
||||
|
||||
writel(epctl, hs->regs + epreg);
|
||||
|
||||
|
|
@ -2491,9 +2545,9 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
|||
timeout = 1000;
|
||||
do {
|
||||
grstctl = readl(hsotg->regs + S3C_GRSTCTL);
|
||||
} while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
|
||||
} while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
|
||||
|
||||
if (!(grstctl & S3C_GRSTCTL_CSftRst)) {
|
||||
if (grstctl & S3C_GRSTCTL_CSftRst) {
|
||||
dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -2510,13 +2564,10 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (grstctl & S3C_GRSTCTL_CSftRst)
|
||||
continue;
|
||||
|
||||
if (!(grstctl & S3C_GRSTCTL_AHBIdle))
|
||||
continue;
|
||||
|
||||
break; /* reset done */
|
||||
break; /* reset done */
|
||||
}
|
||||
|
||||
dev_dbg(hsotg->dev, "reset successful\n");
|
||||
|
|
@ -2588,6 +2639,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
|||
|
||||
writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG);
|
||||
|
||||
/* Clear any pending OTG interrupts */
|
||||
writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
|
||||
|
||||
/* Clear any pending interrupts */
|
||||
writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
|
||||
|
||||
writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
|
||||
S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
|
||||
S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
|
||||
|
|
@ -3261,7 +3318,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
|||
hsotg->clk = clk_get(&pdev->dev, "otg");
|
||||
if (IS_ERR(hsotg->clk)) {
|
||||
dev_err(dev, "cannot get otg clock\n");
|
||||
ret = -EINVAL;
|
||||
ret = PTR_ERR(hsotg->clk);
|
||||
goto err_mem;
|
||||
}
|
||||
|
||||
|
|
|
|||
1349
drivers/usb/gadget/s3c-hsudc.c
Normal file
1349
drivers/usb/gadget/s3c-hsudc.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -708,13 +708,14 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t rc = count;
|
||||
ssize_t rc;
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
unsigned long ro;
|
||||
unsigned ro;
|
||||
|
||||
if (strict_strtoul(buf, 2, &ro))
|
||||
return -EINVAL;
|
||||
rc = kstrtouint(buf, 2, &ro);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Allow the write-enable status to change only while the
|
||||
|
|
@ -728,6 +729,7 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
|||
curlun->ro = ro;
|
||||
curlun->initially_ro = ro;
|
||||
LDBG(curlun, "read-only status set to %d\n", curlun->ro);
|
||||
rc = count;
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
|
|
@ -738,10 +740,12 @@ static ssize_t fsg_store_nofua(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
unsigned long nofua;
|
||||
unsigned nofua;
|
||||
int ret;
|
||||
|
||||
if (strict_strtoul(buf, 2, &nofua))
|
||||
return -EINVAL;
|
||||
ret = kstrtouint(buf, 2, &nofua);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Sync data when switching from async mode to sync */
|
||||
if (!nofua && curlun->nofua)
|
||||
|
|
|
|||
|
|
@ -106,13 +106,13 @@ config USB_EHCI_BIG_ENDIAN_MMIO
|
|||
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
|
||||
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
|
||||
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
|
||||
PMC_MSP)
|
||||
PMC_MSP || SPARC_LEON)
|
||||
default y
|
||||
|
||||
config USB_EHCI_BIG_ENDIAN_DESC
|
||||
bool
|
||||
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
|
||||
PPC_MPC512x || PMC_MSP)
|
||||
PPC_MPC512x || PMC_MSP || SPARC_LEON)
|
||||
default y
|
||||
|
||||
config XPS_USB_HCD_XILINX
|
||||
|
|
@ -188,6 +188,12 @@ config USB_EHCI_SH
|
|||
Enables support for the on-chip EHCI controller on the SuperH.
|
||||
If you use the PCI EHCI controller, this option is not necessary.
|
||||
|
||||
config USB_EHCI_S5P
|
||||
boolean "S5P EHCI support"
|
||||
depends on USB_EHCI_HCD && PLAT_S5P
|
||||
help
|
||||
Enable support for the S5P SOC's on-chip EHCI controller.
|
||||
|
||||
config USB_W90X900_EHCI
|
||||
bool "W90X900(W90P910) EHCI support"
|
||||
depends on USB_EHCI_HCD && ARCH_W90X900
|
||||
|
|
@ -202,6 +208,15 @@ config USB_CNS3XXX_EHCI
|
|||
It is needed for high-speed (480Mbit/sec) USB 2.0 device
|
||||
support.
|
||||
|
||||
config USB_EHCI_ATH79
|
||||
bool "EHCI support for AR7XXX/AR9XXX SoCs"
|
||||
depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X)
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
default y
|
||||
---help---
|
||||
Enables support for the built-in EHCI controller present
|
||||
on the Atheros AR7XXX/AR9XXX SoCs.
|
||||
|
||||
config USB_OXU210HP_HCD
|
||||
tristate "OXU210HP HCD support"
|
||||
depends on USB
|
||||
|
|
@ -287,6 +302,14 @@ config USB_OHCI_HCD_OMAP3
|
|||
Enables support for the on-chip OHCI controller on
|
||||
OMAP3 and later chips.
|
||||
|
||||
config USB_OHCI_ATH79
|
||||
bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs"
|
||||
depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
|
||||
default y
|
||||
help
|
||||
Enables support for the built-in OHCI controller present on the
|
||||
Atheros AR71XX/AR7240 SoCs.
|
||||
|
||||
config USB_OHCI_HCD_PPC_SOC
|
||||
bool "OHCI support for on-chip PPC USB controller"
|
||||
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
|
||||
|
|
@ -373,7 +396,7 @@ config USB_OHCI_LITTLE_ENDIAN
|
|||
|
||||
config USB_UHCI_HCD
|
||||
tristate "UHCI HCD (most Intel and VIA) support"
|
||||
depends on USB && PCI
|
||||
depends on USB && (PCI || SPARC_LEON)
|
||||
---help---
|
||||
The Universal Host Controller Interface is a standard by Intel for
|
||||
accessing the USB hardware in the PC (which is also called the USB
|
||||
|
|
@ -382,11 +405,27 @@ config USB_UHCI_HCD
|
|||
with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
|
||||
i810, i820) conform to this standard. Also all VIA PCI chipsets
|
||||
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
|
||||
133). If unsure, say Y.
|
||||
133) and LEON/GRLIB SoCs with the GRUSBHC controller.
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called uhci-hcd.
|
||||
|
||||
config USB_UHCI_SUPPORT_NON_PCI_HC
|
||||
bool
|
||||
depends on USB_UHCI_HCD
|
||||
default y if SPARC_LEON
|
||||
|
||||
config USB_UHCI_BIG_ENDIAN_MMIO
|
||||
bool
|
||||
depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
|
||||
default y
|
||||
|
||||
config USB_UHCI_BIG_ENDIAN_DESC
|
||||
bool
|
||||
depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
|
||||
default y
|
||||
|
||||
config USB_FHCI_HCD
|
||||
tristate "Freescale QE USB Host Controller support"
|
||||
depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE
|
||||
|
|
@ -444,6 +483,16 @@ config USB_SL811_HCD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called sl811-hcd.
|
||||
|
||||
config USB_SL811_HCD_ISO
|
||||
bool "partial ISO support"
|
||||
depends on USB_SL811_HCD
|
||||
help
|
||||
The driver doesn't support iso_frame_desc (yet), but for some simple
|
||||
devices that just queue one ISO frame per URB, then ISO transfers
|
||||
"should" work using the normal urb status fields.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config USB_SL811_CS
|
||||
tristate "CF/PCMCIA support for SL811HS HCD"
|
||||
depends on USB_SL811_HCD && PCMCIA
|
||||
|
|
|
|||
202
drivers/usb/host/ehci-ath79.c
Normal file
202
drivers/usb/host/ehci-ath79.c
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
* Copyright (C) 2007 Atheros Communications, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
enum {
|
||||
EHCI_ATH79_IP_V1 = 0,
|
||||
EHCI_ATH79_IP_V2,
|
||||
};
|
||||
|
||||
static const struct platform_device_id ehci_ath79_id_table[] = {
|
||||
{
|
||||
.name = "ar71xx-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V1,
|
||||
},
|
||||
{
|
||||
.name = "ar724x-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V2,
|
||||
},
|
||||
{
|
||||
.name = "ar913x-ehci",
|
||||
.driver_data = EHCI_ATH79_IP_V2,
|
||||
},
|
||||
{
|
||||
/* terminating entry */
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
|
||||
|
||||
static int ehci_ath79_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct platform_device *pdev = to_platform_device(hcd->self.controller);
|
||||
const struct platform_device_id *id;
|
||||
int hclength;
|
||||
int ret;
|
||||
|
||||
id = platform_get_device_id(pdev);
|
||||
if (!id) {
|
||||
dev_err(hcd->self.controller, "missing device id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
switch (id->driver_data) {
|
||||
case EHCI_ATH79_IP_V1:
|
||||
ehci->has_synopsys_hc_bug = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + hclength;
|
||||
break;
|
||||
|
||||
case EHCI_ATH79_IP_V2:
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 + hclength;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ret = ehci_init(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_ath79_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Atheros built-in EHCI controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
.reset = ehci_ath79_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int ehci_ath79_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no IRQ specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no base address specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
ret = -EBUSY;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
ret = -EFAULT;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (ret)
|
||||
goto err_iounmap;
|
||||
|
||||
return 0;
|
||||
|
||||
err_iounmap:
|
||||
iounmap(hcd->regs);
|
||||
|
||||
err_release_region:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ehci_ath79_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ehci_ath79_driver = {
|
||||
.probe = ehci_ath79_probe,
|
||||
.remove = ehci_ath79_remove,
|
||||
.id_table = ehci_ath79_id_table,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ath79-ehci",
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
|
||||
|
|
@ -56,7 +56,7 @@ static int ehci_atmel_setup(struct usb_hcd *hcd)
|
|||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
|
|
@ -215,10 +216,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
|||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
return 0;
|
||||
rc = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
|
@ -233,13 +231,13 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
|||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
au1xxx_stop_ehc();
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
// ... we'd only use it to handle clock skew
|
||||
|
||||
au1xxx_stop_ehc();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 0;
|
||||
|
|
|
|||
|
|
@ -726,7 +726,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
|||
}
|
||||
|
||||
/* Capability Registers */
|
||||
i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
temp = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
|
||||
pdata->regs = hcd->regs;
|
||||
|
||||
if (pdata->power_budget)
|
||||
hcd->power_budget = pdata->power_budget;
|
||||
|
||||
/*
|
||||
* do platform specific init: check the clock, grab/config pins, etc.
|
||||
*/
|
||||
|
|
@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->transceiver = otg_get_transceiver();
|
||||
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
|
||||
hcd, ehci, ehci->transceiver);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
retval = otg_set_host(ehci->transceiver,
|
||||
&ehci_to_hcd(ehci)->self);
|
||||
if (retval) {
|
||||
if (ehci->transceiver)
|
||||
put_device(ehci->transceiver->dev);
|
||||
goto err4;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "can't find transceiver\n");
|
||||
retval = -ENODEV;
|
||||
goto err4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
|
|
@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
|
|||
struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
otg_set_host(ehci->transceiver, NULL);
|
||||
put_device(ehci->transceiver->dev);
|
||||
}
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
|
|
@ -291,7 +324,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
@ -328,6 +361,149 @@ struct ehci_fsl {
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
#ifdef DEBUG
|
||||
u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
mode &= USBMODE_CM_MASK;
|
||||
tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d "
|
||||
"mode=%d usbcmd %08x\n", pdata->suspended,
|
||||
pdata->already_suspended, mode, tmp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the controller is already suspended, then this must be a
|
||||
* PM suspend. Remember this fact, so that we will leave the
|
||||
* controller suspended at PM resume time.
|
||||
*/
|
||||
if (pdata->suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "suspending...\n");
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
dev->power.power_state = PMSG_SUSPEND;
|
||||
|
||||
/* ignore non-host interrupts */
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* stop the controller */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp &= ~CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
/* save EHCI registers */
|
||||
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
|
||||
pdata->pm_command &= ~CMD_RUN;
|
||||
pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
|
||||
pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
|
||||
pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
|
||||
pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
|
||||
pdata->pm_configured_flag =
|
||||
ehci_readl(ehci, &ehci->regs->configured_flag);
|
||||
pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
pdata->pm_usbgenctrl = ehci_readl(ehci,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
|
||||
/* clear the W1C bits */
|
||||
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
|
||||
|
||||
pdata->suspended = 1;
|
||||
|
||||
/* clear PP to cut power to the port */
|
||||
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||
tmp &= ~PORT_POWER;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct fsl_usb2_platform_data *pdata = dev->platform_data;
|
||||
u32 tmp;
|
||||
|
||||
dev_dbg(dev, "suspend=%d already_suspended=%d\n",
|
||||
pdata->suspended, pdata->already_suspended);
|
||||
|
||||
/*
|
||||
* If the controller was already suspended at suspend time,
|
||||
* then don't resume it now.
|
||||
*/
|
||||
if (pdata->already_suspended) {
|
||||
dev_dbg(dev, "already suspended, leaving early\n");
|
||||
pdata->already_suspended = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pdata->suspended) {
|
||||
dev_dbg(dev, "not suspended, leaving early\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdata->suspended = 0;
|
||||
|
||||
dev_dbg(dev, "resuming...\n");
|
||||
|
||||
/* set host mode */
|
||||
tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
|
||||
ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
|
||||
|
||||
ehci_writel(ehci, pdata->pm_usbgenctrl,
|
||||
hcd->regs + FSL_SOC_USB_USBGENCTRL);
|
||||
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
|
||||
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
|
||||
|
||||
/* restore EHCI registers */
|
||||
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
|
||||
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
|
||||
ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
|
||||
ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
|
||||
ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
|
||||
ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
|
||||
ehci_writel(ehci, pdata->pm_configured_flag,
|
||||
&ehci->regs->configured_flag);
|
||||
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
dev->power.power_state = PMSG_ON;
|
||||
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
tmp |= CMD_RUN;
|
||||
ehci_writel(ehci, tmp, &ehci->regs->command);
|
||||
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PPC_MPC512x */
|
||||
|
||||
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
|
@ -341,6 +517,11 @@ static int ehci_fsl_drv_suspend(struct device *dev)
|
|||
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_suspend(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
|
||||
device_may_wakeup(dev));
|
||||
if (!fsl_deep_sleep())
|
||||
|
|
@ -357,6 +538,11 @@ static int ehci_fsl_drv_resume(struct device *dev)
|
|||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
return ehci_fsl_mpc512x_drv_resume(dev);
|
||||
}
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!fsl_deep_sleep())
|
||||
return 0;
|
||||
|
|
@ -391,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = {
|
|||
#define EHCI_FSL_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
u32 status;
|
||||
|
||||
if (!port)
|
||||
return -EINVAL;
|
||||
|
||||
port--;
|
||||
|
||||
/* start port reset before HNP protocol time out */
|
||||
status = readl(&ehci->regs->port_status[port]);
|
||||
if (!(status & PORT_CONNECT))
|
||||
return -ENODEV;
|
||||
|
||||
/* khubd will finish the reset later */
|
||||
if (ehci_is_TDI(ehci)) {
|
||||
writel(PORT_RESET |
|
||||
(status & ~(PORT_CSC | PORT_PEC | PORT_OCC)),
|
||||
&ehci->regs->port_status[port]);
|
||||
} else {
|
||||
writel(PORT_RESET, &ehci->regs->port_status[port]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ehci_start_port_reset NULL
|
||||
#endif /* CONFIG_USB_OTG */
|
||||
|
||||
|
||||
static const struct hc_driver ehci_fsl_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Freescale On-Chip EHCI Host Controller",
|
||||
|
|
@ -430,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
|
|||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.start_port_reset = ehci_start_port_reset,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
#define PORT_PTS_SERIAL (3<<30)
|
||||
#define PORT_PTS_PTW (1<<28)
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
|
||||
#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
|
||||
#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
|
||||
|
||||
#define FSL_SOC_USB_USBGENCTRL 0x200
|
||||
#define USBGENCTRL_PPP (1 << 3)
|
||||
|
|
|
|||
242
drivers/usb/host/ehci-grlib.c
Normal file
242
drivers/usb/host/ehci-grlib.c
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
|
||||
*
|
||||
* GRUSBHC is typically found on LEON/GRLIB SoCs
|
||||
*
|
||||
* (c) Jan Andersson <jan@gaisler.com>
|
||||
*
|
||||
* Based on ehci-ppc-of.c which is:
|
||||
* (c) Valentine Barshak <vbarshak@ru.mvista.com>
|
||||
* and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
|
||||
* and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_grlib_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
return ehci_reset(ehci);
|
||||
}
|
||||
|
||||
|
||||
static const struct hc_driver ehci_grlib_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "GRLIB GRUSBHC EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_grlib_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
#endif
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
|
||||
static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
|
||||
{
|
||||
struct device_node *dn = op->dev.of_node;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci = NULL;
|
||||
struct resource res;
|
||||
u32 hc_capbase;
|
||||
int irq;
|
||||
int rv;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
|
||||
|
||||
rv = of_address_to_resource(dn, 0, &res);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* usb_create_hcd requires dma_mask != NULL */
|
||||
op->dev.dma_mask = &op->dev.coherent_dma_mask;
|
||||
hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
|
||||
"GRUSBHC EHCI USB");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = res.start;
|
||||
hcd->rsrc_len = res.end - res.start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
|
||||
rv = -EBUSY;
|
||||
goto err_rmr;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(dn, 0);
|
||||
if (irq == NO_IRQ) {
|
||||
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
|
||||
rv = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
|
||||
rv = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
/* determine endianness of this implementation */
|
||||
hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
|
||||
if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
|
||||
ehci->big_endian_mmio = 1;
|
||||
ehci->big_endian_desc = 1;
|
||||
ehci->big_endian_capbase = 1;
|
||||
}
|
||||
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv)
|
||||
goto err_ehci;
|
||||
|
||||
return 0;
|
||||
|
||||
err_ehci:
|
||||
iounmap(hcd->regs);
|
||||
err_ioremap:
|
||||
irq_dispose_mapping(irq);
|
||||
err_irq:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_rmr:
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int ehci_hcd_grlib_remove(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
dev_set_drvdata(&op->dev, NULL);
|
||||
|
||||
dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
irq_dispose_mapping(hcd->irq);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ehci_hcd_grlib_shutdown(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id ehci_hcd_grlib_of_match[] = {
|
||||
{
|
||||
.name = "GAISLER_EHCI",
|
||||
},
|
||||
{
|
||||
.name = "01_026",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
|
||||
|
||||
|
||||
static struct platform_driver ehci_grlib_driver = {
|
||||
.probe = ehci_hcd_grlib_probe,
|
||||
.remove = ehci_hcd_grlib_remove,
|
||||
.shutdown = ehci_hcd_grlib_shutdown,
|
||||
.driver = {
|
||||
.name = "grlib-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ehci_hcd_grlib_of_match,
|
||||
},
|
||||
};
|
||||
|
|
@ -739,7 +739,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
|||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
ehci->last_periodic_enable = ktime_get_real();
|
||||
|
||||
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci_info (ehci,
|
||||
"USB %x.%x started, EHCI %x.%02x%s\n",
|
||||
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
|
||||
|
|
@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||
goto dead;
|
||||
}
|
||||
|
||||
/* Shared IRQ? */
|
||||
masked_status = status & INTR_MASK;
|
||||
if (!masked_status) { /* irq sharing? */
|
||||
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||
spin_unlock(&ehci->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
|
@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||
dead:
|
||||
ehci_reset(ehci);
|
||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||
usb_hc_died(hcd);
|
||||
/* generic layer kills/unlinks all urbs, then
|
||||
* uses ehci_stop to clean up the rest
|
||||
*/
|
||||
|
|
@ -1265,6 +1267,21 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER tegra_ehci_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_S5P
|
||||
#include "ehci-s5p.c"
|
||||
#define PLATFORM_DRIVER s5p_ehci_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_ATH79
|
||||
#include "ehci-ath79.c"
|
||||
#define PLATFORM_DRIVER ehci_ath79_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARC_LEON
|
||||
#include "ehci-grlib.c"
|
||||
#define PLATFORM_DRIVER ehci_grlib_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
|
||||
|
||||
|
|
@ -127,7 +128,7 @@ static int ehci_port_change(struct ehci_hcd *ehci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
bool suspending, bool do_wakeup)
|
||||
{
|
||||
int port;
|
||||
|
|
@ -801,6 +802,13 @@ static int ehci_hub_control (
|
|||
goto error;
|
||||
if (ehci->no_selective_suspend)
|
||||
break;
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if ((hcd->self.otg_port == (wIndex + 1))
|
||||
&& hcd->self.b_hnp_enable) {
|
||||
otg_start_hnp(ehci->transceiver);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (!(temp & PORT_SUSPEND))
|
||||
break;
|
||||
if ((temp & PORT_PE) == 0)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100
|
||||
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = USB_CAPLENGTH;
|
||||
ehci->regs = USB_CAPLENGTH +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* set up the PORTSCx register */
|
||||
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
|||
/* we know this is the memory we want, no need to ioremap again */
|
||||
omap_ehci->caps = hcd->regs;
|
||||
omap_ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(readl(&omap_ehci->caps->hc_capbase));
|
||||
+ HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(omap_ehci, "reset");
|
||||
dbg_hcc_params(omap_ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
|
|||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
|
|||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
|||
ehci->big_endian_mmio = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -826,6 +826,7 @@ qh_make (
|
|||
is_input, 0,
|
||||
hb_mult(maxp) * max_packet(maxp)));
|
||||
qh->start = NO_FRAME;
|
||||
qh->stamp = ehci->periodic_stamp;
|
||||
|
||||
if (urb->dev->speed == USB_SPEED_HIGH) {
|
||||
qh->c_usecs = 0;
|
||||
|
|
@ -1183,6 +1184,10 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
|||
ehci->reclaim = NULL;
|
||||
start_unlink_async (ehci, next);
|
||||
}
|
||||
|
||||
if (ehci->has_synopsys_hc_bug)
|
||||
ehci_writel(ehci, (u32) ehci->async->qh_dma,
|
||||
&ehci->regs->async_next);
|
||||
}
|
||||
|
||||
/* makes sure the async qh will become idle */
|
||||
|
|
|
|||
202
drivers/usb/host/ehci-s5p.c
Normal file
202
drivers/usb/host/ehci-s5p.c
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* SAMSUNG S5P USB HOST EHCI Controller
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics Co.Ltd
|
||||
* Author: Jingoo Han <jg1.han@samsung.com>
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <mach/regs-pmu.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/ehci.h>
|
||||
#include <plat/usb-phy.h>
|
||||
|
||||
struct s5p_ehci_hcd {
|
||||
struct device *dev;
|
||||
struct usb_hcd *hcd;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static const struct hc_driver s5p_ehci_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "S5P EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
.reset = ehci_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_platdata *pdata;
|
||||
struct s5p_ehci_hcd *s5p_ehci;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int err;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
|
||||
if (!s5p_ehci)
|
||||
return -ENOMEM;
|
||||
|
||||
s5p_ehci->dev = &pdev->dev;
|
||||
|
||||
hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
dev_err(&pdev->dev, "Unable to create HCD\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_hcd;
|
||||
}
|
||||
|
||||
s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
|
||||
|
||||
if (IS_ERR(s5p_ehci->clk)) {
|
||||
dev_err(&pdev->dev, "Failed to get usbhost clock\n");
|
||||
err = PTR_ERR(s5p_ehci->clk);
|
||||
goto fail_clk;
|
||||
}
|
||||
|
||||
err = clk_enable(s5p_ehci->clk);
|
||||
if (err)
|
||||
goto fail_clken;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Failed to get I/O memory\n");
|
||||
err = -ENXIO;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = ioremap(res->start, resource_size(res));
|
||||
if (!hcd->regs) {
|
||||
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ\n");
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pdata->phy_init)
|
||||
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, s5p_ehci);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
iounmap(hcd->regs);
|
||||
fail_io:
|
||||
clk_disable(s5p_ehci->clk);
|
||||
fail_clken:
|
||||
clk_put(s5p_ehci->clk);
|
||||
fail_clk:
|
||||
usb_put_hcd(hcd);
|
||||
fail_hcd:
|
||||
kfree(s5p_ehci);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit s5p_ehci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
|
||||
clk_disable(s5p_ehci->clk);
|
||||
clk_put(s5p_ehci->clk);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
kfree(s5p_ehci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s5p_ehci_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
static struct platform_driver s5p_ehci_driver = {
|
||||
.probe = s5p_ehci_probe,
|
||||
.remove = __devexit_p(s5p_ehci_remove),
|
||||
.shutdown = s5p_ehci_shutdown,
|
||||
.driver = {
|
||||
.name = "s5p-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:s5p-ehci");
|
||||
|
|
@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
|
|||
*/
|
||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||
STS_PSS, 0, 9 * 125);
|
||||
if (status)
|
||||
if (status) {
|
||||
usb_hc_died(ehci_to_hcd(ehci));
|
||||
return status;
|
||||
}
|
||||
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
|
|
@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
|
|||
*/
|
||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||
STS_PSS, STS_PSS, 9 * 125);
|
||||
if (status)
|
||||
if (status) {
|
||||
usb_hc_died(ehci_to_hcd(ehci));
|
||||
return status;
|
||||
}
|
||||
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
|
|
@ -2287,6 +2291,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
}
|
||||
clock &= mod - 1;
|
||||
clock_frame = clock >> 3;
|
||||
++ehci->periodic_stamp;
|
||||
|
||||
for (;;) {
|
||||
union ehci_shadow q, *q_p;
|
||||
|
|
@ -2315,10 +2320,14 @@ restart:
|
|||
temp.qh = qh_get (q.qh);
|
||||
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
|
||||
q = q.qh->qh_next;
|
||||
modified = qh_completions (ehci, temp.qh);
|
||||
if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
temp.qh->needs_rescan))
|
||||
intr_deschedule (ehci, temp.qh);
|
||||
if (temp.qh->stamp != ehci->periodic_stamp) {
|
||||
modified = qh_completions(ehci, temp.qh);
|
||||
if (!modified)
|
||||
temp.qh->stamp = ehci->periodic_stamp;
|
||||
if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
temp.qh->needs_rescan))
|
||||
intr_deschedule(ehci, temp.qh);
|
||||
}
|
||||
qh_put (temp.qh);
|
||||
break;
|
||||
case Q_TYPE_FSTN:
|
||||
|
|
@ -2460,6 +2469,7 @@ restart:
|
|||
if (ehci->clock_frame != clock_frame) {
|
||||
free_cached_lists(ehci);
|
||||
ehci->clock_frame = clock_frame;
|
||||
++ehci->periodic_stamp;
|
||||
}
|
||||
} else {
|
||||
now_uframe++;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
|
|||
int ret;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
|
|||
|
||||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,71 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
|
|||
clk_disable(tegra->emc_clk);
|
||||
}
|
||||
|
||||
static int tegra_ehci_internal_port_reset(
|
||||
struct ehci_hcd *ehci,
|
||||
u32 __iomem *portsc_reg
|
||||
)
|
||||
{
|
||||
u32 temp;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
int i, tries;
|
||||
u32 saved_usbintr;
|
||||
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
/* disable USB interrupt */
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
/*
|
||||
* Here we have to do Port Reset at most twice for
|
||||
* Port Enable bit to be set.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
temp = ehci_readl(ehci, portsc_reg);
|
||||
temp |= PORT_RESET;
|
||||
ehci_writel(ehci, temp, portsc_reg);
|
||||
mdelay(10);
|
||||
temp &= ~PORT_RESET;
|
||||
ehci_writel(ehci, temp, portsc_reg);
|
||||
mdelay(1);
|
||||
tries = 100;
|
||||
do {
|
||||
mdelay(1);
|
||||
/*
|
||||
* Up to this point, Port Enable bit is
|
||||
* expected to be set after 2 ms waiting.
|
||||
* USB1 usually takes extra 45 ms, for safety,
|
||||
* we take 100 ms as timeout.
|
||||
*/
|
||||
temp = ehci_readl(ehci, portsc_reg);
|
||||
} while (!(temp & PORT_PE) && tries--);
|
||||
if (temp & PORT_PE)
|
||||
break;
|
||||
}
|
||||
if (i == 2)
|
||||
retval = -ETIMEDOUT;
|
||||
|
||||
/*
|
||||
* Clear Connect Status Change bit if it's set.
|
||||
* We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
|
||||
*/
|
||||
if (temp & PORT_CSC)
|
||||
ehci_writel(ehci, PORT_CSC, portsc_reg);
|
||||
|
||||
/*
|
||||
* Write to clear any interrupt status bits that might be set
|
||||
* during port reset.
|
||||
*/
|
||||
temp = ehci_readl(ehci, &ehci->regs->status);
|
||||
ehci_writel(ehci, temp, &ehci->regs->status);
|
||||
|
||||
/* restore original interrupt enable bits */
|
||||
ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int tegra_ehci_hub_control(
|
||||
struct usb_hcd *hcd,
|
||||
u16 typeReq,
|
||||
|
|
@ -121,6 +186,13 @@ static int tegra_ehci_hub_control(
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* For USB1 port we need to issue Port Reset twice internally */
|
||||
if (tegra->phy->instance == 0 &&
|
||||
(typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
return tegra_ehci_internal_port_reset(ehci, status_reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tegra host controller will time the resume operation to clear the bit
|
||||
* when the port control state switches to HS or FS Idle. This behavior
|
||||
|
|
@ -328,7 +400,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
|
|||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
|
|||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
|
|||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* enable PHY 0,1,the regs only apply to w90p910
|
||||
* 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
|
|||
*/
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
|
|||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
|
|
@ -128,12 +129,14 @@ struct ehci_hcd { /* one per controller */
|
|||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||
unsigned big_endian_mmio:1;
|
||||
unsigned big_endian_desc:1;
|
||||
unsigned big_endian_capbase:1;
|
||||
unsigned has_amcc_usb23:1;
|
||||
unsigned need_io_watchdog:1;
|
||||
unsigned broken_periodic:1;
|
||||
unsigned amd_pll_fix:1;
|
||||
unsigned fs_i_thresh:1; /* Intel iso scheduling */
|
||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
|
|
@ -160,6 +163,10 @@ struct ehci_hcd { /* one per controller */
|
|||
#ifdef DEBUG
|
||||
struct dentry *debug_dir;
|
||||
#endif
|
||||
/*
|
||||
* OTG controllers and transceivers need software interaction
|
||||
*/
|
||||
struct otg_transceiver *transceiver;
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
|
|
@ -600,12 +607,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
|||
* This attempts to support either format at compile time without a
|
||||
* runtime penalty, or both formats with the additional overhead
|
||||
* of checking a flag bit.
|
||||
*
|
||||
* ehci_big_endian_capbase is a special quirk for controllers that
|
||||
* implement the HC capability registers as separate registers and not
|
||||
* as fields of a 32-bit register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
|
||||
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
|
||||
#else
|
||||
#define ehci_big_endian_mmio(e) 0
|
||||
#define ehci_big_endian_capbase(e) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
|
|||
/* IRQ's are off, we do no DMA,
|
||||
perfectly ready to die ... */
|
||||
hcd->state = HC_STATE_HALT;
|
||||
usb_hc_died(hcd);
|
||||
ret = IRQ_HANDLED;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -49,10 +49,9 @@ void deinit_kmem_cache(void);
|
|||
#define SW_RESET_RESET_ALL (1 << 0)
|
||||
|
||||
#define HC_BUFFER_STATUS_REG 0x334
|
||||
#define ATL_BUFFER 0x1
|
||||
#define INT_BUFFER 0x2
|
||||
#define ISO_BUFFER 0x4
|
||||
#define BUFFER_MAP 0x7
|
||||
#define ISO_BUF_FILL (1 << 2)
|
||||
#define INT_BUF_FILL (1 << 1)
|
||||
#define ATL_BUF_FILL (1 << 0)
|
||||
|
||||
#define HC_MEMORY_REG 0x33c
|
||||
#define ISP_BANK(x) ((x) << 16)
|
||||
|
|
@ -68,14 +67,13 @@ void deinit_kmem_cache(void);
|
|||
#define HC_INTERRUPT_REG 0x310
|
||||
|
||||
#define HC_INTERRUPT_ENABLE 0x314
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_INTL_INT | HC_SOT_INT | HC_EOT_INT)
|
||||
|
||||
#define HC_ISO_INT (1 << 9)
|
||||
#define HC_ATL_INT (1 << 8)
|
||||
#define HC_INTL_INT (1 << 7)
|
||||
#define HC_EOT_INT (1 << 3)
|
||||
#define HC_SOT_INT (1 << 1)
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
|
||||
|
||||
#define HC_ISO_IRQ_MASK_OR_REG 0x318
|
||||
#define HC_INT_IRQ_MASK_OR_REG 0x31C
|
||||
|
|
@ -106,7 +104,7 @@ struct ptd {
|
|||
#define ATL_PTD_OFFSET 0x0c00
|
||||
#define PAYLOAD_OFFSET 0x1000
|
||||
|
||||
struct inter_packet_info {
|
||||
struct slotinfo {
|
||||
struct isp1760_qh *qh;
|
||||
struct isp1760_qtd *qtd;
|
||||
};
|
||||
|
|
@ -156,54 +154,52 @@ struct memory_chunk {
|
|||
|
||||
/* ATL */
|
||||
/* DW0 */
|
||||
#define PTD_VALID 1
|
||||
#define PTD_LENGTH(x) (((u32) x) << 3)
|
||||
#define PTD_MAXPACKET(x) (((u32) x) << 18)
|
||||
#define PTD_MULTI(x) (((u32) x) << 29)
|
||||
#define PTD_ENDPOINT(x) (((u32) x) << 31)
|
||||
#define DW0_VALID_BIT 1
|
||||
#define FROM_DW0_VALID(x) ((x) & 0x01)
|
||||
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
|
||||
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
|
||||
#define TO_DW0_MULTI(x) (((u32) x) << 29)
|
||||
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
|
||||
/* DW1 */
|
||||
#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
|
||||
#define PTD_PID_TOKEN(x) (((u32) x) << 10)
|
||||
#define PTD_TRANS_BULK ((u32) 2 << 12)
|
||||
#define PTD_TRANS_INT ((u32) 3 << 12)
|
||||
#define PTD_TRANS_SPLIT ((u32) 1 << 14)
|
||||
#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
|
||||
#define PTD_PORT_NUM(x) (((u32) x) << 18)
|
||||
#define PTD_HUB_NUM(x) (((u32) x) << 25)
|
||||
#define PTD_PING(x) (((u32) x) << 26)
|
||||
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
|
||||
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
|
||||
#define DW1_TRANS_BULK ((u32) 2 << 12)
|
||||
#define DW1_TRANS_INT ((u32) 3 << 12)
|
||||
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
|
||||
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
|
||||
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
|
||||
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
|
||||
/* DW2 */
|
||||
#define PTD_RL_CNT(x) (((u32) x) << 25)
|
||||
#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
|
||||
#define BASE_ADDR 0x1000
|
||||
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
|
||||
#define TO_DW2_RL(x) ((x) << 25)
|
||||
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
|
||||
/* DW3 */
|
||||
#define PTD_CERR(x) (((u32) x) << 23)
|
||||
#define PTD_NAC_CNT(x) (((u32) x) << 19)
|
||||
#define PTD_ACTIVE ((u32) 1 << 31)
|
||||
#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
|
||||
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
|
||||
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
|
||||
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
|
||||
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
|
||||
#define TO_DW3_CERR(x) ((x) << 23)
|
||||
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
|
||||
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
|
||||
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
|
||||
#define TO_DW3_PING(x) ((x) << 26)
|
||||
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
|
||||
#define DW3_ERROR_BIT (1 << 28)
|
||||
#define DW3_QTD_ACTIVE (1 << 31)
|
||||
#define DW3_BABBLE_BIT (1 << 29)
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define DW3_ACTIVE_BIT (1 << 31)
|
||||
|
||||
#define INT_UNDERRUN (1 << 2)
|
||||
#define INT_BABBLE (1 << 1)
|
||||
#define INT_EXACT (1 << 0)
|
||||
|
||||
#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
|
||||
#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
|
||||
#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
|
||||
|
||||
#define SETUP_PID (2)
|
||||
#define IN_PID (1)
|
||||
#define OUT_PID (0)
|
||||
#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
|
||||
|
||||
#define DATA_TOGGLE (1 << 31)
|
||||
#define GET_DATA_TOGGLE(x) ((x) >> 31)
|
||||
|
||||
/* Errata 1 */
|
||||
#define RL_COUNTER (0)
|
||||
#define NAK_COUNTER (0)
|
||||
#define ERR_COUNTER (2)
|
||||
|
||||
#endif
|
||||
#endif /* _ISP1760_HCD_H_ */
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@
|
|||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2010 Cavium Networks
|
||||
* Copyright (C) 2010, 2011 Cavium Networks
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include <asm/octeon/octeon.h>
|
||||
#include <asm/octeon/cvmx-uctlx-defs.h>
|
||||
|
||||
static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
|
||||
|
||||
static int octeon2_usb_clock_start_cnt;
|
||||
|
||||
void octeon2_usb_clocks_start(void)
|
||||
{
|
||||
|
|
@ -26,8 +27,12 @@ void octeon2_usb_clocks_start(void)
|
|||
int i;
|
||||
unsigned long io_clk_64_to_ns;
|
||||
|
||||
if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1)
|
||||
return;
|
||||
|
||||
mutex_lock(&octeon2_usb_clocks_mutex);
|
||||
|
||||
octeon2_usb_clock_start_cnt++;
|
||||
if (octeon2_usb_clock_start_cnt != 1)
|
||||
goto exit;
|
||||
|
||||
io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
|
||||
|
||||
|
|
@ -43,6 +48,13 @@ void octeon2_usb_clocks_start(void)
|
|||
|
||||
/* Step 3: Configure the reference clock, PHY, and HCLK */
|
||||
clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
|
||||
|
||||
/*
|
||||
* If the UCTL looks like it has already been started, skip
|
||||
* the initialization, otherwise bus errors are obtained.
|
||||
*/
|
||||
if (clk_rst_ctl.s.hrst)
|
||||
goto end_clock;
|
||||
/* 3a */
|
||||
clk_rst_ctl.s.p_por = 1;
|
||||
clk_rst_ctl.s.hrst = 0;
|
||||
|
|
@ -158,28 +170,31 @@ void octeon2_usb_clocks_start(void)
|
|||
clk_rst_ctl.s.hrst = 1;
|
||||
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
|
||||
|
||||
end_clock:
|
||||
/* Now we can set some other registers. */
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
port_ctl_status.u64 =
|
||||
cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
|
||||
/* Set txvreftune to 15 to obtain complient 'eye' diagram. */
|
||||
/* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
|
||||
port_ctl_status.s.txvreftune = 15;
|
||||
port_ctl_status.s.txrisetune = 1;
|
||||
port_ctl_status.s.txpreemphasistune = 1;
|
||||
cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
|
||||
port_ctl_status.u64);
|
||||
}
|
||||
|
||||
/* Set uSOF cycle period to 60,000 bits. */
|
||||
cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
|
||||
exit:
|
||||
mutex_unlock(&octeon2_usb_clocks_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(octeon2_usb_clocks_start);
|
||||
|
||||
void octeon2_usb_clocks_stop(void)
|
||||
{
|
||||
union cvmx_uctlx_if_ena if_ena;
|
||||
|
||||
if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0)
|
||||
return;
|
||||
|
||||
if_ena.u64 = 0;
|
||||
if_ena.s.en = 0;
|
||||
cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
|
||||
mutex_lock(&octeon2_usb_clocks_mutex);
|
||||
octeon2_usb_clock_start_cnt--;
|
||||
mutex_unlock(&octeon2_usb_clocks_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(octeon2_usb_clocks_stop);
|
||||
|
|
|
|||
151
drivers/usb/host/ohci-ath79.c
Normal file
151
drivers/usb/host/ohci-ath79.c
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* Bus Glue for Atheros AR71XX/AR724X built-in OHCI controller.
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
* Copyright (C) 2007 Atheros Communications, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int __devinit ohci_ath79_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
int ret;
|
||||
|
||||
ret = ohci_init(ohci);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ohci_run(ohci);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hc_driver ohci_ath79_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Atheros built-in OHCI controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_USB11 | HCD_MEMORY,
|
||||
|
||||
.start = ohci_ath79_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ohci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
static int ohci_ath79_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no IRQ specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
hcd = usb_create_hcd(&ohci_ath79_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_dbg(&pdev->dev, "no base address specified\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
ret = -EBUSY;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
ret = -EFAULT;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
if (ret)
|
||||
goto err_stop_hcd;
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_hcd:
|
||||
iounmap(hcd->regs);
|
||||
err_release_region:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_ath79_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ohci_hcd_ath79_driver = {
|
||||
.probe = ohci_ath79_probe,
|
||||
.remove = ohci_ath79_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ath79-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ohci");
|
||||
|
|
@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
if (ints == ~(u32)0) {
|
||||
disable (ohci);
|
||||
ohci_dbg (ohci, "device removed!\n");
|
||||
usb_hc_died(hcd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
ints &= ohci_readl(ohci, ®s->intrenable);
|
||||
|
||||
/* interrupt for some other device? */
|
||||
if (ints == 0)
|
||||
if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
|
||||
return IRQ_NOTMINE;
|
||||
|
||||
if (ints & OHCI_INTR_UE) {
|
||||
|
|
@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
|||
} else {
|
||||
disable (ohci);
|
||||
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
|
||||
usb_hc_died(hcd);
|
||||
}
|
||||
|
||||
ohci_dump (ohci, 1);
|
||||
|
|
@ -1105,6 +1107,11 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_OHCI_ATH79
|
||||
#include "ohci-ath79.c"
|
||||
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && \
|
||||
!defined(PLATFORM_DRIVER) && \
|
||||
!defined(OMAP1_PLATFORM_DRIVER) && \
|
||||
|
|
|
|||
|
|
@ -181,10 +181,18 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
|
|||
*/
|
||||
static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci->flags |= OHCI_QUIRK_SHUTDOWN;
|
||||
ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
|
||||
/* Evidently nVidia fixed their later hardware; this is a guess at
|
||||
* the changeover point.
|
||||
*/
|
||||
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d
|
||||
|
||||
if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) {
|
||||
ohci->flags |= OHCI_QUIRK_SHUTDOWN;
|
||||
ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,8 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
|
|||
info->hcd = hcd;
|
||||
info->report_oc = s3c2410_hcd_oc;
|
||||
|
||||
if (info->enable_oc != NULL) {
|
||||
if (info->enable_oc != NULL)
|
||||
(info->enable_oc)(info, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,9 +71,8 @@ static void s3c2410_stop_hc(struct platform_device *dev)
|
|||
info->report_oc = NULL;
|
||||
info->hcd = NULL;
|
||||
|
||||
if (info->enable_oc != NULL) {
|
||||
if (info->enable_oc != NULL)
|
||||
(info->enable_oc)(info, 0);
|
||||
}
|
||||
}
|
||||
|
||||
clk_disable(clk);
|
||||
|
|
@ -88,14 +86,14 @@ static void s3c2410_stop_hc(struct platform_device *dev)
|
|||
*/
|
||||
|
||||
static int
|
||||
ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||
ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)
|
||||
{
|
||||
struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
|
||||
struct s3c2410_hcd_port *port;
|
||||
int orig;
|
||||
int portno;
|
||||
|
||||
orig = ohci_hub_status_data (hcd, buf);
|
||||
orig = ohci_hub_status_data(hcd, buf);
|
||||
|
||||
if (info == NULL)
|
||||
return orig;
|
||||
|
|
@ -145,7 +143,7 @@ static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
|
|||
* request.
|
||||
*/
|
||||
|
||||
static int ohci_s3c2410_hub_control (
|
||||
static int ohci_s3c2410_hub_control(
|
||||
struct usb_hcd *hcd,
|
||||
u16 typeReq,
|
||||
u16 wValue,
|
||||
|
|
@ -199,9 +197,8 @@ static int ohci_s3c2410_hub_control (
|
|||
dev_dbg(hcd->self.controller,
|
||||
"ClearPortFeature: OVER_CURRENT\n");
|
||||
|
||||
if (valid_port(wIndex)) {
|
||||
if (valid_port(wIndex))
|
||||
info->port[wIndex-1].oc_status = 0;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
|
|
@ -242,8 +239,11 @@ static int ohci_s3c2410_hub_control (
|
|||
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
|
||||
|
||||
if (info->enable_oc) {
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(
|
||||
HUB_CHAR_OCPM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(
|
||||
0x0008 |
|
||||
0x0001);
|
||||
}
|
||||
|
||||
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
|
||||
|
|
@ -257,13 +257,11 @@ static int ohci_s3c2410_hub_control (
|
|||
dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
|
||||
|
||||
if (valid_port(wIndex)) {
|
||||
if (info->port[wIndex-1].oc_changed) {
|
||||
if (info->port[wIndex-1].oc_changed)
|
||||
*data |= cpu_to_le32(RH_PS_OCIC);
|
||||
}
|
||||
|
||||
if (info->port[wIndex-1].oc_status) {
|
||||
if (info->port[wIndex-1].oc_status)
|
||||
*data |= cpu_to_le32(RH_PS_POCI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +319,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
|
|||
*/
|
||||
|
||||
static void
|
||||
usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
|
||||
usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
s3c2410_stop_hc(dev);
|
||||
|
|
@ -339,7 +337,7 @@ usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
|
|||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
*/
|
||||
static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
|
||||
static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = NULL;
|
||||
|
|
@ -353,7 +351,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
|
|||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = dev->resource[0].start;
|
||||
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
|
||||
hcd->rsrc_len = resource_size(&dev->resource[0]);
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
dev_err(&dev->dev, "request_mem_region failed\n");
|
||||
|
|
@ -364,14 +362,14 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
|
|||
clk = clk_get(&dev->dev, "usb-host");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&dev->dev, "cannot get usb-host clock\n");
|
||||
retval = -ENOENT;
|
||||
retval = PTR_ERR(clk);
|
||||
goto err_mem;
|
||||
}
|
||||
|
||||
usb_clk = clk_get(&dev->dev, "usb-bus-host");
|
||||
if (IS_ERR(usb_clk)) {
|
||||
dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
|
||||
retval = -ENOENT;
|
||||
retval = PTR_ERR(usb_clk);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
|
|
@ -411,17 +409,19 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
|
|||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int
|
||||
ohci_s3c2410_start (struct usb_hcd *hcd)
|
||||
ohci_s3c2410_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
int ret;
|
||||
|
||||
if ((ret = ohci_init(ohci)) < 0)
|
||||
ret = ohci_init(ohci);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = ohci_run (ohci)) < 0) {
|
||||
err ("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop (hcd);
|
||||
ret = ohci_run(ohci);
|
||||
if (ret < 0) {
|
||||
err("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -473,12 +473,12 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
|
|||
|
||||
/* device driver */
|
||||
|
||||
static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
|
||||
static int __devinit ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
|
||||
}
|
||||
|
||||
static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
|
||||
static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -488,7 +488,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver ohci_hcd_s3c2410_driver = {
|
||||
.probe = ohci_hcd_s3c2410_drv_probe,
|
||||
.remove = ohci_hcd_s3c2410_drv_remove,
|
||||
.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, */
|
||||
|
|
|
|||
|
|
@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hcd *oxu)
|
|||
status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
|
||||
if (status != 0) {
|
||||
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
||||
usb_hc_died(oxu_to_hcd(oxu));
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_hcd *oxu)
|
|||
status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
|
||||
if (status != 0) {
|
||||
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
||||
usb_hc_died(oxu_to_hcd(oxu));
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
|
|||
goto dead;
|
||||
}
|
||||
|
||||
/* Shared IRQ? */
|
||||
status &= INTR_MASK;
|
||||
if (!status) { /* irq sharing? */
|
||||
if (!status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||
spin_unlock(&oxu->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
|
@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
|
|||
dead:
|
||||
ehci_reset(oxu);
|
||||
writel(0, &oxu->regs->configured_flag);
|
||||
usb_hc_died(hcd);
|
||||
/* generic layer kills/unlinks all urbs, then
|
||||
* uses oxu_stop to clean up the rest
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include "pci-quirks.h"
|
||||
#include "xhci-ext-caps.h"
|
||||
|
||||
|
|
@ -503,14 +504,84 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
|||
iounmap(base);
|
||||
}
|
||||
|
||||
static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
|
||||
void __iomem *op_reg_base,
|
||||
u32 cap, u8 offset)
|
||||
{
|
||||
int try_handoff = 1, tried_handoff = 0;
|
||||
|
||||
/* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90
|
||||
* seconds trying the handoff on its unused controller. Skip
|
||||
* it. */
|
||||
if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
|
||||
const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
|
||||
if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
|
||||
dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
|
||||
try_handoff = 0;
|
||||
}
|
||||
|
||||
if (try_handoff && (cap & EHCI_USBLEGSUP_BIOS)) {
|
||||
dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
|
||||
|
||||
#if 0
|
||||
/* [email protected] reports that some systems need SMI forced on,
|
||||
* but that seems dubious in general (the BIOS left it off intentionally)
|
||||
* and is known to prevent some systems from booting. so we won't do this
|
||||
* unless maybe we can determine when we're on a system that needs SMI forced.
|
||||
*/
|
||||
/* BIOS workaround (?): be sure the pre-Linux code
|
||||
* receives the SMI
|
||||
*/
|
||||
pci_read_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, &val);
|
||||
pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS,
|
||||
val | EHCI_USBLEGCTLSTS_SOOE);
|
||||
#endif
|
||||
|
||||
/* some systems get upset if this semaphore is
|
||||
* set for any other reason than forcing a BIOS
|
||||
* handoff..
|
||||
*/
|
||||
pci_write_config_byte(pdev, offset + 3, 1);
|
||||
}
|
||||
|
||||
/* if boot firmware now owns EHCI, spin till it hands it over. */
|
||||
if (try_handoff) {
|
||||
int msec = 1000;
|
||||
while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
|
||||
tried_handoff = 1;
|
||||
msleep(10);
|
||||
msec -= 10;
|
||||
pci_read_config_dword(pdev, offset, &cap);
|
||||
}
|
||||
}
|
||||
|
||||
if (cap & EHCI_USBLEGSUP_BIOS) {
|
||||
/* well, possibly buggy BIOS... try to shut it down,
|
||||
* and hope nothing goes too wrong
|
||||
*/
|
||||
if (try_handoff)
|
||||
dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
|
||||
" (BIOS bug?) %08x\n", cap);
|
||||
pci_write_config_byte(pdev, offset + 2, 0);
|
||||
}
|
||||
|
||||
/* just in case, always disable EHCI SMIs */
|
||||
pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, 0);
|
||||
|
||||
/* If the BIOS ever owned the controller then we can't expect
|
||||
* any power sessions to remain intact.
|
||||
*/
|
||||
if (tried_handoff)
|
||||
writel(0, op_reg_base + EHCI_CONFIGFLAG);
|
||||
}
|
||||
|
||||
static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
|
||||
{
|
||||
int wait_time, delta;
|
||||
void __iomem *base, *op_reg_base;
|
||||
u32 hcc_params, val;
|
||||
u32 hcc_params, cap, val;
|
||||
u8 offset, cap_length;
|
||||
int count = 256/4;
|
||||
int tried_handoff = 0;
|
||||
int wait_time, delta, count = 256/4;
|
||||
|
||||
if (!mmio_resource_enabled(pdev, 0))
|
||||
return;
|
||||
|
|
@ -529,77 +600,17 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
|
|||
hcc_params = readl(base + EHCI_HCC_PARAMS);
|
||||
offset = (hcc_params >> 8) & 0xff;
|
||||
while (offset && --count) {
|
||||
u32 cap;
|
||||
int msec;
|
||||
|
||||
pci_read_config_dword(pdev, offset, &cap);
|
||||
|
||||
switch (cap & 0xff) {
|
||||
case 1: /* BIOS/SMM/... handoff support */
|
||||
if ((cap & EHCI_USBLEGSUP_BIOS)) {
|
||||
dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
|
||||
|
||||
#if 0
|
||||
/* [email protected] reports that some systems need SMI forced on,
|
||||
* but that seems dubious in general (the BIOS left it off intentionally)
|
||||
* and is known to prevent some systems from booting. so we won't do this
|
||||
* unless maybe we can determine when we're on a system that needs SMI forced.
|
||||
*/
|
||||
/* BIOS workaround (?): be sure the
|
||||
* pre-Linux code receives the SMI
|
||||
*/
|
||||
pci_read_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
&val);
|
||||
pci_write_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
val | EHCI_USBLEGCTLSTS_SOOE);
|
||||
#endif
|
||||
|
||||
/* some systems get upset if this semaphore is
|
||||
* set for any other reason than forcing a BIOS
|
||||
* handoff..
|
||||
*/
|
||||
pci_write_config_byte(pdev, offset + 3, 1);
|
||||
}
|
||||
|
||||
/* if boot firmware now owns EHCI, spin till
|
||||
* it hands it over.
|
||||
*/
|
||||
msec = 1000;
|
||||
while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
|
||||
tried_handoff = 1;
|
||||
msleep(10);
|
||||
msec -= 10;
|
||||
pci_read_config_dword(pdev, offset, &cap);
|
||||
}
|
||||
|
||||
if (cap & EHCI_USBLEGSUP_BIOS) {
|
||||
/* well, possibly buggy BIOS... try to shut
|
||||
* it down, and hope nothing goes too wrong
|
||||
*/
|
||||
dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
|
||||
" (BIOS bug?) %08x\n", cap);
|
||||
pci_write_config_byte(pdev, offset + 2, 0);
|
||||
}
|
||||
|
||||
/* just in case, always disable EHCI SMIs */
|
||||
pci_write_config_dword(pdev,
|
||||
offset + EHCI_USBLEGCTLSTS,
|
||||
0);
|
||||
|
||||
/* If the BIOS ever owned the controller then we
|
||||
* can't expect any power sessions to remain intact.
|
||||
*/
|
||||
if (tried_handoff)
|
||||
writel(0, op_reg_base + EHCI_CONFIGFLAG);
|
||||
case 1:
|
||||
ehci_bios_handoff(pdev, op_reg_base, cap, offset);
|
||||
break;
|
||||
case 0: /* illegal reserved capability */
|
||||
cap = 0;
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Illegal reserved cap, set cap=0 so we exit */
|
||||
cap = 0; /* then fallthrough... */
|
||||
default:
|
||||
dev_warn(&pdev->dev, "EHCI: unrecognized capability "
|
||||
"%02x\n", cap & 0xff);
|
||||
break;
|
||||
"%02x\n", cap & 0xff);
|
||||
}
|
||||
offset = (cap >> 8) & 0xff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,12 +72,6 @@ MODULE_ALIAS("platform:sl811-hcd");
|
|||
/* for now, use only one transfer register bank */
|
||||
#undef USE_B
|
||||
|
||||
/* this doesn't understand urb->iso_frame_desc[], but if you had a driver
|
||||
* that just queued one ISO frame per URB then iso transfers "should" work
|
||||
* using the normal urb status fields.
|
||||
*/
|
||||
#define DISABLE_ISO
|
||||
|
||||
// #define QUIRK2
|
||||
#define QUIRK3
|
||||
|
||||
|
|
@ -808,7 +802,7 @@ static int sl811h_urb_enqueue(
|
|||
int retval;
|
||||
struct usb_host_endpoint *hep = urb->ep;
|
||||
|
||||
#ifdef DISABLE_ISO
|
||||
#ifndef CONFIG_USB_SL811_HCD_ISO
|
||||
if (type == PIPE_ISOCHRONOUS)
|
||||
return -ENOSPC;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3230,8 +3230,7 @@ static int __init u132_hcd_init(void)
|
|||
mutex_init(&u132_module_lock);
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
|
||||
__DATE__);
|
||||
printk(KERN_INFO "driver %s\n", hcd_name);
|
||||
workqueue = create_singlethread_workqueue("u132");
|
||||
retval = platform_driver_register(&u132_platform_driver);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ static void lprintk(char *buf)
|
|||
}
|
||||
}
|
||||
|
||||
static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
||||
static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf,
|
||||
int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
char *spid;
|
||||
|
|
@ -47,8 +48,9 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
|||
if (len < 160)
|
||||
return 0;
|
||||
|
||||
status = td_status(td);
|
||||
out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link));
|
||||
status = td_status(uhci, td);
|
||||
out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td,
|
||||
hc32_to_cpu(uhci, td->link));
|
||||
out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
|
||||
((status >> 27) & 3),
|
||||
(status & TD_CTRL_SPD) ? "SPD " : "",
|
||||
|
|
@ -63,7 +65,7 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
|||
(status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
|
||||
status & 0x7ff);
|
||||
|
||||
token = td_token(td);
|
||||
token = td_token(uhci, td);
|
||||
switch (uhci_packetid(token)) {
|
||||
case USB_PID_SETUP:
|
||||
spid = "SETUP";
|
||||
|
|
@ -86,12 +88,13 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
|
|||
(token >> 8) & 127,
|
||||
(token & 0xff),
|
||||
spid);
|
||||
out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer));
|
||||
out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer));
|
||||
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
||||
static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp,
|
||||
char *buf, int len, int space)
|
||||
{
|
||||
char *out = buf;
|
||||
struct uhci_td *td;
|
||||
|
|
@ -130,9 +133,10 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
|||
if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
|
||||
(++i <= 10 || debug > 2)) {
|
||||
out += sprintf(out, "%*s%d: ", space + 2, "", i);
|
||||
out += uhci_show_td(td, out, len - (out - buf), 0);
|
||||
out += uhci_show_td(uhci, td, out,
|
||||
len - (out - buf), 0);
|
||||
} else {
|
||||
if (td_status(td) & TD_CTRL_ACTIVE)
|
||||
if (td_status(uhci, td) & TD_CTRL_ACTIVE)
|
||||
++nactive;
|
||||
else
|
||||
++ninactive;
|
||||
|
|
@ -151,7 +155,7 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
|||
{
|
||||
char *out = buf;
|
||||
int i, nurbs;
|
||||
__le32 element = qh_element(qh);
|
||||
__hc32 element = qh_element(qh);
|
||||
char *qtype;
|
||||
|
||||
/* Try to make sure there's enough memory */
|
||||
|
|
@ -168,7 +172,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
|||
|
||||
out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
|
||||
space, "", qh, qtype,
|
||||
le32_to_cpu(qh->link), le32_to_cpu(element));
|
||||
hc32_to_cpu(uhci, qh->link),
|
||||
hc32_to_cpu(uhci, element));
|
||||
if (qh->type == USB_ENDPOINT_XFER_ISOC)
|
||||
out += sprintf(out, "%*s period %d phase %d load %d us, "
|
||||
"frame %x desc [%p]\n",
|
||||
|
|
@ -178,22 +183,22 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
|||
out += sprintf(out, "%*s period %d phase %d load %d us\n",
|
||||
space, "", qh->period, qh->phase, qh->load);
|
||||
|
||||
if (element & UHCI_PTR_QH)
|
||||
if (element & UHCI_PTR_QH(uhci))
|
||||
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
|
||||
|
||||
if (element & UHCI_PTR_DEPTH)
|
||||
if (element & UHCI_PTR_DEPTH(uhci))
|
||||
out += sprintf(out, "%*s Depth traverse\n", space, "");
|
||||
|
||||
if (element & cpu_to_le32(8))
|
||||
if (element & cpu_to_hc32(uhci, 8))
|
||||
out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, "");
|
||||
|
||||
if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
|
||||
if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci))))
|
||||
out += sprintf(out, "%*s Element is NULL (bug?)\n", space, "");
|
||||
|
||||
if (list_empty(&qh->queue)) {
|
||||
out += sprintf(out, "%*s queue is empty\n", space, "");
|
||||
if (qh == uhci->skel_async_qh)
|
||||
out += uhci_show_td(uhci->term_td, out,
|
||||
out += uhci_show_td(uhci, uhci->term_td, out,
|
||||
len - (out - buf), 0);
|
||||
} else {
|
||||
struct urb_priv *urbp = list_entry(qh->queue.next,
|
||||
|
|
@ -201,13 +206,13 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
|||
struct uhci_td *td = list_entry(urbp->td_list.next,
|
||||
struct uhci_td, list);
|
||||
|
||||
if (element != LINK_TO_TD(td))
|
||||
if (element != LINK_TO_TD(uhci, td))
|
||||
out += sprintf(out, "%*s Element != First TD\n",
|
||||
space, "");
|
||||
i = nurbs = 0;
|
||||
list_for_each_entry(urbp, &qh->queue, node) {
|
||||
if (++i <= 10)
|
||||
out += uhci_show_urbp(urbp, out,
|
||||
out += uhci_show_urbp(uhci, urbp, out,
|
||||
len - (out - buf), space + 2);
|
||||
else
|
||||
++nurbs;
|
||||
|
|
@ -219,7 +224,8 @@ static int uhci_show_qh(struct uhci_hcd *uhci,
|
|||
|
||||
if (qh->dummy_td) {
|
||||
out += sprintf(out, "%*s Dummy TD\n", space, "");
|
||||
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
|
||||
out += uhci_show_td(uhci, qh->dummy_td, out,
|
||||
len - (out - buf), 0);
|
||||
}
|
||||
|
||||
return out - buf;
|
||||
|
|
@ -285,7 +291,6 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
|
|||
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
|
||||
{
|
||||
char *out = buf;
|
||||
unsigned long io_addr = uhci->io_addr;
|
||||
unsigned short usbcmd, usbstat, usbint, usbfrnum;
|
||||
unsigned int flbaseadd;
|
||||
unsigned char sof;
|
||||
|
|
@ -295,14 +300,14 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
|
|||
if (len < 80 * 9)
|
||||
return 0;
|
||||
|
||||
usbcmd = inw(io_addr + 0);
|
||||
usbstat = inw(io_addr + 2);
|
||||
usbint = inw(io_addr + 4);
|
||||
usbfrnum = inw(io_addr + 6);
|
||||
flbaseadd = inl(io_addr + 8);
|
||||
sof = inb(io_addr + 12);
|
||||
portsc1 = inw(io_addr + 16);
|
||||
portsc2 = inw(io_addr + 18);
|
||||
usbcmd = uhci_readw(uhci, 0);
|
||||
usbstat = uhci_readw(uhci, 2);
|
||||
usbint = uhci_readw(uhci, 4);
|
||||
usbfrnum = uhci_readw(uhci, 6);
|
||||
flbaseadd = uhci_readl(uhci, 8);
|
||||
sof = uhci_readb(uhci, 12);
|
||||
portsc1 = uhci_readw(uhci, 16);
|
||||
portsc2 = uhci_readw(uhci, 18);
|
||||
|
||||
out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n",
|
||||
usbcmd,
|
||||
|
|
@ -347,8 +352,8 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
|||
struct uhci_td *td;
|
||||
struct list_head *tmp, *head;
|
||||
int nframes, nerrs;
|
||||
__le32 link;
|
||||
__le32 fsbr_link;
|
||||
__hc32 link;
|
||||
__hc32 fsbr_link;
|
||||
|
||||
static const char * const qh_names[] = {
|
||||
"unlink", "iso", "int128", "int64", "int32", "int16",
|
||||
|
|
@ -376,7 +381,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
|||
nframes = 10;
|
||||
nerrs = 0;
|
||||
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
|
||||
__le32 qh_dma;
|
||||
__hc32 qh_dma;
|
||||
|
||||
j = 0;
|
||||
td = uhci->frame_cpu[i];
|
||||
|
|
@ -386,7 +391,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
|||
|
||||
if (nframes > 0) {
|
||||
out += sprintf(out, "- Frame %d -> (%08x)\n",
|
||||
i, le32_to_cpu(link));
|
||||
i, hc32_to_cpu(uhci, link));
|
||||
j = 1;
|
||||
}
|
||||
|
||||
|
|
@ -395,7 +400,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
|||
do {
|
||||
td = list_entry(tmp, struct uhci_td, fl_list);
|
||||
tmp = tmp->next;
|
||||
if (link != LINK_TO_TD(td)) {
|
||||
if (link != LINK_TO_TD(uhci, td)) {
|
||||
if (nframes > 0)
|
||||
out += sprintf(out, " link does "
|
||||
"not match list entry!\n");
|
||||
|
|
@ -403,7 +408,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
|||
++nerrs;
|
||||
}
|
||||
if (nframes > 0)
|
||||
out += uhci_show_td(td, out,
|
||||
out += uhci_show_td(uhci, td, out,
|
||||
len - (out - buf), 4);
|
||||
link = td->link;
|
||||
} while (tmp != head);
|
||||
|
|
@ -415,11 +420,12 @@ check_link:
|
|||
if (!j) {
|
||||
out += sprintf(out,
|
||||
"- Frame %d -> (%08x)\n",
|
||||
i, le32_to_cpu(link));
|
||||
i, hc32_to_cpu(uhci, link));
|
||||
j = 1;
|
||||
}
|
||||
out += sprintf(out, " link does not match "
|
||||
"QH (%08x)!\n", le32_to_cpu(qh_dma));
|
||||
"QH (%08x)!\n",
|
||||
hc32_to_cpu(uhci, qh_dma));
|
||||
} else
|
||||
++nerrs;
|
||||
}
|
||||
|
|
@ -440,11 +446,11 @@ check_link:
|
|||
|
||||
/* Last QH is the Terminating QH, it's different */
|
||||
if (i == SKEL_TERM) {
|
||||
if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
|
||||
if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td))
|
||||
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
|
||||
link = fsbr_link;
|
||||
if (!link)
|
||||
link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
goto check_qh_link;
|
||||
}
|
||||
|
||||
|
|
@ -458,20 +464,20 @@ check_link:
|
|||
out += uhci_show_qh(uhci, qh, out,
|
||||
len - (out - buf), 4);
|
||||
if (!fsbr_link && qh->skel >= SKEL_FSBR)
|
||||
fsbr_link = LINK_TO_QH(qh);
|
||||
fsbr_link = LINK_TO_QH(uhci, qh);
|
||||
}
|
||||
if ((cnt -= 10) > 0)
|
||||
out += sprintf(out, " Skipped %d QHs\n", cnt);
|
||||
|
||||
link = UHCI_PTR_TERM;
|
||||
link = UHCI_PTR_TERM(uhci);
|
||||
if (i <= SKEL_ISO)
|
||||
;
|
||||
else if (i < SKEL_ASYNC)
|
||||
link = LINK_TO_QH(uhci->skel_async_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_async_qh);
|
||||
else if (!uhci->fsbr_is_on)
|
||||
;
|
||||
else
|
||||
link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
check_qh_link:
|
||||
if (qh->link != link)
|
||||
out += sprintf(out, " last QH not linked to next skeleton!\n");
|
||||
|
|
|
|||
208
drivers/usb/host/uhci-grlib.c
Normal file
208
drivers/usb/host/uhci-grlib.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* UHCI HCD (Host Controller Driver) for GRLIB GRUSBHC
|
||||
*
|
||||
* Copyright (c) 2011 Jan Andersson <jan@gaisler.com>
|
||||
*
|
||||
* This file is based on UHCI PCI HCD:
|
||||
* (C) Copyright 1999 Linus Torvalds
|
||||
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
|
||||
* (C) Copyright 1999 Randy Dunlap
|
||||
* (C) Copyright 1999 Georg Acher, acher@in.tum.de
|
||||
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
|
||||
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
|
||||
* (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
|
||||
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
|
||||
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
|
||||
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
|
||||
* (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
|
||||
*/
|
||||
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
static int uhci_grlib_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
|
||||
/*
|
||||
* Probe to determine the endianness of the controller.
|
||||
* We know that bit 7 of the PORTSC1 register is always set
|
||||
* and bit 15 is always clear. If uhci_readw() yields a value
|
||||
* with bit 7 (0x80) turned on then the current little-endian
|
||||
* setting is correct. Otherwise we assume the value was
|
||||
* byte-swapped; hence the register interface and presumably
|
||||
* also the descriptors are big-endian.
|
||||
*/
|
||||
if (!(uhci_readw(uhci, USBPORTSC1) & 0x80)) {
|
||||
uhci->big_endian_mmio = 1;
|
||||
uhci->big_endian_desc = 1;
|
||||
}
|
||||
|
||||
uhci->rh_numports = uhci_count_ports(hcd);
|
||||
|
||||
/* Set up pointers to to generic functions */
|
||||
uhci->reset_hc = uhci_generic_reset_hc;
|
||||
uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
|
||||
/* No special actions need to be taken for the functions below */
|
||||
uhci->configure_hc = NULL;
|
||||
uhci->resume_detect_interrupts_are_broken = NULL;
|
||||
uhci->global_suspend_mode_is_broken = NULL;
|
||||
|
||||
/* Reset if the controller isn't already safely quiescent. */
|
||||
check_and_reset_hc(uhci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hc_driver uhci_grlib_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "GRLIB GRUSBHC UHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct uhci_hcd),
|
||||
|
||||
/* Generic hardware linkage */
|
||||
.irq = uhci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB11,
|
||||
|
||||
/* Basic lifecycle operations */
|
||||
.reset = uhci_grlib_init,
|
||||
.start = uhci_start,
|
||||
#ifdef CONFIG_PM
|
||||
.pci_suspend = NULL,
|
||||
.pci_resume = NULL,
|
||||
.bus_suspend = uhci_rh_suspend,
|
||||
.bus_resume = uhci_rh_resume,
|
||||
#endif
|
||||
.stop = uhci_stop,
|
||||
|
||||
.urb_enqueue = uhci_urb_enqueue,
|
||||
.urb_dequeue = uhci_urb_dequeue,
|
||||
|
||||
.endpoint_disable = uhci_hcd_endpoint_disable,
|
||||
.get_frame_number = uhci_hcd_get_frame_number,
|
||||
|
||||
.hub_status_data = uhci_hub_status_data,
|
||||
.hub_control = uhci_hub_control,
|
||||
};
|
||||
|
||||
|
||||
static int __devinit uhci_hcd_grlib_probe(struct platform_device *op)
|
||||
{
|
||||
struct device_node *dn = op->dev.of_node;
|
||||
struct usb_hcd *hcd;
|
||||
struct uhci_hcd *uhci = NULL;
|
||||
struct resource res;
|
||||
int irq;
|
||||
int rv;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&op->dev, "initializing GRUSBHC UHCI USB Controller\n");
|
||||
|
||||
rv = of_address_to_resource(dn, 0, &res);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* usb_create_hcd requires dma_mask != NULL */
|
||||
op->dev.dma_mask = &op->dev.coherent_dma_mask;
|
||||
hcd = usb_create_hcd(&uhci_grlib_hc_driver, &op->dev,
|
||||
"GRUSBHC UHCI USB");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
hcd->rsrc_start = res.start;
|
||||
hcd->rsrc_len = res.end - res.start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
|
||||
rv = -EBUSY;
|
||||
goto err_rmr;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(dn, 0);
|
||||
if (irq == NO_IRQ) {
|
||||
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
|
||||
rv = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
|
||||
rv = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
uhci = hcd_to_uhci(hcd);
|
||||
|
||||
uhci->regs = hcd->regs;
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv)
|
||||
goto err_uhci;
|
||||
|
||||
return 0;
|
||||
|
||||
err_uhci:
|
||||
iounmap(hcd->regs);
|
||||
err_ioremap:
|
||||
irq_dispose_mapping(irq);
|
||||
err_irq:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_rmr:
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int uhci_hcd_grlib_remove(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
dev_set_drvdata(&op->dev, NULL);
|
||||
|
||||
dev_dbg(&op->dev, "stopping GRLIB GRUSBHC UHCI USB Controller\n");
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
irq_dispose_mapping(hcd->irq);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the controller is quiescent and that we're not using it
|
||||
* any more. This is mainly for the benefit of programs which, like kexec,
|
||||
* expect the hardware to be idle: not doing DMA or generating IRQs.
|
||||
*
|
||||
* This routine may be called in a damaged or failing kernel. Hence we
|
||||
* do not acquire the spinlock before shutting down the controller.
|
||||
*/
|
||||
static void uhci_hcd_grlib_shutdown(struct platform_device *op)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
|
||||
|
||||
uhci_hc_died(hcd_to_uhci(hcd));
|
||||
}
|
||||
|
||||
static const struct of_device_id uhci_hcd_grlib_of_match[] = {
|
||||
{ .name = "GAISLER_UHCI", },
|
||||
{ .name = "01_027", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match);
|
||||
|
||||
|
||||
static struct platform_driver uhci_grlib_driver = {
|
||||
.probe = uhci_hcd_grlib_probe,
|
||||
.remove = uhci_hcd_grlib_remove,
|
||||
.shutdown = uhci_hcd_grlib_shutdown,
|
||||
.driver = {
|
||||
.name = "grlib-uhci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = uhci_hcd_grlib_of_match,
|
||||
},
|
||||
};
|
||||
|
|
@ -48,7 +48,6 @@
|
|||
#include <asm/system.h>
|
||||
|
||||
#include "uhci-hcd.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
|
|
@ -94,7 +93,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
|
|||
/*
|
||||
* Calculate the link pointer DMA value for the first Skeleton QH in a frame.
|
||||
*/
|
||||
static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
|
||||
static __hc32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
|
||||
{
|
||||
int skelnum;
|
||||
|
||||
|
|
@ -116,7 +115,7 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
|
|||
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
|
||||
if (skelnum <= 1)
|
||||
skelnum = 9;
|
||||
return LINK_TO_QH(uhci->skelqh[skelnum]);
|
||||
return LINK_TO_QH(uhci, uhci->skelqh[skelnum]);
|
||||
}
|
||||
|
||||
#include "uhci-debug.c"
|
||||
|
|
@ -135,15 +134,12 @@ static void finish_reset(struct uhci_hcd *uhci)
|
|||
* We have to clear them by hand.
|
||||
*/
|
||||
for (port = 0; port < uhci->rh_numports; ++port)
|
||||
outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
|
||||
uhci_writew(uhci, 0, USBPORTSC1 + (port * 2));
|
||||
|
||||
uhci->port_c_suspend = uhci->resuming_ports = 0;
|
||||
uhci->rh_state = UHCI_RH_RESET;
|
||||
uhci->is_stopped = UHCI_IS_STOPPED;
|
||||
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
|
||||
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
|
||||
|
||||
uhci->dead = 0; /* Full reset resurrects the controller */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -153,7 +149,7 @@ static void finish_reset(struct uhci_hcd *uhci)
|
|||
static void uhci_hc_died(struct uhci_hcd *uhci)
|
||||
{
|
||||
uhci_get_current_frame_number(uhci);
|
||||
uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
|
||||
uhci->reset_hc(uhci);
|
||||
finish_reset(uhci);
|
||||
uhci->dead = 1;
|
||||
|
||||
|
|
@ -168,97 +164,118 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
|
|||
*/
|
||||
static void check_and_reset_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
|
||||
if (uhci->check_and_reset_hc(uhci))
|
||||
finish_reset(uhci);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC)
|
||||
/*
|
||||
* The two functions below are generic reset functions that are used on systems
|
||||
* that do not have keyboard and mouse legacy support. We assume that we are
|
||||
* running on such a system if CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC is defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Make sure the controller is completely inactive, unable to
|
||||
* generate interrupts or do DMA.
|
||||
*/
|
||||
static void uhci_generic_reset_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
/* Reset the HC - this will force us to get a
|
||||
* new notification of any already connected
|
||||
* ports due to the virtual disconnect that it
|
||||
* implies.
|
||||
*/
|
||||
uhci_writew(uhci, USBCMD_HCRESET, USBCMD);
|
||||
mb();
|
||||
udelay(5);
|
||||
if (uhci_readw(uhci, USBCMD) & USBCMD_HCRESET)
|
||||
dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
|
||||
|
||||
/* Just to be safe, disable interrupt requests and
|
||||
* make sure the controller is stopped.
|
||||
*/
|
||||
uhci_writew(uhci, 0, USBINTR);
|
||||
uhci_writew(uhci, 0, USBCMD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a controller that was newly discovered or has just been
|
||||
* resumed. In either case we can't be sure of its previous state.
|
||||
*
|
||||
* Returns: 1 if the controller was reset, 0 otherwise.
|
||||
*/
|
||||
static int uhci_generic_check_and_reset_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
unsigned int cmd, intr;
|
||||
|
||||
/*
|
||||
* When restarting a suspended controller, we expect all the
|
||||
* settings to be the same as we left them:
|
||||
*
|
||||
* Controller is stopped and configured with EGSM set;
|
||||
* No interrupts enabled except possibly Resume Detect.
|
||||
*
|
||||
* If any of these conditions are violated we do a complete reset.
|
||||
*/
|
||||
|
||||
cmd = uhci_readw(uhci, USBCMD);
|
||||
if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
|
||||
dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
|
||||
__func__, cmd);
|
||||
goto reset_needed;
|
||||
}
|
||||
|
||||
intr = uhci_readw(uhci, USBINTR);
|
||||
if (intr & (~USBINTR_RESUME)) {
|
||||
dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
|
||||
__func__, intr);
|
||||
goto reset_needed;
|
||||
}
|
||||
return 0;
|
||||
|
||||
reset_needed:
|
||||
dev_dbg(uhci_dev(uhci), "Performing full reset\n");
|
||||
uhci_generic_reset_hc(uhci);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */
|
||||
|
||||
/*
|
||||
* Store the basic register settings needed by the controller.
|
||||
*/
|
||||
static void configure_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
|
||||
|
||||
/* Set the frame length to the default: 1 ms exactly */
|
||||
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
|
||||
uhci_writeb(uhci, USBSOF_DEFAULT, USBSOF);
|
||||
|
||||
/* Store the frame list base address */
|
||||
outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
|
||||
uhci_writel(uhci, uhci->frame_dma_handle, USBFLBASEADD);
|
||||
|
||||
/* Set the current frame number */
|
||||
outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
|
||||
uhci->io_addr + USBFRNUM);
|
||||
uhci_writew(uhci, uhci->frame_number & UHCI_MAX_SOF_NUMBER,
|
||||
USBFRNUM);
|
||||
|
||||
/* Mark controller as not halted before we enable interrupts */
|
||||
uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
|
||||
mb();
|
||||
|
||||
/* Enable PIRQ */
|
||||
pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
|
||||
|
||||
/* Disable platform-specific non-PME# wakeup */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
pci_write_config_byte(pdev, USBRES_INTEL, 0);
|
||||
/* perform any arch/bus specific configuration */
|
||||
if (uhci->configure_hc)
|
||||
uhci->configure_hc(uhci);
|
||||
}
|
||||
|
||||
|
||||
static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
|
||||
/* If we have to ignore overcurrent events then almost by definition
|
||||
* we can't depend on resume-detect interrupts. */
|
||||
if (ignore_oc)
|
||||
return 1;
|
||||
|
||||
switch (to_pci_dev(uhci_dev(uhci))->vendor) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case PCI_VENDOR_ID_GENESYS:
|
||||
/* Genesys Logic's GL880S controllers don't generate
|
||||
* resume-detect interrupts.
|
||||
*/
|
||||
return 1;
|
||||
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
/* Some of Intel's USB controllers have a bug that causes
|
||||
* resume-detect interrupts if any port has an over-current
|
||||
* condition. To make matters worse, some motherboards
|
||||
* hardwire unused USB ports' over-current inputs active!
|
||||
* To prevent problems, we will not enable resume-detect
|
||||
* interrupts if any ports are OC.
|
||||
*/
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
|
||||
USBPORTSC_OC)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return uhci->resume_detect_interrupts_are_broken ?
|
||||
uhci->resume_detect_interrupts_are_broken(uhci) : 0;
|
||||
}
|
||||
|
||||
static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
const char *sys_info;
|
||||
static char bad_Asus_board[] = "A7V8X";
|
||||
|
||||
/* One of Asus's motherboards has a bug which causes it to
|
||||
* wake up immediately from suspend-to-RAM if any of the ports
|
||||
* are connected. In such cases we will not set EGSM.
|
||||
*/
|
||||
sys_info = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
if (sys_info && !strcmp(sys_info, bad_Asus_board)) {
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
|
||||
USBPORTSC_CCS)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return uhci->global_suspend_mode_is_broken ?
|
||||
uhci->global_suspend_mode_is_broken(uhci) : 0;
|
||||
}
|
||||
|
||||
static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
|
||||
|
|
@ -321,8 +338,8 @@ __acquires(uhci->lock)
|
|||
!int_enable)
|
||||
uhci->RD_enable = int_enable = 0;
|
||||
|
||||
outw(int_enable, uhci->io_addr + USBINTR);
|
||||
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
|
||||
uhci_writew(uhci, int_enable, USBINTR);
|
||||
uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
|
||||
mb();
|
||||
udelay(5);
|
||||
|
||||
|
|
@ -331,7 +348,7 @@ __acquires(uhci->lock)
|
|||
* controller should stop after a few microseconds. Otherwise
|
||||
* we will give the controller one frame to stop.
|
||||
*/
|
||||
if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
|
||||
if (!auto_stop && !(uhci_readw(uhci, USBSTS) & USBSTS_HCH)) {
|
||||
uhci->rh_state = UHCI_RH_SUSPENDING;
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
msleep(1);
|
||||
|
|
@ -339,7 +356,7 @@ __acquires(uhci->lock)
|
|||
if (uhci->dead)
|
||||
return;
|
||||
}
|
||||
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
|
||||
if (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH))
|
||||
dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
|
||||
|
||||
uhci_get_current_frame_number(uhci);
|
||||
|
|
@ -361,15 +378,14 @@ __acquires(uhci->lock)
|
|||
|
||||
static void start_rh(struct uhci_hcd *uhci)
|
||||
{
|
||||
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
|
||||
uhci->is_stopped = 0;
|
||||
|
||||
/* Mark it configured and running with a 64-byte max packet.
|
||||
* All interrupts are enabled, even though RESUME won't do anything.
|
||||
*/
|
||||
outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
|
||||
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
|
||||
uhci->io_addr + USBINTR);
|
||||
uhci_writew(uhci, USBCMD_RS | USBCMD_CF | USBCMD_MAXP, USBCMD);
|
||||
uhci_writew(uhci, USBINTR_TIMEOUT | USBINTR_RESUME |
|
||||
USBINTR_IOC | USBINTR_SP, USBINTR);
|
||||
mb();
|
||||
uhci->rh_state = UHCI_RH_RUNNING;
|
||||
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
|
||||
|
|
@ -392,9 +408,9 @@ __acquires(uhci->lock)
|
|||
unsigned egsm;
|
||||
|
||||
/* Keep EGSM on if it was set before */
|
||||
egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
|
||||
egsm = uhci_readw(uhci, USBCMD) & USBCMD_EGSM;
|
||||
uhci->rh_state = UHCI_RH_RESUMING;
|
||||
outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
|
||||
uhci_writew(uhci, USBCMD_FGR | USBCMD_CF | egsm, USBCMD);
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
msleep(20);
|
||||
spin_lock_irq(&uhci->lock);
|
||||
|
|
@ -402,10 +418,10 @@ __acquires(uhci->lock)
|
|||
return;
|
||||
|
||||
/* End Global Resume and wait for EOP to be sent */
|
||||
outw(USBCMD_CF, uhci->io_addr + USBCMD);
|
||||
uhci_writew(uhci, USBCMD_CF, USBCMD);
|
||||
mb();
|
||||
udelay(4);
|
||||
if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
|
||||
if (uhci_readw(uhci, USBCMD) & USBCMD_FGR)
|
||||
dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
|
||||
}
|
||||
|
||||
|
|
@ -425,10 +441,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
|
|||
* interrupt cause. Contrary to the UHCI specification, the
|
||||
* "HC Halted" status bit is persistent: it is RO, not R/WC.
|
||||
*/
|
||||
status = inw(uhci->io_addr + USBSTS);
|
||||
status = uhci_readw(uhci, USBSTS);
|
||||
if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
|
||||
return IRQ_NONE;
|
||||
outw(status, uhci->io_addr + USBSTS); /* Clear it */
|
||||
uhci_writew(uhci, status, USBSTS); /* Clear it */
|
||||
|
||||
if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
|
||||
if (status & USBSTS_HSE)
|
||||
|
|
@ -450,6 +466,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
|
|||
lprintk(errbuf);
|
||||
}
|
||||
uhci_hc_died(uhci);
|
||||
usb_hc_died(hcd);
|
||||
|
||||
/* Force a callback in case there are
|
||||
* pending unlinks */
|
||||
|
|
@ -483,7 +500,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
|
|||
if (!uhci->is_stopped) {
|
||||
unsigned delta;
|
||||
|
||||
delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
|
||||
delta = (uhci_readw(uhci, USBFRNUM) - uhci->frame_number) &
|
||||
(UHCI_NUMFRAMES - 1);
|
||||
uhci->frame_number += delta;
|
||||
}
|
||||
|
|
@ -520,61 +537,6 @@ static void release_uhci(struct uhci_hcd *uhci)
|
|||
uhci->frame, uhci->frame_dma_handle);
|
||||
}
|
||||
|
||||
static int uhci_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
unsigned io_size = (unsigned) hcd->rsrc_len;
|
||||
int port;
|
||||
|
||||
uhci->io_addr = (unsigned long) hcd->rsrc_start;
|
||||
|
||||
/* The UHCI spec says devices must have 2 ports, and goes on to say
|
||||
* they may have more but gives no way to determine how many there
|
||||
* are. However according to the UHCI spec, Bit 7 of the port
|
||||
* status and control register is always set to 1. So we try to
|
||||
* use this to our advantage. Another common failure mode when
|
||||
* a nonexistent register is addressed is to return all ones, so
|
||||
* we test for that also.
|
||||
*/
|
||||
for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
|
||||
unsigned int portstatus;
|
||||
|
||||
portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2));
|
||||
if (!(portstatus & 0x0080) || portstatus == 0xffff)
|
||||
break;
|
||||
}
|
||||
if (debug)
|
||||
dev_info(uhci_dev(uhci), "detected %d ports\n", port);
|
||||
|
||||
/* Anything greater than 7 is weird so we'll ignore it. */
|
||||
if (port > UHCI_RH_MAXCHILD) {
|
||||
dev_info(uhci_dev(uhci), "port count misdetected? "
|
||||
"forcing to 2 ports\n");
|
||||
port = 2;
|
||||
}
|
||||
uhci->rh_numports = port;
|
||||
|
||||
/* Kick BIOS off this hardware and reset if the controller
|
||||
* isn't already safely quiescent.
|
||||
*/
|
||||
check_and_reset_hc(uhci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the controller is quiescent and that we're not using it
|
||||
* any more. This is mainly for the benefit of programs which, like kexec,
|
||||
* expect the hardware to be idle: not doing DMA or generating IRQs.
|
||||
*
|
||||
* This routine may be called in a damaged or failing kernel. Hence we
|
||||
* do not acquire the spinlock before shutting down the controller.
|
||||
*/
|
||||
static void uhci_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pdev);
|
||||
|
||||
uhci_hc_died(hcd_to_uhci(hcd));
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a frame list, and then setup the skeleton
|
||||
*
|
||||
|
|
@ -669,16 +631,16 @@ static int uhci_start(struct usb_hcd *hcd)
|
|||
* 8 Interrupt queues; link all higher int queues to int1 = async
|
||||
*/
|
||||
for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
|
||||
uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
|
||||
uhci->skel_async_qh->link = UHCI_PTR_TERM;
|
||||
uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
uhci->skelqh[i]->link = LINK_TO_QH(uhci, uhci->skel_async_qh);
|
||||
uhci->skel_async_qh->link = UHCI_PTR_TERM(uhci);
|
||||
uhci->skel_term_qh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
|
||||
/* This dummy TD is to work around a bug in Intel PIIX controllers */
|
||||
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
|
||||
uhci_fill_td(uhci, uhci->term_td, 0, uhci_explen(0) |
|
||||
(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
|
||||
uhci->term_td->link = UHCI_PTR_TERM;
|
||||
uhci->term_td->link = UHCI_PTR_TERM(uhci);
|
||||
uhci->skel_async_qh->element = uhci->skel_term_qh->element =
|
||||
LINK_TO_TD(uhci->term_td);
|
||||
LINK_TO_TD(uhci, uhci->term_td);
|
||||
|
||||
/*
|
||||
* Fill the frame list: make all entries point to the proper
|
||||
|
|
@ -791,86 +753,6 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
|
||||
|
||||
spin_lock_irq(&uhci->lock);
|
||||
if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
|
||||
goto done_okay; /* Already suspended or dead */
|
||||
|
||||
if (uhci->rh_state > UHCI_RH_SUSPENDED) {
|
||||
dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
|
||||
rc = -EBUSY;
|
||||
goto done;
|
||||
};
|
||||
|
||||
/* All PCI host controllers are required to disable IRQ generation
|
||||
* at the source, so we must turn off PIRQ.
|
||||
*/
|
||||
pci_write_config_word(pdev, USBLEGSUP, 0);
|
||||
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
|
||||
/* Enable platform-specific non-PME# wakeup */
|
||||
if (do_wakeup) {
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
pci_write_config_byte(pdev, USBRES_INTEL,
|
||||
USBPORT1EN | USBPORT2EN);
|
||||
}
|
||||
|
||||
done_okay:
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
done:
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
|
||||
|
||||
/* Since we aren't in D3 any more, it's safe to set this flag
|
||||
* even if the controller was dead.
|
||||
*/
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
spin_lock_irq(&uhci->lock);
|
||||
|
||||
/* Make sure resume from hibernation re-enumerates everything */
|
||||
if (hibernated)
|
||||
uhci_hc_died(uhci);
|
||||
|
||||
/* The firmware or a boot kernel may have changed the controller
|
||||
* settings during a system wakeup. Check it and reconfigure
|
||||
* to avoid problems.
|
||||
*/
|
||||
check_and_reset_hc(uhci);
|
||||
|
||||
/* If the controller was dead before, it's back alive now */
|
||||
configure_hc(uhci);
|
||||
|
||||
/* Tell the core if the controller had to be reset */
|
||||
if (uhci->rh_state == UHCI_RH_RESET)
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
|
||||
/* If interrupts don't work and remote wakeup is enabled then
|
||||
* the suspended root hub needs to be polled.
|
||||
*/
|
||||
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
|
||||
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
|
||||
/* Does the root hub have a port wakeup pending? */
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wait until a particular device/endpoint's QH is idle, and free it */
|
||||
|
|
@ -908,67 +790,62 @@ static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
|
|||
/* Minimize latency by avoiding the spinlock */
|
||||
frame_number = uhci->frame_number;
|
||||
barrier();
|
||||
delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
|
||||
delta = (uhci_readw(uhci, USBFRNUM) - frame_number) &
|
||||
(UHCI_NUMFRAMES - 1);
|
||||
return frame_number + delta;
|
||||
}
|
||||
|
||||
/* Determines number of ports on controller */
|
||||
static int uhci_count_ports(struct usb_hcd *hcd)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
unsigned io_size = (unsigned) hcd->rsrc_len;
|
||||
int port;
|
||||
|
||||
/* The UHCI spec says devices must have 2 ports, and goes on to say
|
||||
* they may have more but gives no way to determine how many there
|
||||
* are. However according to the UHCI spec, Bit 7 of the port
|
||||
* status and control register is always set to 1. So we try to
|
||||
* use this to our advantage. Another common failure mode when
|
||||
* a nonexistent register is addressed is to return all ones, so
|
||||
* we test for that also.
|
||||
*/
|
||||
for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
|
||||
unsigned int portstatus;
|
||||
|
||||
portstatus = uhci_readw(uhci, USBPORTSC1 + (port * 2));
|
||||
if (!(portstatus & 0x0080) || portstatus == 0xffff)
|
||||
break;
|
||||
}
|
||||
if (debug)
|
||||
dev_info(uhci_dev(uhci), "detected %d ports\n", port);
|
||||
|
||||
/* Anything greater than 7 is weird so we'll ignore it. */
|
||||
if (port > UHCI_RH_MAXCHILD) {
|
||||
dev_info(uhci_dev(uhci), "port count misdetected? "
|
||||
"forcing to 2 ports\n");
|
||||
port = 2;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
static const char hcd_name[] = "uhci_hcd";
|
||||
|
||||
static const struct hc_driver uhci_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "UHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct uhci_hcd),
|
||||
|
||||
/* Generic hardware linkage */
|
||||
.irq = uhci_irq,
|
||||
.flags = HCD_USB11,
|
||||
|
||||
/* Basic lifecycle operations */
|
||||
.reset = uhci_init,
|
||||
.start = uhci_start,
|
||||
#ifdef CONFIG_PM
|
||||
.pci_suspend = uhci_pci_suspend,
|
||||
.pci_resume = uhci_pci_resume,
|
||||
.bus_suspend = uhci_rh_suspend,
|
||||
.bus_resume = uhci_rh_resume,
|
||||
#ifdef CONFIG_PCI
|
||||
#include "uhci-pci.c"
|
||||
#define PCI_DRIVER uhci_pci_driver
|
||||
#endif
|
||||
.stop = uhci_stop,
|
||||
|
||||
.urb_enqueue = uhci_urb_enqueue,
|
||||
.urb_dequeue = uhci_urb_dequeue,
|
||||
|
||||
.endpoint_disable = uhci_hcd_endpoint_disable,
|
||||
.get_frame_number = uhci_hcd_get_frame_number,
|
||||
|
||||
.hub_status_data = uhci_hub_status_data,
|
||||
.hub_control = uhci_hub_control,
|
||||
};
|
||||
|
||||
static const struct pci_device_id uhci_pci_ids[] = { {
|
||||
/* handle any USB UHCI controller */
|
||||
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),
|
||||
.driver_data = (unsigned long) &uhci_driver,
|
||||
}, { /* end: all zeroes */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
|
||||
|
||||
static struct pci_driver uhci_pci_driver = {
|
||||
.name = (char *)hcd_name,
|
||||
.id_table = uhci_pci_ids,
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = uhci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#ifdef CONFIG_SPARC_LEON
|
||||
#include "uhci-grlib.c"
|
||||
#define PLATFORM_DRIVER uhci_grlib_driver
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
|
||||
#error "missing bus glue for uhci-hcd"
|
||||
#endif
|
||||
|
||||
static int __init uhci_hcd_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
|
@ -994,13 +871,27 @@ static int __init uhci_hcd_init(void)
|
|||
if (!uhci_up_cachep)
|
||||
goto up_failed;
|
||||
|
||||
retval = pci_register_driver(&uhci_pci_driver);
|
||||
if (retval)
|
||||
goto init_failed;
|
||||
#ifdef PLATFORM_DRIVER
|
||||
retval = platform_driver_register(&PLATFORM_DRIVER);
|
||||
if (retval < 0)
|
||||
goto clean0;
|
||||
#endif
|
||||
|
||||
#ifdef PCI_DRIVER
|
||||
retval = pci_register_driver(&PCI_DRIVER);
|
||||
if (retval < 0)
|
||||
goto clean1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
init_failed:
|
||||
#ifdef PCI_DRIVER
|
||||
clean1:
|
||||
#endif
|
||||
#ifdef PLATFORM_DRIVER
|
||||
platform_driver_unregister(&PLATFORM_DRIVER);
|
||||
clean0:
|
||||
#endif
|
||||
kmem_cache_destroy(uhci_up_cachep);
|
||||
|
||||
up_failed:
|
||||
|
|
@ -1017,7 +908,12 @@ errbuf_failed:
|
|||
|
||||
static void __exit uhci_hcd_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&uhci_pci_driver);
|
||||
#ifdef PLATFORM_DRIVER
|
||||
platform_driver_unregister(&PLATFORM_DRIVER);
|
||||
#endif
|
||||
#ifdef PCI_DRIVER
|
||||
pci_unregister_driver(&PCI_DRIVER);
|
||||
#endif
|
||||
kmem_cache_destroy(uhci_up_cachep);
|
||||
debugfs_remove(uhci_debugfs_root);
|
||||
kfree(errbuf);
|
||||
|
|
|
|||
|
|
@ -78,11 +78,11 @@
|
|||
#define USBPORT1EN 0x01
|
||||
#define USBPORT2EN 0x02
|
||||
|
||||
#define UHCI_PTR_BITS cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH cpu_to_le32(0x0002)
|
||||
#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
|
||||
#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
|
||||
#define UHCI_PTR_BITS(uhci) cpu_to_hc32((uhci), 0x000F)
|
||||
#define UHCI_PTR_TERM(uhci) cpu_to_hc32((uhci), 0x0001)
|
||||
#define UHCI_PTR_QH(uhci) cpu_to_hc32((uhci), 0x0002)
|
||||
#define UHCI_PTR_DEPTH(uhci) cpu_to_hc32((uhci), 0x0004)
|
||||
#define UHCI_PTR_BREADTH(uhci) cpu_to_hc32((uhci), 0x0000)
|
||||
|
||||
#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
|
||||
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
|
||||
|
|
@ -98,6 +98,22 @@
|
|||
#define QH_WAIT_TIMEOUT msecs_to_jiffies(200)
|
||||
|
||||
|
||||
/*
|
||||
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
|
||||
* __leXX (normally) or __beXX (given UHCI_BIG_ENDIAN_DESC), depending on
|
||||
* the host controller implementation.
|
||||
*
|
||||
* To facilitate the strongest possible byte-order checking from "sparse"
|
||||
* and so on, we use __leXX unless that's not practical.
|
||||
*/
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
|
||||
typedef __u32 __bitwise __hc32;
|
||||
typedef __u16 __bitwise __hc16;
|
||||
#else
|
||||
#define __hc32 __le32
|
||||
#define __hc16 __le16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue Headers
|
||||
*/
|
||||
|
|
@ -130,8 +146,8 @@
|
|||
|
||||
struct uhci_qh {
|
||||
/* Hardware fields */
|
||||
__le32 link; /* Next QH in the schedule */
|
||||
__le32 element; /* Queue element (TD) pointer */
|
||||
__hc32 link; /* Next QH in the schedule */
|
||||
__hc32 element; /* Queue element (TD) pointer */
|
||||
|
||||
/* Software fields */
|
||||
dma_addr_t dma_handle;
|
||||
|
|
@ -168,14 +184,10 @@ struct uhci_qh {
|
|||
* We need a special accessor for the element pointer because it is
|
||||
* subject to asynchronous updates by the controller.
|
||||
*/
|
||||
static inline __le32 qh_element(struct uhci_qh *qh) {
|
||||
__le32 element = qh->element;
|
||||
#define qh_element(qh) ACCESS_ONCE((qh)->element)
|
||||
|
||||
barrier();
|
||||
return element;
|
||||
}
|
||||
|
||||
#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle))
|
||||
#define LINK_TO_QH(uhci, qh) (UHCI_PTR_QH((uhci)) | \
|
||||
cpu_to_hc32((uhci), (qh)->dma_handle))
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -212,7 +224,7 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
|
|||
/*
|
||||
* for TD <info>: (a.k.a. Token)
|
||||
*/
|
||||
#define td_token(td) le32_to_cpu((td)->token)
|
||||
#define td_token(uhci, td) hc32_to_cpu((uhci), (td)->token)
|
||||
#define TD_TOKEN_DEVADDR_SHIFT 8
|
||||
#define TD_TOKEN_TOGGLE_SHIFT 19
|
||||
#define TD_TOKEN_TOGGLE (1 << 19)
|
||||
|
|
@ -245,10 +257,10 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
|
|||
*/
|
||||
struct uhci_td {
|
||||
/* Hardware fields */
|
||||
__le32 link;
|
||||
__le32 status;
|
||||
__le32 token;
|
||||
__le32 buffer;
|
||||
__hc32 link;
|
||||
__hc32 status;
|
||||
__hc32 token;
|
||||
__hc32 buffer;
|
||||
|
||||
/* Software fields */
|
||||
dma_addr_t dma_handle;
|
||||
|
|
@ -263,14 +275,10 @@ struct uhci_td {
|
|||
* We need a special accessor for the control/status word because it is
|
||||
* subject to asynchronous updates by the controller.
|
||||
*/
|
||||
static inline u32 td_status(struct uhci_td *td) {
|
||||
__le32 status = td->status;
|
||||
#define td_status(uhci, td) hc32_to_cpu((uhci), \
|
||||
ACCESS_ONCE((td)->status))
|
||||
|
||||
barrier();
|
||||
return le32_to_cpu(status);
|
||||
}
|
||||
|
||||
#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle))
|
||||
#define LINK_TO_TD(uhci, td) (cpu_to_hc32((uhci), (td)->dma_handle))
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -380,6 +388,9 @@ struct uhci_hcd {
|
|||
/* Grabbed from PCI */
|
||||
unsigned long io_addr;
|
||||
|
||||
/* Used when registers are memory mapped */
|
||||
void __iomem *regs;
|
||||
|
||||
struct dma_pool *qh_pool;
|
||||
struct dma_pool *td_pool;
|
||||
|
||||
|
|
@ -390,7 +401,7 @@ struct uhci_hcd {
|
|||
spinlock_t lock;
|
||||
|
||||
dma_addr_t frame_dma_handle; /* Hardware frame list */
|
||||
__le32 *frame;
|
||||
__hc32 *frame;
|
||||
void **frame_cpu; /* CPU's frame list */
|
||||
|
||||
enum uhci_rh_state rh_state;
|
||||
|
|
@ -415,6 +426,12 @@ struct uhci_hcd {
|
|||
|
||||
struct timer_list fsbr_timer; /* For turning off FBSR */
|
||||
|
||||
/* Silicon quirks */
|
||||
unsigned int oc_low:1; /* OverCurrent bit active low */
|
||||
unsigned int wait_for_hp:1; /* Wait for HP port reset */
|
||||
unsigned int big_endian_mmio:1; /* Big endian registers */
|
||||
unsigned int big_endian_desc:1; /* Big endian descriptors */
|
||||
|
||||
/* Support for port suspend/resume/reset */
|
||||
unsigned long port_c_suspend; /* Bit-arrays of ports */
|
||||
unsigned long resuming_ports;
|
||||
|
|
@ -429,6 +446,16 @@ struct uhci_hcd {
|
|||
|
||||
int total_load; /* Sum of array values */
|
||||
short load[MAX_PHASE]; /* Periodic allocations */
|
||||
|
||||
/* Reset host controller */
|
||||
void (*reset_hc) (struct uhci_hcd *uhci);
|
||||
int (*check_and_reset_hc) (struct uhci_hcd *uhci);
|
||||
/* configure_hc should perform arch specific settings, if needed */
|
||||
void (*configure_hc) (struct uhci_hcd *uhci);
|
||||
/* Check for broken resume detect interrupts */
|
||||
int (*resume_detect_interrupts_are_broken) (struct uhci_hcd *uhci);
|
||||
/* Check for broken global suspend */
|
||||
int (*global_suspend_mode_is_broken) (struct uhci_hcd *uhci);
|
||||
};
|
||||
|
||||
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
|
||||
|
|
@ -467,4 +494,171 @@ struct urb_priv {
|
|||
#define PCI_VENDOR_ID_GENESYS 0x17a0
|
||||
#define PCI_DEVICE_ID_GL880S_UHCI 0x8083
|
||||
|
||||
/*
|
||||
* Functions used to access controller registers. The UCHI spec says that host
|
||||
* controller I/O registers are mapped into PCI I/O space. For non-PCI hosts
|
||||
* we use memory mapped registers.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC
|
||||
/* Support PCI only */
|
||||
static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
return inl(uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg)
|
||||
{
|
||||
outl(val, uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
return inw(uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg)
|
||||
{
|
||||
outw(val, uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
return inb(uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
|
||||
{
|
||||
outb(val, uhci->io_addr + reg);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Support non-PCI host controllers */
|
||||
#ifdef CONFIG_PCI
|
||||
/* Support PCI and non-PCI host controllers */
|
||||
#define uhci_has_pci_registers(u) ((u)->io_addr != 0)
|
||||
#else
|
||||
/* Support non-PCI host controllers only */
|
||||
#define uhci_has_pci_registers(u) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
/* Support (non-PCI) big endian host controllers */
|
||||
#define uhci_big_endian_mmio(u) ((u)->big_endian_mmio)
|
||||
#else
|
||||
#define uhci_big_endian_mmio(u) 0
|
||||
#endif
|
||||
|
||||
static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
return inl(uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
return readl_be(uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
return readl(uhci->regs + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
outl(val, uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
writel_be(val, uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
writel(val, uhci->regs + reg);
|
||||
}
|
||||
|
||||
static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
return inw(uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
return readw_be(uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
return readw(uhci->regs + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
outw(val, uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
writew_be(val, uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
writew(val, uhci->regs + reg);
|
||||
}
|
||||
|
||||
static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
return inb(uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
return readb_be(uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
return readb(uhci->regs + reg);
|
||||
}
|
||||
|
||||
static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
|
||||
{
|
||||
if (uhci_has_pci_registers(uhci))
|
||||
outb(val, uhci->io_addr + reg);
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
|
||||
else if (uhci_big_endian_mmio(uhci))
|
||||
writeb_be(val, uhci->regs + reg);
|
||||
#endif
|
||||
else
|
||||
writeb(val, uhci->regs + reg);
|
||||
}
|
||||
#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */
|
||||
|
||||
/*
|
||||
* The GRLIB GRUSBHC controller can use big endian format for its descriptors.
|
||||
*
|
||||
* UHCI controllers accessed through PCI work normally (little-endian
|
||||
* everywhere), so we don't bother supporting a BE-only mode.
|
||||
*/
|
||||
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC
|
||||
#define uhci_big_endian_desc(u) ((u)->big_endian_desc)
|
||||
|
||||
/* cpu to uhci */
|
||||
static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
|
||||
{
|
||||
return uhci_big_endian_desc(uhci)
|
||||
? (__force __hc32)cpu_to_be32(x)
|
||||
: (__force __hc32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* uhci to cpu */
|
||||
static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
|
||||
{
|
||||
return uhci_big_endian_desc(uhci)
|
||||
? be32_to_cpu((__force __be32)x)
|
||||
: le32_to_cpu((__force __le32)x);
|
||||
}
|
||||
|
||||
#else
|
||||
/* cpu to uhci */
|
||||
static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x)
|
||||
{
|
||||
return cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* uhci to cpu */
|
||||
static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x)
|
||||
{
|
||||
return le32_to_cpu(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ static int any_ports_active(struct uhci_hcd *uhci)
|
|||
int port;
|
||||
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
|
||||
if ((uhci_readw(uhci, USBPORTSC1 + port * 2) &
|
||||
(USBPORTSC_CCS | RWC_BITS)) ||
|
||||
test_bit(port, &uhci->port_c_suspend))
|
||||
return 1;
|
||||
|
|
@ -68,7 +68,7 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
|
|||
|
||||
*buf = 0;
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) ||
|
||||
if ((uhci_readw(uhci, USBPORTSC1 + port * 2) & mask) ||
|
||||
test_bit(port, &uhci->port_c_suspend))
|
||||
*buf |= (1 << (port + 1));
|
||||
}
|
||||
|
|
@ -78,17 +78,17 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
|
|||
#define OK(x) len = (x); break
|
||||
|
||||
#define CLR_RH_PORTSTAT(x) \
|
||||
status = inw(port_addr); \
|
||||
status = uhci_readw(uhci, port_addr); \
|
||||
status &= ~(RWC_BITS|WZ_BITS); \
|
||||
status &= ~(x); \
|
||||
status |= RWC_BITS & (x); \
|
||||
outw(status, port_addr)
|
||||
uhci_writew(uhci, status, port_addr)
|
||||
|
||||
#define SET_RH_PORTSTAT(x) \
|
||||
status = inw(port_addr); \
|
||||
status = uhci_readw(uhci, port_addr); \
|
||||
status |= (x); \
|
||||
status &= ~(RWC_BITS|WZ_BITS); \
|
||||
outw(status, port_addr)
|
||||
uhci_writew(uhci, status, port_addr)
|
||||
|
||||
/* UHCI controllers don't automatically stop resume signalling after 20 msec,
|
||||
* so we have to poll and check timeouts in order to take care of it.
|
||||
|
|
@ -99,7 +99,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
|
|||
int status;
|
||||
int i;
|
||||
|
||||
if (inw(port_addr) & SUSPEND_BITS) {
|
||||
if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) {
|
||||
CLR_RH_PORTSTAT(SUSPEND_BITS);
|
||||
if (test_bit(port, &uhci->resuming_ports))
|
||||
set_bit(port, &uhci->port_c_suspend);
|
||||
|
|
@ -110,7 +110,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
|
|||
* Experiments show that some controllers take longer, so
|
||||
* we'll poll for completion. */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
if (!(inw(port_addr) & SUSPEND_BITS))
|
||||
if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS))
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
|
@ -121,12 +121,12 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
|
|||
/* Wait for the UHCI controller in HP's iLO2 server management chip.
|
||||
* It can take up to 250 us to finish a reset and set the CSC bit.
|
||||
*/
|
||||
static void wait_for_HP(unsigned long port_addr)
|
||||
static void wait_for_HP(struct uhci_hcd *uhci, unsigned long port_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 10; i < 250; i += 10) {
|
||||
if (inw(port_addr) & USBPORTSC_CSC)
|
||||
if (uhci_readw(uhci, port_addr) & USBPORTSC_CSC)
|
||||
return;
|
||||
udelay(10);
|
||||
}
|
||||
|
|
@ -140,8 +140,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
|
|||
int status;
|
||||
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
|
||||
status = inw(port_addr);
|
||||
port_addr = USBPORTSC1 + 2 * port;
|
||||
status = uhci_readw(uhci, port_addr);
|
||||
if (unlikely(status & USBPORTSC_PR)) {
|
||||
if (time_after_eq(jiffies, uhci->ports_timeout)) {
|
||||
CLR_RH_PORTSTAT(USBPORTSC_PR);
|
||||
|
|
@ -149,9 +149,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
|
|||
|
||||
/* HP's server management chip requires
|
||||
* a longer delay. */
|
||||
if (to_pci_dev(uhci_dev(uhci))->vendor ==
|
||||
PCI_VENDOR_ID_HP)
|
||||
wait_for_HP(port_addr);
|
||||
if (uhci->wait_for_hp)
|
||||
wait_for_HP(uhci, port_addr);
|
||||
|
||||
/* If the port was enabled before, turning
|
||||
* reset on caused a port enable change.
|
||||
|
|
@ -242,7 +241,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
int status, lstatus, retval = 0, len = 0;
|
||||
unsigned int port = wIndex - 1;
|
||||
unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
|
||||
unsigned long port_addr = USBPORTSC1 + 2 * port;
|
||||
u16 wPortChange, wPortStatus;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -260,14 +259,13 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
goto err;
|
||||
|
||||
uhci_check_ports(uhci);
|
||||
status = inw(port_addr);
|
||||
status = uhci_readw(uhci, port_addr);
|
||||
|
||||
/* Intel controllers report the OverCurrent bit active on.
|
||||
* VIA controllers report it active off, so we'll adjust the
|
||||
* bit value. (It's not standardized in the UHCI spec.)
|
||||
*/
|
||||
if (to_pci_dev(hcd->self.controller)->vendor ==
|
||||
PCI_VENDOR_ID_VIA)
|
||||
if (uhci->oc_low)
|
||||
status ^= USBPORTSC_OC;
|
||||
|
||||
/* UHCI doesn't support C_RESET (always false) */
|
||||
|
|
@ -358,7 +356,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
CLR_RH_PORTSTAT(USBPORTSC_PEC);
|
||||
OK(0);
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
if (!(inw(port_addr) & USBPORTSC_SUSP)) {
|
||||
if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) {
|
||||
|
||||
/* Make certain the port isn't suspended */
|
||||
uhci_finish_suspend(uhci, port, port_addr);
|
||||
|
|
@ -370,7 +368,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
* if the port is disabled. When this happens
|
||||
* just skip the Resume signalling.
|
||||
*/
|
||||
if (!(inw(port_addr) & USBPORTSC_RD))
|
||||
if (!(uhci_readw(uhci, port_addr) &
|
||||
USBPORTSC_RD))
|
||||
uhci_finish_suspend(uhci, port,
|
||||
port_addr);
|
||||
else
|
||||
|
|
|
|||
301
drivers/usb/host/uhci-pci.c
Normal file
301
drivers/usb/host/uhci-pci.c
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* UHCI HCD (Host Controller Driver) PCI Bus Glue.
|
||||
*
|
||||
* Extracted from uhci-hcd.c:
|
||||
* Maintainer: Alan Stern <stern@rowland.harvard.edu>
|
||||
*
|
||||
* (C) Copyright 1999 Linus Torvalds
|
||||
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
|
||||
* (C) Copyright 1999 Randy Dunlap
|
||||
* (C) Copyright 1999 Georg Acher, acher@in.tum.de
|
||||
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
|
||||
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
|
||||
* (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
|
||||
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
|
||||
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
|
||||
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
|
||||
* (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
|
||||
*/
|
||||
|
||||
#include "pci-quirks.h"
|
||||
|
||||
/*
|
||||
* Make sure the controller is completely inactive, unable to
|
||||
* generate interrupts or do DMA.
|
||||
*/
|
||||
static void uhci_pci_reset_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a controller that was newly discovered or has just been
|
||||
* resumed. In either case we can't be sure of its previous state.
|
||||
*
|
||||
* Returns: 1 if the controller was reset, 0 otherwise.
|
||||
*/
|
||||
static int uhci_pci_check_and_reset_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
return uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)),
|
||||
uhci->io_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the basic register settings needed by the controller.
|
||||
* This function is called at the end of configure_hc in uhci-hcd.c.
|
||||
*/
|
||||
static void uhci_pci_configure_hc(struct uhci_hcd *uhci)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
|
||||
|
||||
/* Enable PIRQ */
|
||||
pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
|
||||
|
||||
/* Disable platform-specific non-PME# wakeup */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
pci_write_config_byte(pdev, USBRES_INTEL, 0);
|
||||
}
|
||||
|
||||
static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
|
||||
switch (to_pci_dev(uhci_dev(uhci))->vendor) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case PCI_VENDOR_ID_GENESYS:
|
||||
/* Genesys Logic's GL880S controllers don't generate
|
||||
* resume-detect interrupts.
|
||||
*/
|
||||
return 1;
|
||||
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
/* Some of Intel's USB controllers have a bug that causes
|
||||
* resume-detect interrupts if any port has an over-current
|
||||
* condition. To make matters worse, some motherboards
|
||||
* hardwire unused USB ports' over-current inputs active!
|
||||
* To prevent problems, we will not enable resume-detect
|
||||
* interrupts if any ports are OC.
|
||||
*/
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
|
||||
USBPORTSC_OC)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uhci_pci_global_suspend_mode_is_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
const char *sys_info;
|
||||
static const char bad_Asus_board[] = "A7V8X";
|
||||
|
||||
/* One of Asus's motherboards has a bug which causes it to
|
||||
* wake up immediately from suspend-to-RAM if any of the ports
|
||||
* are connected. In such cases we will not set EGSM.
|
||||
*/
|
||||
sys_info = dmi_get_system_info(DMI_BOARD_NAME);
|
||||
if (sys_info && !strcmp(sys_info, bad_Asus_board)) {
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
|
||||
USBPORTSC_CCS)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uhci_pci_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
|
||||
uhci->io_addr = (unsigned long) hcd->rsrc_start;
|
||||
|
||||
uhci->rh_numports = uhci_count_ports(hcd);
|
||||
|
||||
/* Intel controllers report the OverCurrent bit active on.
|
||||
* VIA controllers report it active off, so we'll adjust the
|
||||
* bit value. (It's not standardized in the UHCI spec.)
|
||||
*/
|
||||
if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA)
|
||||
uhci->oc_low = 1;
|
||||
|
||||
/* HP's server management chip requires a longer port reset delay. */
|
||||
if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP)
|
||||
uhci->wait_for_hp = 1;
|
||||
|
||||
/* Set up pointers to PCI-specific functions */
|
||||
uhci->reset_hc = uhci_pci_reset_hc;
|
||||
uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc;
|
||||
uhci->configure_hc = uhci_pci_configure_hc;
|
||||
uhci->resume_detect_interrupts_are_broken =
|
||||
uhci_pci_resume_detect_interrupts_are_broken;
|
||||
uhci->global_suspend_mode_is_broken =
|
||||
uhci_pci_global_suspend_mode_is_broken;
|
||||
|
||||
|
||||
/* Kick BIOS off this hardware and reset if the controller
|
||||
* isn't already safely quiescent.
|
||||
*/
|
||||
check_and_reset_hc(uhci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the controller is quiescent and that we're not using it
|
||||
* any more. This is mainly for the benefit of programs which, like kexec,
|
||||
* expect the hardware to be idle: not doing DMA or generating IRQs.
|
||||
*
|
||||
* This routine may be called in a damaged or failing kernel. Hence we
|
||||
* do not acquire the spinlock before shutting down the controller.
|
||||
*/
|
||||
static void uhci_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pdev);
|
||||
|
||||
uhci_hc_died(hcd_to_uhci(hcd));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
|
||||
|
||||
spin_lock_irq(&uhci->lock);
|
||||
if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
|
||||
goto done_okay; /* Already suspended or dead */
|
||||
|
||||
if (uhci->rh_state > UHCI_RH_SUSPENDED) {
|
||||
dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
|
||||
rc = -EBUSY;
|
||||
goto done;
|
||||
};
|
||||
|
||||
/* All PCI host controllers are required to disable IRQ generation
|
||||
* at the source, so we must turn off PIRQ.
|
||||
*/
|
||||
pci_write_config_word(pdev, USBLEGSUP, 0);
|
||||
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
|
||||
/* Enable platform-specific non-PME# wakeup */
|
||||
if (do_wakeup) {
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
pci_write_config_byte(pdev, USBRES_INTEL,
|
||||
USBPORT1EN | USBPORT2EN);
|
||||
}
|
||||
|
||||
done_okay:
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
done:
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
|
||||
|
||||
/* Since we aren't in D3 any more, it's safe to set this flag
|
||||
* even if the controller was dead.
|
||||
*/
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
spin_lock_irq(&uhci->lock);
|
||||
|
||||
/* Make sure resume from hibernation re-enumerates everything */
|
||||
if (hibernated) {
|
||||
uhci->reset_hc(uhci);
|
||||
finish_reset(uhci);
|
||||
}
|
||||
|
||||
/* The firmware may have changed the controller settings during
|
||||
* a system wakeup. Check it and reconfigure to avoid problems.
|
||||
*/
|
||||
else {
|
||||
check_and_reset_hc(uhci);
|
||||
}
|
||||
configure_hc(uhci);
|
||||
|
||||
/* Tell the core if the controller had to be reset */
|
||||
if (uhci->rh_state == UHCI_RH_RESET)
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
|
||||
/* If interrupts don't work and remote wakeup is enabled then
|
||||
* the suspended root hub needs to be polled.
|
||||
*/
|
||||
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
|
||||
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
|
||||
/* Does the root hub have a port wakeup pending? */
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct hc_driver uhci_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "UHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct uhci_hcd),
|
||||
|
||||
/* Generic hardware linkage */
|
||||
.irq = uhci_irq,
|
||||
.flags = HCD_USB11,
|
||||
|
||||
/* Basic lifecycle operations */
|
||||
.reset = uhci_pci_init,
|
||||
.start = uhci_start,
|
||||
#ifdef CONFIG_PM
|
||||
.pci_suspend = uhci_pci_suspend,
|
||||
.pci_resume = uhci_pci_resume,
|
||||
.bus_suspend = uhci_rh_suspend,
|
||||
.bus_resume = uhci_rh_resume,
|
||||
#endif
|
||||
.stop = uhci_stop,
|
||||
|
||||
.urb_enqueue = uhci_urb_enqueue,
|
||||
.urb_dequeue = uhci_urb_dequeue,
|
||||
|
||||
.endpoint_disable = uhci_hcd_endpoint_disable,
|
||||
.get_frame_number = uhci_hcd_get_frame_number,
|
||||
|
||||
.hub_status_data = uhci_hub_status_data,
|
||||
.hub_control = uhci_hub_control,
|
||||
};
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(uhci_pci_ids) = { {
|
||||
/* handle any USB UHCI controller */
|
||||
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),
|
||||
.driver_data = (unsigned long) &uhci_driver,
|
||||
}, { /* end: all zeroes */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
|
||||
|
||||
static struct pci_driver uhci_pci_driver = {
|
||||
.name = (char *)hcd_name,
|
||||
.id_table = uhci_pci_ids,
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = uhci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
|
@ -29,12 +29,12 @@ static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
|
|||
{
|
||||
if (uhci->is_stopped)
|
||||
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
|
||||
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
|
||||
uhci->term_td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
|
||||
}
|
||||
|
||||
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
|
||||
{
|
||||
uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
|
||||
uhci->term_td->status &= ~cpu_to_hc32(uhci, TD_CTRL_IOC);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ static void uhci_fsbr_on(struct uhci_hcd *uhci)
|
|||
uhci->fsbr_is_on = 1;
|
||||
lqh = list_entry(uhci->skel_async_qh->node.prev,
|
||||
struct uhci_qh, node);
|
||||
lqh->link = LINK_TO_QH(uhci->skel_term_qh);
|
||||
lqh->link = LINK_TO_QH(uhci, uhci->skel_term_qh);
|
||||
}
|
||||
|
||||
static void uhci_fsbr_off(struct uhci_hcd *uhci)
|
||||
|
|
@ -65,7 +65,7 @@ static void uhci_fsbr_off(struct uhci_hcd *uhci)
|
|||
uhci->fsbr_is_on = 0;
|
||||
lqh = list_entry(uhci->skel_async_qh->node.prev,
|
||||
struct uhci_qh, node);
|
||||
lqh->link = UHCI_PTR_TERM;
|
||||
lqh->link = UHCI_PTR_TERM(uhci);
|
||||
}
|
||||
|
||||
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
|
||||
|
|
@ -131,12 +131,12 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
|
|||
dma_pool_free(uhci->td_pool, td, td->dma_handle);
|
||||
}
|
||||
|
||||
static inline void uhci_fill_td(struct uhci_td *td, u32 status,
|
||||
u32 token, u32 buffer)
|
||||
static inline void uhci_fill_td(struct uhci_hcd *uhci, struct uhci_td *td,
|
||||
u32 status, u32 token, u32 buffer)
|
||||
{
|
||||
td->status = cpu_to_le32(status);
|
||||
td->token = cpu_to_le32(token);
|
||||
td->buffer = cpu_to_le32(buffer);
|
||||
td->status = cpu_to_hc32(uhci, status);
|
||||
td->token = cpu_to_hc32(uhci, token);
|
||||
td->buffer = cpu_to_hc32(uhci, buffer);
|
||||
}
|
||||
|
||||
static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
|
||||
|
|
@ -170,11 +170,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
|
|||
|
||||
td->link = ltd->link;
|
||||
wmb();
|
||||
ltd->link = LINK_TO_TD(td);
|
||||
ltd->link = LINK_TO_TD(uhci, td);
|
||||
} else {
|
||||
td->link = uhci->frame[framenum];
|
||||
wmb();
|
||||
uhci->frame[framenum] = LINK_TO_TD(td);
|
||||
uhci->frame[framenum] = LINK_TO_TD(uhci, td);
|
||||
uhci->frame_cpu[framenum] = td;
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
|
|||
ntd = list_entry(td->fl_list.next,
|
||||
struct uhci_td,
|
||||
fl_list);
|
||||
uhci->frame[td->frame] = LINK_TO_TD(ntd);
|
||||
uhci->frame[td->frame] = LINK_TO_TD(uhci, ntd);
|
||||
uhci->frame_cpu[td->frame] = ntd;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -255,8 +255,8 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
|
|||
memset(qh, 0, sizeof(*qh));
|
||||
qh->dma_handle = dma_handle;
|
||||
|
||||
qh->element = UHCI_PTR_TERM;
|
||||
qh->link = UHCI_PTR_TERM;
|
||||
qh->element = UHCI_PTR_TERM(uhci);
|
||||
qh->link = UHCI_PTR_TERM(uhci);
|
||||
|
||||
INIT_LIST_HEAD(&qh->queue);
|
||||
INIT_LIST_HEAD(&qh->node);
|
||||
|
|
@ -348,9 +348,9 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
|
|||
|
||||
/* If the QH element pointer is UHCI_PTR_TERM then then currently
|
||||
* executing URB has already been unlinked, so this one isn't it. */
|
||||
if (qh_element(qh) == UHCI_PTR_TERM)
|
||||
if (qh_element(qh) == UHCI_PTR_TERM(uhci))
|
||||
goto done;
|
||||
qh->element = UHCI_PTR_TERM;
|
||||
qh->element = UHCI_PTR_TERM(uhci);
|
||||
|
||||
/* Control pipes don't have to worry about toggles */
|
||||
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
|
||||
|
|
@ -360,7 +360,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
|
|||
WARN_ON(list_empty(&urbp->td_list));
|
||||
td = list_entry(urbp->td_list.next, struct uhci_td, list);
|
||||
qh->needs_fixup = 1;
|
||||
qh->initial_toggle = uhci_toggle(td_token(td));
|
||||
qh->initial_toggle = uhci_toggle(td_token(uhci, td));
|
||||
|
||||
done:
|
||||
return ret;
|
||||
|
|
@ -370,7 +370,8 @@ done:
|
|||
* Fix up the data toggles for URBs in a queue, when one of them
|
||||
* terminates early (short transfer, error, or dequeued).
|
||||
*/
|
||||
static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
|
||||
static void uhci_fixup_toggles(struct uhci_hcd *uhci, struct uhci_qh *qh,
|
||||
int skip_first)
|
||||
{
|
||||
struct urb_priv *urbp = NULL;
|
||||
struct uhci_td *td;
|
||||
|
|
@ -384,7 +385,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
|
|||
|
||||
/* When starting with the first URB, if the QH element pointer is
|
||||
* still valid then we know the URB's toggles are okay. */
|
||||
else if (qh_element(qh) != UHCI_PTR_TERM)
|
||||
else if (qh_element(qh) != UHCI_PTR_TERM(uhci))
|
||||
toggle = 2;
|
||||
|
||||
/* Fix up the toggle for the URBs in the queue. Normally this
|
||||
|
|
@ -396,15 +397,15 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
|
|||
/* If the first TD has the right toggle value, we don't
|
||||
* need to change any toggles in this URB */
|
||||
td = list_entry(urbp->td_list.next, struct uhci_td, list);
|
||||
if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
|
||||
if (toggle > 1 || uhci_toggle(td_token(uhci, td)) == toggle) {
|
||||
td = list_entry(urbp->td_list.prev, struct uhci_td,
|
||||
list);
|
||||
toggle = uhci_toggle(td_token(td)) ^ 1;
|
||||
toggle = uhci_toggle(td_token(uhci, td)) ^ 1;
|
||||
|
||||
/* Otherwise all the toggles in the URB have to be switched */
|
||||
} else {
|
||||
list_for_each_entry(td, &urbp->td_list, list) {
|
||||
td->token ^= cpu_to_le32(
|
||||
td->token ^= cpu_to_hc32(uhci,
|
||||
TD_TOKEN_TOGGLE);
|
||||
toggle ^= 1;
|
||||
}
|
||||
|
|
@ -441,7 +442,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
|
||||
qh->link = pqh->link;
|
||||
wmb();
|
||||
pqh->link = LINK_TO_QH(qh);
|
||||
pqh->link = LINK_TO_QH(uhci, qh);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -451,7 +452,7 @@ static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
||||
{
|
||||
struct uhci_qh *pqh;
|
||||
__le32 link_to_new_qh;
|
||||
__hc32 link_to_new_qh;
|
||||
|
||||
/* Find the predecessor QH for our new one and insert it in the list.
|
||||
* The list of QHs is expected to be short, so linear search won't
|
||||
|
|
@ -465,7 +466,7 @@ static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
/* Link it into the schedule */
|
||||
qh->link = pqh->link;
|
||||
wmb();
|
||||
link_to_new_qh = LINK_TO_QH(qh);
|
||||
link_to_new_qh = LINK_TO_QH(uhci, qh);
|
||||
pqh->link = link_to_new_qh;
|
||||
|
||||
/* If this is now the first FSBR QH, link the terminating skeleton
|
||||
|
|
@ -483,13 +484,13 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
|
||||
/* Set the element pointer if it isn't set already.
|
||||
* This isn't needed for Isochronous queues, but it doesn't hurt. */
|
||||
if (qh_element(qh) == UHCI_PTR_TERM) {
|
||||
if (qh_element(qh) == UHCI_PTR_TERM(uhci)) {
|
||||
struct urb_priv *urbp = list_entry(qh->queue.next,
|
||||
struct urb_priv, node);
|
||||
struct uhci_td *td = list_entry(urbp->td_list.next,
|
||||
struct uhci_td, list);
|
||||
|
||||
qh->element = LINK_TO_TD(td);
|
||||
qh->element = LINK_TO_TD(uhci, td);
|
||||
}
|
||||
|
||||
/* Treat the queue as if it has just advanced */
|
||||
|
|
@ -533,7 +534,7 @@ static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
||||
{
|
||||
struct uhci_qh *pqh;
|
||||
__le32 link_to_next_qh = qh->link;
|
||||
__hc32 link_to_next_qh = qh->link;
|
||||
|
||||
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
|
||||
pqh->link = link_to_next_qh;
|
||||
|
|
@ -757,8 +758,8 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
|
|||
/*
|
||||
* Map status to standard result codes
|
||||
*
|
||||
* <status> is (td_status(td) & 0xF60000), a.k.a.
|
||||
* uhci_status_bits(td_status(td)).
|
||||
* <status> is (td_status(uhci, td) & 0xF60000), a.k.a.
|
||||
* uhci_status_bits(td_status(uhci, td)).
|
||||
* Note: <status> does not include the TD_CTRL_NAK bit.
|
||||
* <dir_out> is True for output TDs and False for input TDs.
|
||||
*/
|
||||
|
|
@ -794,7 +795,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int len = urb->transfer_buffer_length;
|
||||
dma_addr_t data = urb->transfer_dma;
|
||||
__le32 *plink;
|
||||
__hc32 *plink;
|
||||
struct urb_priv *urbp = urb->hcpriv;
|
||||
int skel;
|
||||
|
||||
|
|
@ -811,7 +812,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
*/
|
||||
td = qh->dummy_td;
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(8),
|
||||
uhci_fill_td(uhci, td, status, destination | uhci_explen(8),
|
||||
urb->setup_dma);
|
||||
plink = &td->link;
|
||||
status |= TD_CTRL_ACTIVE;
|
||||
|
|
@ -844,14 +845,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
|
||||
/* Alternate Data0/1 (start with Data1) */
|
||||
destination ^= TD_TOKEN_TOGGLE;
|
||||
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(pktsze),
|
||||
data);
|
||||
uhci_fill_td(uhci, td, status,
|
||||
destination | uhci_explen(pktsze), data);
|
||||
plink = &td->link;
|
||||
|
||||
data += pktsze;
|
||||
|
|
@ -864,14 +865,14 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
|
||||
/* Change direction for the status transaction */
|
||||
destination ^= (USB_PID_IN ^ USB_PID_OUT);
|
||||
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
|
||||
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status | TD_CTRL_IOC,
|
||||
uhci_fill_td(uhci, td, status | TD_CTRL_IOC,
|
||||
destination | uhci_explen(0), 0);
|
||||
plink = &td->link;
|
||||
|
||||
|
|
@ -881,11 +882,11 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
|
||||
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
wmb();
|
||||
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
|
||||
qh->dummy_td = td;
|
||||
|
||||
/* Low-speed transfers get a different queue, and won't hog the bus.
|
||||
|
|
@ -921,7 +922,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
int len = urb->transfer_buffer_length;
|
||||
int this_sg_len;
|
||||
dma_addr_t data;
|
||||
__le32 *plink;
|
||||
__hc32 *plink;
|
||||
struct urb_priv *urbp = urb->hcpriv;
|
||||
unsigned int toggle;
|
||||
struct scatterlist *sg;
|
||||
|
|
@ -974,10 +975,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
}
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status,
|
||||
uhci_fill_td(uhci, td, status,
|
||||
destination | uhci_explen(pktsze) |
|
||||
(toggle << TD_TOKEN_TOGGLE_SHIFT),
|
||||
data);
|
||||
|
|
@ -1010,10 +1011,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status,
|
||||
uhci_fill_td(uhci, td, status,
|
||||
destination | uhci_explen(0) |
|
||||
(toggle << TD_TOKEN_TOGGLE_SHIFT),
|
||||
data);
|
||||
|
|
@ -1028,7 +1029,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
* fast side but not enough to justify delaying an interrupt
|
||||
* more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
|
||||
* flag setting. */
|
||||
td->status |= cpu_to_le32(TD_CTRL_IOC);
|
||||
td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
|
||||
|
||||
/*
|
||||
* Build the new dummy TD and activate the old one
|
||||
|
|
@ -1036,11 +1037,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
td = uhci_alloc_td(uhci);
|
||||
if (!td)
|
||||
goto nomem;
|
||||
*plink = LINK_TO_TD(td);
|
||||
*plink = LINK_TO_TD(uhci, td);
|
||||
|
||||
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
wmb();
|
||||
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE);
|
||||
qh->dummy_td = td;
|
||||
|
||||
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
|
||||
|
|
@ -1133,7 +1134,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
|
|||
* the queue at the status stage transaction, which is
|
||||
* the last TD. */
|
||||
WARN_ON(list_empty(&urbp->td_list));
|
||||
qh->element = LINK_TO_TD(td);
|
||||
qh->element = LINK_TO_TD(uhci, td);
|
||||
tmp = td->list.prev;
|
||||
ret = -EINPROGRESS;
|
||||
|
||||
|
|
@ -1142,8 +1143,9 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
|
|||
/* When a bulk/interrupt transfer is short, we have to
|
||||
* fix up the toggles of the following URBs on the queue
|
||||
* before restarting the queue at the next URB. */
|
||||
qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1;
|
||||
uhci_fixup_toggles(qh, 1);
|
||||
qh->initial_toggle =
|
||||
uhci_toggle(td_token(uhci, qh->post_td)) ^ 1;
|
||||
uhci_fixup_toggles(uhci, qh, 1);
|
||||
|
||||
if (list_empty(&urbp->td_list))
|
||||
td = qh->post_td;
|
||||
|
|
@ -1178,7 +1180,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
|
|||
unsigned int ctrlstat;
|
||||
int len;
|
||||
|
||||
ctrlstat = td_status(td);
|
||||
ctrlstat = td_status(uhci, td);
|
||||
status = uhci_status_bits(ctrlstat);
|
||||
if (status & TD_CTRL_ACTIVE)
|
||||
return -EINPROGRESS;
|
||||
|
|
@ -1188,7 +1190,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
|
|||
|
||||
if (status) {
|
||||
ret = uhci_map_status(status,
|
||||
uhci_packetout(td_token(td)));
|
||||
uhci_packetout(td_token(uhci, td)));
|
||||
if ((debug == 1 && ret != -EPIPE) || debug > 1) {
|
||||
/* Some debugging code */
|
||||
dev_dbg(&urb->dev->dev,
|
||||
|
|
@ -1204,7 +1206,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
|
|||
}
|
||||
|
||||
/* Did we receive a short packet? */
|
||||
} else if (len < uhci_expected_length(td_token(td))) {
|
||||
} else if (len < uhci_expected_length(td_token(uhci, td))) {
|
||||
|
||||
/* For control transfers, go to the status TD if
|
||||
* this isn't already the last data TD */
|
||||
|
|
@ -1236,10 +1238,10 @@ err:
|
|||
if (ret < 0) {
|
||||
/* Note that the queue has stopped and save
|
||||
* the next toggle value */
|
||||
qh->element = UHCI_PTR_TERM;
|
||||
qh->element = UHCI_PTR_TERM(uhci);
|
||||
qh->is_stopped = 1;
|
||||
qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL);
|
||||
qh->initial_toggle = uhci_toggle(td_token(td)) ^
|
||||
qh->initial_toggle = uhci_toggle(td_token(uhci, td)) ^
|
||||
(ret == -EREMOTEIO);
|
||||
|
||||
} else /* Short packet received */
|
||||
|
|
@ -1335,14 +1337,14 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
|
|||
return -ENOMEM;
|
||||
|
||||
uhci_add_td_to_urbp(td, urbp);
|
||||
uhci_fill_td(td, status, destination |
|
||||
uhci_fill_td(uhci, td, status, destination |
|
||||
uhci_explen(urb->iso_frame_desc[i].length),
|
||||
urb->transfer_dma +
|
||||
urb->iso_frame_desc[i].offset);
|
||||
}
|
||||
|
||||
/* Set the interrupt-on-completion flag on the last packet. */
|
||||
td->status |= cpu_to_le32(TD_CTRL_IOC);
|
||||
td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
|
||||
|
||||
/* Add the TDs to the frame list */
|
||||
frame = urb->start_frame;
|
||||
|
|
@ -1378,7 +1380,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
|
|||
|
||||
uhci_remove_tds_from_frame(uhci, qh->iso_frame);
|
||||
|
||||
ctrlstat = td_status(td);
|
||||
ctrlstat = td_status(uhci, td);
|
||||
if (ctrlstat & TD_CTRL_ACTIVE) {
|
||||
status = -EXDEV; /* TD was added too late? */
|
||||
} else {
|
||||
|
|
@ -1629,7 +1631,7 @@ restart:
|
|||
* queue, the QH can now be re-activated. */
|
||||
if (!list_empty(&qh->queue)) {
|
||||
if (qh->needs_fixup)
|
||||
uhci_fixup_toggles(qh, 0);
|
||||
uhci_fixup_toggles(uhci, qh, 0);
|
||||
|
||||
/* If the first URB on the queue wants FSBR but its time
|
||||
* limit has expired, set the next TD to interrupt on
|
||||
|
|
@ -1639,7 +1641,7 @@ restart:
|
|||
struct uhci_td *td = list_entry(urbp->td_list.next,
|
||||
struct uhci_td, list);
|
||||
|
||||
td->status |= __cpu_to_le32(TD_CTRL_IOC);
|
||||
td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC);
|
||||
}
|
||||
|
||||
uhci_activate_qh(uhci, qh);
|
||||
|
|
@ -1686,7 +1688,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
} else {
|
||||
urbp = list_entry(qh->queue.next, struct urb_priv, node);
|
||||
td = list_entry(urbp->td_list.next, struct uhci_td, list);
|
||||
status = td_status(td);
|
||||
status = td_status(uhci, td);
|
||||
if (!(status & TD_CTRL_ACTIVE)) {
|
||||
|
||||
/* We're okay, the queue has advanced */
|
||||
|
|
@ -1704,7 +1706,8 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
|
|||
if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
|
||||
|
||||
/* Detect the Intel bug and work around it */
|
||||
if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) {
|
||||
if (qh->post_td && qh_element(qh) ==
|
||||
LINK_TO_TD(uhci, qh->post_td)) {
|
||||
qh->element = qh->post_td->link;
|
||||
qh->advance_jiffies = jiffies;
|
||||
ret = 1;
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ static void xhci_print_op_regs(struct xhci_hcd *xhci)
|
|||
|
||||
static void xhci_print_ports(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 __iomem *addr;
|
||||
__le32 __iomem *addr;
|
||||
int i, j;
|
||||
int ports;
|
||||
char *names[NUM_PORT_REGS] = {
|
||||
|
|
@ -253,27 +253,27 @@ void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
|
|||
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
{
|
||||
u64 address;
|
||||
u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
|
||||
u32 type = le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK;
|
||||
|
||||
switch (type) {
|
||||
case TRB_TYPE(TRB_LINK):
|
||||
xhci_dbg(xhci, "Link TRB:\n");
|
||||
xhci_print_trb_offsets(xhci, trb);
|
||||
|
||||
address = trb->link.segment_ptr;
|
||||
address = le64_to_cpu(trb->link.segment_ptr);
|
||||
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
|
||||
|
||||
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
|
||||
GET_INTR_TARGET(trb->link.intr_target));
|
||||
GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
|
||||
xhci_dbg(xhci, "Cycle bit = %u\n",
|
||||
(unsigned int) (trb->link.control & TRB_CYCLE));
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE));
|
||||
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
|
||||
(unsigned int) (trb->link.control & LINK_TOGGLE));
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE));
|
||||
xhci_dbg(xhci, "No Snoop bit = %u\n",
|
||||
(unsigned int) (trb->link.control & TRB_NO_SNOOP));
|
||||
(unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP));
|
||||
break;
|
||||
case TRB_TYPE(TRB_TRANSFER):
|
||||
address = trb->trans_event.buffer;
|
||||
address = le64_to_cpu(trb->trans_event.buffer);
|
||||
/*
|
||||
* FIXME: look at flags to figure out if it's an address or if
|
||||
* the data is directly in the buffer field.
|
||||
|
|
@ -281,11 +281,12 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
|||
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
|
||||
break;
|
||||
case TRB_TYPE(TRB_COMPLETION):
|
||||
address = trb->event_cmd.cmd_trb;
|
||||
address = le64_to_cpu(trb->event_cmd.cmd_trb);
|
||||
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
|
||||
xhci_dbg(xhci, "Completion status = %u\n",
|
||||
(unsigned int) GET_COMP_CODE(trb->event_cmd.status));
|
||||
xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
|
||||
(unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
|
||||
xhci_dbg(xhci, "Flags = 0x%x\n",
|
||||
(unsigned int) le32_to_cpu(trb->event_cmd.flags));
|
||||
break;
|
||||
default:
|
||||
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
|
||||
|
|
@ -311,16 +312,16 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
|||
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
{
|
||||
int i;
|
||||
u32 addr = (u32) seg->dma;
|
||||
u64 addr = seg->dma;
|
||||
union xhci_trb *trb = seg->trbs;
|
||||
|
||||
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
|
||||
trb = &seg->trbs[i];
|
||||
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
|
||||
lower_32_bits(trb->link.segment_ptr),
|
||||
upper_32_bits(trb->link.segment_ptr),
|
||||
(unsigned int) trb->link.intr_target,
|
||||
(unsigned int) trb->link.control);
|
||||
xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
|
||||
(u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
(u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
||||
(unsigned int) le32_to_cpu(trb->link.intr_target),
|
||||
(unsigned int) le32_to_cpu(trb->link.control));
|
||||
addr += sizeof(*trb);
|
||||
}
|
||||
}
|
||||
|
|
@ -391,18 +392,18 @@ void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
|
|||
|
||||
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
|
||||
{
|
||||
u32 addr = (u32) erst->erst_dma_addr;
|
||||
u64 addr = erst->erst_dma_addr;
|
||||
int i;
|
||||
struct xhci_erst_entry *entry;
|
||||
|
||||
for (i = 0; i < erst->num_entries; ++i) {
|
||||
entry = &erst->entries[i];
|
||||
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
|
||||
(unsigned int) addr,
|
||||
lower_32_bits(entry->seg_addr),
|
||||
upper_32_bits(entry->seg_addr),
|
||||
(unsigned int) entry->seg_size,
|
||||
(unsigned int) entry->rsvd);
|
||||
xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n",
|
||||
addr,
|
||||
lower_32_bits(le64_to_cpu(entry->seg_addr)),
|
||||
upper_32_bits(le64_to_cpu(entry->seg_addr)),
|
||||
(unsigned int) le32_to_cpu(entry->seg_size),
|
||||
(unsigned int) le32_to_cpu(entry->rsvd));
|
||||
addr += sizeof(*entry);
|
||||
}
|
||||
}
|
||||
|
|
@ -436,7 +437,7 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
|
|||
{
|
||||
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
|
||||
|
||||
switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
|
||||
switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) {
|
||||
case 0:
|
||||
return "enabled/disabled";
|
||||
case 1:
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
|
|||
temp |= 0x0008;
|
||||
/* Bits 6:5 - no TTs in root ports */
|
||||
/* Bit 7 - no port indicators */
|
||||
desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
|
||||
desc->wHubCharacteristics = cpu_to_le16(temp);
|
||||
}
|
||||
|
||||
/* Fill in the USB 2.0 roothub descriptor */
|
||||
|
|
@ -314,7 +314,7 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
|
|||
}
|
||||
|
||||
static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
||||
u16 wIndex, u32 __iomem *addr, u32 port_status)
|
||||
u16 wIndex, __le32 __iomem *addr, u32 port_status)
|
||||
{
|
||||
/* Don't allow the USB core to disable SuperSpeed ports. */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
|
|
@ -331,7 +331,7 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
|||
}
|
||||
|
||||
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
|
||||
u16 wIndex, u32 __iomem *addr, u32 port_status)
|
||||
u16 wIndex, __le32 __iomem *addr, u32 port_status)
|
||||
{
|
||||
char *port_change_bit;
|
||||
u32 status;
|
||||
|
|
@ -341,6 +341,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
|
|||
status = PORT_RC;
|
||||
port_change_bit = "reset";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_BH_PORT_RESET:
|
||||
status = PORT_WRC;
|
||||
port_change_bit = "warm(BH) reset";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
status = PORT_CSC;
|
||||
port_change_bit = "connect";
|
||||
|
|
@ -357,6 +361,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
|
|||
status = PORT_PLC;
|
||||
port_change_bit = "suspend/resume";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_PORT_LINK_STATE:
|
||||
status = PORT_PLC;
|
||||
port_change_bit = "link state";
|
||||
break;
|
||||
default:
|
||||
/* Should never happen */
|
||||
return;
|
||||
|
|
@ -368,25 +376,36 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
|
|||
port_change_bit, wIndex, port_status);
|
||||
}
|
||||
|
||||
static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
|
||||
{
|
||||
int max_ports;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
max_ports = xhci->num_usb3_ports;
|
||||
*port_array = xhci->usb3_ports;
|
||||
} else {
|
||||
max_ports = xhci->num_usb2_ports;
|
||||
*port_array = xhci->usb2_ports;
|
||||
}
|
||||
|
||||
return max_ports;
|
||||
}
|
||||
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
u16 wIndex, char *buf, u16 wLength)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ports;
|
||||
int max_ports;
|
||||
unsigned long flags;
|
||||
u32 temp, temp1, status;
|
||||
int retval = 0;
|
||||
u32 __iomem **port_array;
|
||||
__le32 __iomem **port_array;
|
||||
int slot_id;
|
||||
struct xhci_bus_state *bus_state;
|
||||
u16 link_state = 0;
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
ports = xhci->num_usb3_ports;
|
||||
port_array = xhci->usb3_ports;
|
||||
} else {
|
||||
ports = xhci->num_usb2_ports;
|
||||
port_array = xhci->usb2_ports;
|
||||
}
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
|
@ -411,7 +430,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
(struct usb_hub_descriptor *) buf);
|
||||
break;
|
||||
case GetPortStatus:
|
||||
if (!wIndex || wIndex > ports)
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
status = 0;
|
||||
|
|
@ -422,9 +441,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
}
|
||||
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
|
||||
/* FIXME - should we return a port status value like the USB
|
||||
* 3.0 external hubs do?
|
||||
*/
|
||||
/* wPortChange bits */
|
||||
if (temp & PORT_CSC)
|
||||
status |= USB_PORT_STAT_C_CONNECTION << 16;
|
||||
|
|
@ -432,13 +448,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
status |= USB_PORT_STAT_C_ENABLE << 16;
|
||||
if ((temp & PORT_OCC))
|
||||
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||
/*
|
||||
* FIXME ignoring reset and USB 2.1/3.0 specific
|
||||
* changes
|
||||
*/
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U3
|
||||
&& (temp & PORT_POWER))
|
||||
status |= 1 << USB_PORT_FEAT_SUSPEND;
|
||||
if ((temp & PORT_RC))
|
||||
status |= USB_PORT_STAT_C_RESET << 16;
|
||||
/* USB3.0 only */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if ((temp & PORT_PLC))
|
||||
status |= USB_PORT_STAT_C_LINK_STATE << 16;
|
||||
if ((temp & PORT_WRC))
|
||||
status |= USB_PORT_STAT_C_BH_RESET << 16;
|
||||
}
|
||||
|
||||
if (hcd->speed != HCD_USB3) {
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U3
|
||||
&& (temp & PORT_POWER))
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
}
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
if ((temp & PORT_RESET) || !(temp & PORT_PE))
|
||||
goto error;
|
||||
|
|
@ -469,7 +493,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
&& (temp & PORT_POWER)
|
||||
&& (bus_state->suspended_ports & (1 << wIndex))) {
|
||||
bus_state->suspended_ports &= ~(1 << wIndex);
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
if (hcd->speed != HCD_USB3)
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
}
|
||||
if (temp & PORT_CONNECT) {
|
||||
status |= USB_PORT_STAT_CONNECTION;
|
||||
|
|
@ -481,16 +506,30 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
status |= USB_PORT_STAT_OVERCURRENT;
|
||||
if (temp & PORT_RESET)
|
||||
status |= USB_PORT_STAT_RESET;
|
||||
if (temp & PORT_POWER)
|
||||
status |= USB_PORT_STAT_POWER;
|
||||
if (temp & PORT_POWER) {
|
||||
if (hcd->speed == HCD_USB3)
|
||||
status |= USB_SS_PORT_STAT_POWER;
|
||||
else
|
||||
status |= USB_PORT_STAT_POWER;
|
||||
}
|
||||
/* Port Link State */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
/* resume state is a xHCI internal state.
|
||||
* Do not report it to usb core.
|
||||
*/
|
||||
if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
|
||||
status |= (temp & PORT_PLS_MASK);
|
||||
}
|
||||
if (bus_state->port_c_suspend & (1 << wIndex))
|
||||
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
||||
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
|
||||
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
|
||||
break;
|
||||
case SetPortFeature:
|
||||
if (wValue == USB_PORT_FEAT_LINK_STATE)
|
||||
link_state = (wIndex & 0xff00) >> 3;
|
||||
wIndex &= 0xff;
|
||||
if (!wIndex || wIndex > ports)
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
|
|
@ -537,6 +576,44 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
bus_state->suspended_ports |= 1 << wIndex;
|
||||
break;
|
||||
case USB_PORT_FEAT_LINK_STATE:
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
/* Software should not attempt to set
|
||||
* port link state above '5' (Rx.Detect) and the port
|
||||
* must be enabled.
|
||||
*/
|
||||
if ((temp & PORT_PE) == 0 ||
|
||||
(link_state > USB_SS_PORT_LS_RX_DETECT)) {
|
||||
xhci_warn(xhci, "Cannot set link state.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (link_state == USB_SS_PORT_LS_U3) {
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
wIndex + 1);
|
||||
if (slot_id) {
|
||||
/* unlock to execute stop endpoint
|
||||
* commands */
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
xhci_stop_device(xhci, slot_id, 1);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | link_state;
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20); /* wait device to enter */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
if (link_state == USB_SS_PORT_LS_U3)
|
||||
bus_state->suspended_ports |= 1 << wIndex;
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
/*
|
||||
* Turn on ports, even if there isn't per-port switching.
|
||||
|
|
@ -557,6 +634,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_BH_PORT_RESET:
|
||||
temp |= PORT_WR;
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -564,7 +647,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
break;
|
||||
case ClearPortFeature:
|
||||
if (!wIndex || wIndex > ports)
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
|
|
@ -584,35 +667,27 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
if (temp & XDEV_U3) {
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
xhci_readl(xhci, port_array[wIndex]);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
|
||||
temp = xhci_readl(xhci,
|
||||
port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
}
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci,
|
||||
port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
}
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
wIndex + 1);
|
||||
|
|
@ -625,9 +700,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
case USB_PORT_FEAT_C_SUSPEND:
|
||||
bus_state->port_c_suspend &= ~(1 << wIndex);
|
||||
case USB_PORT_FEAT_C_RESET:
|
||||
case USB_PORT_FEAT_C_BH_PORT_RESET:
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
case USB_PORT_FEAT_C_ENABLE:
|
||||
case USB_PORT_FEAT_C_PORT_LINK_STATE:
|
||||
xhci_clear_port_change_bit(xhci, wValue, wIndex,
|
||||
port_array[wIndex], temp);
|
||||
break;
|
||||
|
|
@ -663,29 +740,23 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
u32 mask;
|
||||
int i, retval;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ports;
|
||||
u32 __iomem **port_array;
|
||||
int max_ports;
|
||||
__le32 __iomem **port_array;
|
||||
struct xhci_bus_state *bus_state;
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
ports = xhci->num_usb3_ports;
|
||||
port_array = xhci->usb3_ports;
|
||||
} else {
|
||||
ports = xhci->num_usb2_ports;
|
||||
port_array = xhci->usb2_ports;
|
||||
}
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
||||
/* Initial status is no changes */
|
||||
retval = (ports + 8) / 8;
|
||||
retval = (max_ports + 8) / 8;
|
||||
memset(buf, 0, retval);
|
||||
status = 0;
|
||||
|
||||
mask = PORT_CSC | PORT_PEC | PORT_OCC;
|
||||
mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* For each port, did anything change? If so, set that bit in buf. */
|
||||
for (i = 0; i < ports; i++) {
|
||||
for (i = 0; i < max_ports; i++) {
|
||||
temp = xhci_readl(xhci, port_array[i]);
|
||||
if (temp == 0xffffffff) {
|
||||
retval = -ENODEV;
|
||||
|
|
@ -709,19 +780,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int max_ports, port_index;
|
||||
u32 __iomem **port_array;
|
||||
__le32 __iomem **port_array;
|
||||
struct xhci_bus_state *bus_state;
|
||||
unsigned long flags;
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
max_ports = xhci->num_usb3_ports;
|
||||
port_array = xhci->usb3_ports;
|
||||
xhci_dbg(xhci, "suspend USB 3.0 root hub\n");
|
||||
} else {
|
||||
max_ports = xhci->num_usb2_ports;
|
||||
port_array = xhci->usb2_ports;
|
||||
xhci_dbg(xhci, "suspend USB 2.0 root hub\n");
|
||||
}
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
|
@ -779,7 +842,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
|
||||
if (hcd->speed != HCD_USB3) {
|
||||
/* enable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
__le32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
/* Add one to the port status register address to get
|
||||
|
|
@ -801,20 +864,12 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int max_ports, port_index;
|
||||
u32 __iomem **port_array;
|
||||
__le32 __iomem **port_array;
|
||||
struct xhci_bus_state *bus_state;
|
||||
u32 temp;
|
||||
unsigned long flags;
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
max_ports = xhci->num_usb3_ports;
|
||||
port_array = xhci->usb3_ports;
|
||||
xhci_dbg(xhci, "resume USB 3.0 root hub\n");
|
||||
} else {
|
||||
max_ports = xhci->num_usb2_ports;
|
||||
port_array = xhci->usb2_ports;
|
||||
xhci_dbg(xhci, "resume USB 2.0 root hub\n");
|
||||
}
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
||||
if (time_before(jiffies, bus_state->next_statechange))
|
||||
|
|
@ -890,7 +945,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||
|
||||
if (hcd->speed != HCD_USB3) {
|
||||
/* disable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
__le32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
/* Add one to the port status register address to get
|
||||
|
|
|
|||
|
|
@ -89,16 +89,17 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
|
|||
return;
|
||||
prev->next = next;
|
||||
if (link_trbs) {
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.
|
||||
segment_ptr = cpu_to_le64(next->dma);
|
||||
|
||||
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
|
||||
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
|
||||
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
|
||||
val &= ~TRB_TYPE_BITMASK;
|
||||
val |= TRB_TYPE(TRB_LINK);
|
||||
/* Always set the chain bit with 0.95 hardware */
|
||||
if (xhci_link_trb_quirk(xhci))
|
||||
val |= TRB_CHAIN;
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
|
||||
}
|
||||
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
|
||||
(unsigned long long)prev->dma,
|
||||
|
|
@ -186,7 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
|||
|
||||
if (link_trbs) {
|
||||
/* See section 4.9.2.1 and 6.4.4.1 */
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.
|
||||
control |= cpu_to_le32(LINK_TOGGLE);
|
||||
xhci_dbg(xhci, "Wrote link toggle flag to"
|
||||
" segment %p (virtual), 0x%llx (DMA)\n",
|
||||
prev, (unsigned long long)prev->dma);
|
||||
|
|
@ -207,14 +209,13 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
|
|||
|
||||
rings_cached = virt_dev->num_rings_cached;
|
||||
if (rings_cached < XHCI_MAX_RINGS_CACHED) {
|
||||
virt_dev->num_rings_cached++;
|
||||
rings_cached = virt_dev->num_rings_cached;
|
||||
virt_dev->ring_cache[rings_cached] =
|
||||
virt_dev->eps[ep_index].ring;
|
||||
virt_dev->num_rings_cached++;
|
||||
xhci_dbg(xhci, "Cached old ring, "
|
||||
"%d ring%s cached\n",
|
||||
rings_cached,
|
||||
(rings_cached > 1) ? "s" : "");
|
||||
virt_dev->num_rings_cached,
|
||||
(virt_dev->num_rings_cached > 1) ? "s" : "");
|
||||
} else {
|
||||
xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
|
||||
xhci_dbg(xhci, "Ring cache full (%d rings), "
|
||||
|
|
@ -548,7 +549,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
|
|||
addr = cur_ring->first_seg->dma |
|
||||
SCT_FOR_CTX(SCT_PRI_TR) |
|
||||
cur_ring->cycle_state;
|
||||
stream_info->stream_ctx_array[cur_stream].stream_ring = addr;
|
||||
stream_info->stream_ctx_array[cur_stream].
|
||||
stream_ring = cpu_to_le64(addr);
|
||||
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
|
||||
cur_stream, (unsigned long long) addr);
|
||||
|
||||
|
|
@ -614,10 +616,10 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
|
|||
max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
|
||||
xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
|
||||
1 << (max_primary_streams + 1));
|
||||
ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
|
||||
ep_ctx->ep_info |= EP_MAXPSTREAMS(max_primary_streams);
|
||||
ep_ctx->ep_info |= EP_HAS_LSA;
|
||||
ep_ctx->deq = stream_info->ctx_array_dma;
|
||||
ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
|
||||
ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
|
||||
| EP_HAS_LSA);
|
||||
ep_ctx->deq = cpu_to_le64(stream_info->ctx_array_dma);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -630,10 +632,9 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
|
|||
struct xhci_virt_ep *ep)
|
||||
{
|
||||
dma_addr_t addr;
|
||||
ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
|
||||
ep_ctx->ep_info &= ~EP_HAS_LSA;
|
||||
ep_ctx->ep_info &= cpu_to_le32(~(EP_MAXPSTREAMS_MASK | EP_HAS_LSA));
|
||||
addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue);
|
||||
ep_ctx->deq = addr | ep->ring->cycle_state;
|
||||
ep_ctx->deq = cpu_to_le64(addr | ep->ring->cycle_state);
|
||||
}
|
||||
|
||||
/* Frees all stream contexts associated with the endpoint,
|
||||
|
|
@ -781,11 +782,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
|||
dev->udev = udev;
|
||||
|
||||
/* Point to output device context in dcbaa. */
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(dev->out_ctx->dma);
|
||||
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
|
||||
slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[slot_id],
|
||||
(unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
|
||||
slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[slot_id],
|
||||
(unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
|
|
@ -810,8 +811,9 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
|
|||
* configured device has reset, so all control transfers should have
|
||||
* been completed or cancelled before the reset.
|
||||
*/
|
||||
ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue);
|
||||
ep0_ctx->deq |= ep_ring->cycle_state;
|
||||
ep0_ctx->deq = cpu_to_le64(xhci_trb_virt_to_dma(ep_ring->enq_seg,
|
||||
ep_ring->enqueue)
|
||||
| ep_ring->cycle_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -885,24 +887,22 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||
slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
|
||||
|
||||
/* 2) New slot context and endpoint 0 context are valid*/
|
||||
ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
|
||||
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
|
||||
|
||||
/* 3) Only the control endpoint is valid - one endpoint context */
|
||||
slot_ctx->dev_info |= LAST_CTX(1);
|
||||
|
||||
slot_ctx->dev_info |= (u32) udev->route;
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS);
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS);
|
||||
break;
|
||||
case USB_SPEED_LOW:
|
||||
slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
|
||||
slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS);
|
||||
break;
|
||||
case USB_SPEED_WIRELESS:
|
||||
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
|
||||
|
|
@ -916,7 +916,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||
port_num = xhci_find_real_port_number(xhci, udev);
|
||||
if (!port_num)
|
||||
return -EINVAL;
|
||||
slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(port_num);
|
||||
slot_ctx->dev_info2 |= cpu_to_le32((u32) ROOT_HUB_PORT(port_num));
|
||||
/* Set the port number in the virtual_device to the faked port number */
|
||||
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
|
||||
top_dev = top_dev->parent)
|
||||
|
|
@ -927,31 +927,31 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||
|
||||
/* Is this a LS/FS device under an external HS hub? */
|
||||
if (udev->tt && udev->tt->hub->parent) {
|
||||
slot_ctx->tt_info = udev->tt->hub->slot_id;
|
||||
slot_ctx->tt_info |= udev->ttport << 8;
|
||||
slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id |
|
||||
(udev->ttport << 8));
|
||||
if (udev->tt->multi)
|
||||
slot_ctx->dev_info |= DEV_MTT;
|
||||
slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
|
||||
}
|
||||
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
|
||||
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
|
||||
|
||||
/* Step 4 - ring already allocated */
|
||||
/* Step 5 */
|
||||
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
|
||||
ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
|
||||
/*
|
||||
* XXX: Not sure about wireless USB devices.
|
||||
*/
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
ep0_ctx->ep_info2 |= MAX_PACKET(512);
|
||||
ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
/* USB core guesses at a 64-byte max packet first for FS devices */
|
||||
case USB_SPEED_FULL:
|
||||
ep0_ctx->ep_info2 |= MAX_PACKET(64);
|
||||
ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
|
||||
break;
|
||||
case USB_SPEED_LOW:
|
||||
ep0_ctx->ep_info2 |= MAX_PACKET(8);
|
||||
ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
|
||||
break;
|
||||
case USB_SPEED_WIRELESS:
|
||||
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
|
||||
|
|
@ -962,12 +962,10 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||
BUG();
|
||||
}
|
||||
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
|
||||
ep0_ctx->ep_info2 |= MAX_BURST(0);
|
||||
ep0_ctx->ep_info2 |= ERROR_COUNT(3);
|
||||
ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
|
||||
|
||||
ep0_ctx->deq =
|
||||
dev->eps[0].ring->first_seg->dma;
|
||||
ep0_ctx->deq |= dev->eps[0].ring->cycle_state;
|
||||
ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma |
|
||||
dev->eps[0].ring->cycle_state);
|
||||
|
||||
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
|
||||
|
||||
|
|
@ -1046,12 +1044,12 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
|||
break;
|
||||
|
||||
case USB_SPEED_FULL:
|
||||
if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
interval = xhci_parse_exponent_interval(udev, ep);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Fall through for isochronous endpoint interval decoding
|
||||
* Fall through for interrupt endpoint interval decoding
|
||||
* since it uses the same rules as low speed interrupt
|
||||
* endpoints.
|
||||
*/
|
||||
|
|
@ -1131,10 +1129,10 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
|
|||
return 0;
|
||||
|
||||
if (udev->speed == USB_SPEED_SUPER)
|
||||
return ep->ss_ep_comp.wBytesPerInterval;
|
||||
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
|
||||
|
||||
max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
|
||||
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
|
||||
/* A 0 in max burst means 1 transfer per ESIT */
|
||||
return max_packet * (max_burst + 1);
|
||||
}
|
||||
|
|
@ -1183,33 +1181,33 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
}
|
||||
virt_dev->eps[ep_index].skip = false;
|
||||
ep_ring = virt_dev->eps[ep_index].new_ring;
|
||||
ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
|
||||
ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state);
|
||||
|
||||
ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
|
||||
ep_ctx->ep_info |= EP_MULT(xhci_get_endpoint_mult(udev, ep));
|
||||
ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep)
|
||||
| EP_MULT(xhci_get_endpoint_mult(udev, ep)));
|
||||
|
||||
/* FIXME dig Mult and streams info out of ep companion desc */
|
||||
|
||||
/* Allow 3 retries for everything but isoc;
|
||||
* error count = 0 means infinite retries.
|
||||
* CErr shall be set to 0 for Isoch endpoints.
|
||||
*/
|
||||
if (!usb_endpoint_xfer_isoc(&ep->desc))
|
||||
ep_ctx->ep_info2 = ERROR_COUNT(3);
|
||||
ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3));
|
||||
else
|
||||
ep_ctx->ep_info2 = ERROR_COUNT(1);
|
||||
ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(0));
|
||||
|
||||
ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep));
|
||||
|
||||
/* Set the max packet size and max burst */
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
max_packet = ep->desc.wMaxPacketSize;
|
||||
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
|
||||
max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
/* dig out max burst from ep companion desc */
|
||||
max_packet = ep->ss_ep_comp.bMaxBurst;
|
||||
if (!max_packet)
|
||||
xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
|
||||
ep_ctx->ep_info2 |= MAX_BURST(max_packet);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
/* bits 11:12 specify the number of additional transaction
|
||||
|
|
@ -1217,20 +1215,21 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc)) {
|
||||
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
|
||||
ep_ctx->ep_info2 |= MAX_BURST(max_burst);
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
|
||||
& 0x1800) >> 11;
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
|
||||
}
|
||||
/* Fall through */
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
|
||||
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep);
|
||||
ep_ctx->tx_info = MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload);
|
||||
ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
|
||||
|
||||
/*
|
||||
* XXX no idea how to calculate the average TRB buffer length for bulk
|
||||
|
|
@ -1246,8 +1245,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
* including link TRBs, No-op TRBs, and Event data TRBs. Since we don't
|
||||
* use Event Data TRBs, and we don't chain in a link TRB on short
|
||||
* transfers, we're basically dividing by 1.
|
||||
*
|
||||
* xHCI 1.0 specification indicates that the Average TRB Length should
|
||||
* be set to 8 for control endpoints.
|
||||
*/
|
||||
ep_ctx->tx_info |= AVG_TRB_LENGTH_FOR_EP(max_esit_payload);
|
||||
if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100)
|
||||
ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
|
||||
else
|
||||
ep_ctx->tx_info |=
|
||||
cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload));
|
||||
|
||||
/* FIXME Debug endpoint context */
|
||||
return 0;
|
||||
|
|
@ -1347,7 +1353,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
|||
if (!xhci->scratchpad->sp_dma_buffers)
|
||||
goto fail_sp4;
|
||||
|
||||
xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma;
|
||||
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
|
||||
for (i = 0; i < num_sp; i++) {
|
||||
dma_addr_t dma;
|
||||
void *buf = pci_alloc_consistent(to_pci_dev(dev),
|
||||
|
|
@ -1724,7 +1730,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
|
|||
}
|
||||
|
||||
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
||||
u32 __iomem *addr, u8 major_revision)
|
||||
__le32 __iomem *addr, u8 major_revision)
|
||||
{
|
||||
u32 temp, port_offset, port_count;
|
||||
int i;
|
||||
|
|
@ -1789,7 +1795,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
|||
*/
|
||||
static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
u32 __iomem *addr;
|
||||
__le32 __iomem *addr;
|
||||
u32 offset;
|
||||
unsigned int num_ports;
|
||||
int i, port_index;
|
||||
|
|
@ -2042,8 +2048,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
/* set ring base address and size for each segment table entry */
|
||||
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
|
||||
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
|
||||
entry->seg_addr = seg->dma;
|
||||
entry->seg_size = TRBS_PER_SEGMENT;
|
||||
entry->seg_addr = cpu_to_le64(seg->dma);
|
||||
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
|
||||
entry->rsvd = 0;
|
||||
seg = seg->next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -973,8 +973,8 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|||
|
||||
out_ctx = xhci->devs[slot_id]->out_ctx;
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
||||
hw_max_packet_size = MAX_PACKET_DECODED(ep_ctx->ep_info2);
|
||||
max_packet_size = urb->dev->ep0.desc.wMaxPacketSize;
|
||||
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
|
||||
max_packet_size = le16_to_cpu(urb->dev->ep0.desc.wMaxPacketSize);
|
||||
if (hw_max_packet_size != max_packet_size) {
|
||||
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
|
||||
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
|
||||
|
|
@ -988,15 +988,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|||
xhci->devs[slot_id]->out_ctx, ep_index);
|
||||
in_ctx = xhci->devs[slot_id]->in_ctx;
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
|
||||
ep_ctx->ep_info2 &= ~MAX_PACKET_MASK;
|
||||
ep_ctx->ep_info2 |= MAX_PACKET(max_packet_size);
|
||||
ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
|
||||
|
||||
/* Set up the input context flags for the command */
|
||||
/* FIXME: This won't work if a non-default control endpoint
|
||||
* changes max packet sizes.
|
||||
*/
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
ctrl_ctx->add_flags = EP0_FLAG;
|
||||
ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
|
||||
ctrl_ctx->drop_flags = 0;
|
||||
|
||||
xhci_dbg(xhci, "Slot %d input context\n", slot_id);
|
||||
|
|
@ -1010,7 +1010,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|||
/* Clean up the input context for later use by bandwidth
|
||||
* functions.
|
||||
*/
|
||||
ctrl_ctx->add_flags = SLOT_FLAG;
|
||||
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1331,27 +1331,30 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
/* If the HC already knows the endpoint is disabled,
|
||||
* or the HCD has noted it is disabled, ignore this request
|
||||
*/
|
||||
if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED ||
|
||||
ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
|
||||
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
|
||||
EP_STATE_DISABLED ||
|
||||
le32_to_cpu(ctrl_ctx->drop_flags) &
|
||||
xhci_get_endpoint_flag(&ep->desc)) {
|
||||
xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
|
||||
__func__, ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl_ctx->drop_flags |= drop_flag;
|
||||
new_drop_flags = ctrl_ctx->drop_flags;
|
||||
ctrl_ctx->drop_flags |= cpu_to_le32(drop_flag);
|
||||
new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags);
|
||||
|
||||
ctrl_ctx->add_flags &= ~drop_flag;
|
||||
new_add_flags = ctrl_ctx->add_flags;
|
||||
ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag);
|
||||
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
|
||||
|
||||
last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
|
||||
last_ctx = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags));
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
|
||||
/* Update the last valid endpoint context, if we deleted the last one */
|
||||
if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
|
||||
slot_ctx->dev_info &= ~LAST_CTX_MASK;
|
||||
slot_ctx->dev_info |= LAST_CTX(last_ctx);
|
||||
if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) >
|
||||
LAST_CTX(last_ctx)) {
|
||||
slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
|
||||
}
|
||||
new_slot_info = slot_ctx->dev_info;
|
||||
new_slot_info = le32_to_cpu(slot_ctx->dev_info);
|
||||
|
||||
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
|
||||
|
||||
|
|
@ -1419,7 +1422,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
/* If the HCD has already noted the endpoint is enabled,
|
||||
* ignore this request.
|
||||
*/
|
||||
if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
|
||||
if (le32_to_cpu(ctrl_ctx->add_flags) &
|
||||
xhci_get_endpoint_flag(&ep->desc)) {
|
||||
xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
|
||||
__func__, ep);
|
||||
return 0;
|
||||
|
|
@ -1437,8 +1441,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctrl_ctx->add_flags |= added_ctxs;
|
||||
new_add_flags = ctrl_ctx->add_flags;
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
|
||||
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
|
||||
|
||||
/* If xhci_endpoint_disable() was called for this endpoint, but the
|
||||
* xHC hasn't been notified yet through the check_bandwidth() call,
|
||||
|
|
@ -1446,15 +1450,16 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
* descriptors. We must drop and re-add this endpoint, so we leave the
|
||||
* drop flags alone.
|
||||
*/
|
||||
new_drop_flags = ctrl_ctx->drop_flags;
|
||||
new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags);
|
||||
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
|
||||
/* Update the last valid endpoint context, if we just added one past */
|
||||
if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
|
||||
slot_ctx->dev_info &= ~LAST_CTX_MASK;
|
||||
slot_ctx->dev_info |= LAST_CTX(last_ctx);
|
||||
if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) <
|
||||
LAST_CTX(last_ctx)) {
|
||||
slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
|
||||
}
|
||||
new_slot_info = slot_ctx->dev_info;
|
||||
new_slot_info = le32_to_cpu(slot_ctx->dev_info);
|
||||
|
||||
/* Store the usb_device pointer for later use */
|
||||
ep->hcpriv = udev;
|
||||
|
|
@ -1484,9 +1489,9 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
|
|||
ctrl_ctx->drop_flags = 0;
|
||||
ctrl_ctx->add_flags = 0;
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||
slot_ctx->dev_info &= ~LAST_CTX_MASK;
|
||||
slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
|
||||
/* Endpoint 0 is always valid */
|
||||
slot_ctx->dev_info |= LAST_CTX(1);
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1));
|
||||
for (i = 1; i < 31; ++i) {
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i);
|
||||
ep_ctx->ep_info = 0;
|
||||
|
|
@ -1497,7 +1502,7 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
|
|||
}
|
||||
|
||||
static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
|
||||
struct usb_device *udev, int *cmd_status)
|
||||
struct usb_device *udev, u32 *cmd_status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -1535,7 +1540,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
|
|||
}
|
||||
|
||||
static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
||||
struct usb_device *udev, int *cmd_status)
|
||||
struct usb_device *udev, u32 *cmd_status)
|
||||
{
|
||||
int ret;
|
||||
struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
|
||||
|
|
@ -1555,6 +1560,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case COMP_MEL_ERR:
|
||||
/* Max Exit Latency too large error */
|
||||
dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case COMP_SUCCESS:
|
||||
dev_dbg(&udev->dev, "Successful evaluate context command\n");
|
||||
ret = 0;
|
||||
|
|
@ -1581,7 +1591,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
unsigned long flags;
|
||||
struct xhci_container_ctx *in_ctx;
|
||||
struct completion *cmd_completion;
|
||||
int *cmd_status;
|
||||
u32 *cmd_status;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
|
@ -1595,8 +1605,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
/* Enqueue pointer can be left pointing to the link TRB,
|
||||
* we must handle that
|
||||
*/
|
||||
if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
|
||||
== TRB_TYPE(TRB_LINK))
|
||||
if ((le32_to_cpu(command->command_trb->link.control)
|
||||
& TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
|
||||
command->command_trb =
|
||||
xhci->cmd_ring->enq_seg->next->trbs;
|
||||
|
||||
|
|
@ -1672,14 +1682,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
|
||||
ctrl_ctx->add_flags |= SLOT_FLAG;
|
||||
ctrl_ctx->add_flags &= ~EP0_FLAG;
|
||||
ctrl_ctx->drop_flags &= ~SLOT_FLAG;
|
||||
ctrl_ctx->drop_flags &= ~EP0_FLAG;
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
|
||||
ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG);
|
||||
ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
|
||||
xhci_dbg(xhci, "New Input Control Context:\n");
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
|
||||
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
|
||||
LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
|
||||
|
||||
ret = xhci_configure_endpoint(xhci, udev, NULL,
|
||||
false, false);
|
||||
|
|
@ -1690,10 +1699,19 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
|
||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx,
|
||||
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
|
||||
LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info)));
|
||||
|
||||
/* Free any rings that were dropped, but not changed. */
|
||||
for (i = 1; i < 31; ++i) {
|
||||
if ((ctrl_ctx->drop_flags & (1 << (i + 1))) &&
|
||||
!(ctrl_ctx->add_flags & (1 << (i + 1))))
|
||||
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
|
||||
}
|
||||
xhci_zero_in_ctx(xhci, virt_dev);
|
||||
/* Install new rings and free or cache any old rings */
|
||||
/*
|
||||
* Install any rings for completely new endpoints or changed endpoints,
|
||||
* and free or cache any old rings from changed endpoints.
|
||||
*/
|
||||
for (i = 1; i < 31; ++i) {
|
||||
if (!virt_dev->eps[i].new_ring)
|
||||
continue;
|
||||
|
|
@ -1740,10 +1758,10 @@ static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
|
|||
{
|
||||
struct xhci_input_control_ctx *ctrl_ctx;
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
ctrl_ctx->add_flags = add_flags;
|
||||
ctrl_ctx->drop_flags = drop_flags;
|
||||
ctrl_ctx->add_flags = cpu_to_le32(add_flags);
|
||||
ctrl_ctx->drop_flags = cpu_to_le32(drop_flags);
|
||||
xhci_slot_copy(xhci, in_ctx, out_ctx);
|
||||
ctrl_ctx->add_flags |= SLOT_FLAG;
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
|
||||
|
||||
xhci_dbg(xhci, "Input Context:\n");
|
||||
xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
|
||||
|
|
@ -1772,7 +1790,7 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
|
|||
deq_state->new_deq_ptr);
|
||||
return;
|
||||
}
|
||||
ep_ctx->deq = addr | deq_state->new_cycle_state;
|
||||
ep_ctx->deq = cpu_to_le64(addr | deq_state->new_cycle_state);
|
||||
|
||||
added_ctxs = xhci_get_endpoint_flag_from_index(ep_index);
|
||||
xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx,
|
||||
|
|
@ -2327,8 +2345,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
/* Enqueue pointer can be left pointing to the link TRB,
|
||||
* we must handle that
|
||||
*/
|
||||
if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
|
||||
== TRB_TYPE(TRB_LINK))
|
||||
if ((le32_to_cpu(reset_device_cmd->command_trb->link.control)
|
||||
& TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
|
||||
reset_device_cmd->command_trb =
|
||||
xhci->cmd_ring->enq_seg->next->trbs;
|
||||
|
||||
|
|
@ -2542,6 +2560,17 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
|
||||
if (WARN_ON(!virt_dev)) {
|
||||
/*
|
||||
* In plug/unplug torture test with an NEC controller,
|
||||
* a zero-dereference was observed once due to virt_dev = 0.
|
||||
* Print useful debug rather than crash if it is observed again!
|
||||
*/
|
||||
xhci_warn(xhci, "Virt dev invalid for slot_id 0x%x!\n",
|
||||
udev->slot_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||
/*
|
||||
* If this is the first Set Address since device plug-in or
|
||||
|
|
@ -2609,10 +2638,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
||||
xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
|
||||
xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
|
||||
udev->slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[udev->slot_id],
|
||||
(unsigned long long)
|
||||
xhci->dcbaa->dev_context_ptrs[udev->slot_id]);
|
||||
udev->slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[udev->slot_id],
|
||||
(unsigned long long)
|
||||
le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
|
||||
xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
|
||||
(unsigned long long)virt_dev->out_ctx->dma);
|
||||
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
|
||||
|
|
@ -2626,7 +2655,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
/* Use kernel assigned address for devices; store xHC assigned
|
||||
* address locally. */
|
||||
virt_dev->address = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
|
||||
virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
|
||||
+ 1;
|
||||
/* Zero the input context control for later use */
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
|
||||
ctrl_ctx->add_flags = 0;
|
||||
|
|
@ -2670,24 +2700,29 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
|||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx);
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
|
||||
ctrl_ctx->add_flags |= SLOT_FLAG;
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx);
|
||||
slot_ctx->dev_info |= DEV_HUB;
|
||||
slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
|
||||
if (tt->multi)
|
||||
slot_ctx->dev_info |= DEV_MTT;
|
||||
slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
|
||||
if (xhci->hci_version > 0x95) {
|
||||
xhci_dbg(xhci, "xHCI version %x needs hub "
|
||||
"TT think time and number of ports\n",
|
||||
(unsigned int) xhci->hci_version);
|
||||
slot_ctx->dev_info2 |= XHCI_MAX_PORTS(hdev->maxchild);
|
||||
slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(hdev->maxchild));
|
||||
/* Set TT think time - convert from ns to FS bit times.
|
||||
* 0 = 8 FS bit times, 1 = 16 FS bit times,
|
||||
* 2 = 24 FS bit times, 3 = 32 FS bit times.
|
||||
*
|
||||
* xHCI 1.0: this field shall be 0 if the device is not a
|
||||
* High-spped hub.
|
||||
*/
|
||||
think_time = tt->think_time;
|
||||
if (think_time != 0)
|
||||
think_time = (think_time / 666) - 1;
|
||||
slot_ctx->tt_info |= TT_THINK_TIME(think_time);
|
||||
if (xhci->hci_version < 0x100 || hdev->speed == USB_SPEED_HIGH)
|
||||
slot_ctx->tt_info |=
|
||||
cpu_to_le32(TT_THINK_TIME(think_time));
|
||||
} else {
|
||||
xhci_dbg(xhci, "xHCI version %x doesn't need hub "
|
||||
"TT think time or number of ports\n",
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@
|
|||
* @run_regs_off: RTSOFF - Runtime register space offset
|
||||
*/
|
||||
struct xhci_cap_regs {
|
||||
u32 hc_capbase;
|
||||
u32 hcs_params1;
|
||||
u32 hcs_params2;
|
||||
u32 hcs_params3;
|
||||
u32 hcc_params;
|
||||
u32 db_off;
|
||||
u32 run_regs_off;
|
||||
__le32 hc_capbase;
|
||||
__le32 hcs_params1;
|
||||
__le32 hcs_params2;
|
||||
__le32 hcs_params3;
|
||||
__le32 hcc_params;
|
||||
__le32 db_off;
|
||||
__le32 run_regs_off;
|
||||
/* Reserved up to (CAPLENGTH - 0x1C) */
|
||||
};
|
||||
|
||||
|
|
@ -155,26 +155,26 @@ struct xhci_cap_regs {
|
|||
* devices.
|
||||
*/
|
||||
struct xhci_op_regs {
|
||||
u32 command;
|
||||
u32 status;
|
||||
u32 page_size;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 dev_notification;
|
||||
u64 cmd_ring;
|
||||
__le32 command;
|
||||
__le32 status;
|
||||
__le32 page_size;
|
||||
__le32 reserved1;
|
||||
__le32 reserved2;
|
||||
__le32 dev_notification;
|
||||
__le64 cmd_ring;
|
||||
/* rsvd: offset 0x20-2F */
|
||||
u32 reserved3[4];
|
||||
u64 dcbaa_ptr;
|
||||
u32 config_reg;
|
||||
__le32 reserved3[4];
|
||||
__le64 dcbaa_ptr;
|
||||
__le32 config_reg;
|
||||
/* rsvd: offset 0x3C-3FF */
|
||||
u32 reserved4[241];
|
||||
__le32 reserved4[241];
|
||||
/* port 1 registers, which serve as a base address for other ports */
|
||||
u32 port_status_base;
|
||||
u32 port_power_base;
|
||||
u32 port_link_base;
|
||||
u32 reserved5;
|
||||
__le32 port_status_base;
|
||||
__le32 port_power_base;
|
||||
__le32 port_link_base;
|
||||
__le32 reserved5;
|
||||
/* registers for ports 2-255 */
|
||||
u32 reserved6[NUM_PORT_REGS*254];
|
||||
__le32 reserved6[NUM_PORT_REGS*254];
|
||||
};
|
||||
|
||||
/* USBCMD - USB command - command bitmasks */
|
||||
|
|
@ -382,12 +382,12 @@ struct xhci_op_regs {
|
|||
* updates the dequeue pointer.
|
||||
*/
|
||||
struct xhci_intr_reg {
|
||||
u32 irq_pending;
|
||||
u32 irq_control;
|
||||
u32 erst_size;
|
||||
u32 rsvd;
|
||||
u64 erst_base;
|
||||
u64 erst_dequeue;
|
||||
__le32 irq_pending;
|
||||
__le32 irq_control;
|
||||
__le32 erst_size;
|
||||
__le32 rsvd;
|
||||
__le64 erst_base;
|
||||
__le64 erst_dequeue;
|
||||
};
|
||||
|
||||
/* irq_pending bitmasks */
|
||||
|
|
@ -432,8 +432,8 @@ struct xhci_intr_reg {
|
|||
* or larger accesses"
|
||||
*/
|
||||
struct xhci_run_regs {
|
||||
u32 microframe_index;
|
||||
u32 rsvd[7];
|
||||
__le32 microframe_index;
|
||||
__le32 rsvd[7];
|
||||
struct xhci_intr_reg ir_set[128];
|
||||
};
|
||||
|
||||
|
|
@ -447,7 +447,7 @@ struct xhci_run_regs {
|
|||
* Section 5.6
|
||||
*/
|
||||
struct xhci_doorbell_array {
|
||||
u32 doorbell[256];
|
||||
__le32 doorbell[256];
|
||||
};
|
||||
|
||||
#define DB_VALUE(ep, stream) ((((ep) + 1) & 0xff) | ((stream) << 16))
|
||||
|
|
@ -504,12 +504,12 @@ struct xhci_container_ctx {
|
|||
* reserved at the end of the slot context for HC internal use.
|
||||
*/
|
||||
struct xhci_slot_ctx {
|
||||
u32 dev_info;
|
||||
u32 dev_info2;
|
||||
u32 tt_info;
|
||||
u32 dev_state;
|
||||
__le32 dev_info;
|
||||
__le32 dev_info2;
|
||||
__le32 tt_info;
|
||||
__le32 dev_state;
|
||||
/* offset 0x10 to 0x1f reserved for HC internal use */
|
||||
u32 reserved[4];
|
||||
__le32 reserved[4];
|
||||
};
|
||||
|
||||
/* dev_info bitmasks */
|
||||
|
|
@ -580,12 +580,12 @@ struct xhci_slot_ctx {
|
|||
* reserved at the end of the endpoint context for HC internal use.
|
||||
*/
|
||||
struct xhci_ep_ctx {
|
||||
u32 ep_info;
|
||||
u32 ep_info2;
|
||||
u64 deq;
|
||||
u32 tx_info;
|
||||
__le32 ep_info;
|
||||
__le32 ep_info2;
|
||||
__le64 deq;
|
||||
__le32 tx_info;
|
||||
/* offset 0x14 - 0x1f reserved for HC internal use */
|
||||
u32 reserved[3];
|
||||
__le32 reserved[3];
|
||||
};
|
||||
|
||||
/* ep_info bitmasks */
|
||||
|
|
@ -660,9 +660,9 @@ struct xhci_ep_ctx {
|
|||
* @add_context: set the bit of the endpoint context you want to enable
|
||||
*/
|
||||
struct xhci_input_control_ctx {
|
||||
u32 drop_flags;
|
||||
u32 add_flags;
|
||||
u32 rsvd2[6];
|
||||
__le32 drop_flags;
|
||||
__le32 add_flags;
|
||||
__le32 rsvd2[6];
|
||||
};
|
||||
|
||||
/* Represents everything that is needed to issue a command on the command ring.
|
||||
|
|
@ -688,9 +688,9 @@ struct xhci_command {
|
|||
|
||||
struct xhci_stream_ctx {
|
||||
/* 64-bit stream ring address, cycle state, and stream type */
|
||||
u64 stream_ring;
|
||||
__le64 stream_ring;
|
||||
/* offset 0x14 - 0x1f reserved for HC internal use */
|
||||
u32 reserved[2];
|
||||
__le32 reserved[2];
|
||||
};
|
||||
|
||||
/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */
|
||||
|
|
@ -803,7 +803,7 @@ struct xhci_virt_device {
|
|||
*/
|
||||
struct xhci_device_context_array {
|
||||
/* 64-bit device addresses; we only write 32-bit addresses */
|
||||
u64 dev_context_ptrs[MAX_HC_SLOTS];
|
||||
__le64 dev_context_ptrs[MAX_HC_SLOTS];
|
||||
/* private xHCD pointers */
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
|
@ -816,10 +816,10 @@ struct xhci_device_context_array {
|
|||
|
||||
struct xhci_transfer_event {
|
||||
/* 64-bit buffer address, or immediate data */
|
||||
u64 buffer;
|
||||
u32 transfer_len;
|
||||
__le64 buffer;
|
||||
__le32 transfer_len;
|
||||
/* This field is interpreted differently based on the type of TRB */
|
||||
u32 flags;
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
/** Transfer Event bit fields **/
|
||||
|
|
@ -881,7 +881,9 @@ struct xhci_transfer_event {
|
|||
#define COMP_STOP_INVAL 27
|
||||
/* Control Abort Error - Debug Capability - control pipe aborted */
|
||||
#define COMP_DBG_ABORT 28
|
||||
/* TRB type 29 and 30 reserved */
|
||||
/* Max Exit Latency Too Large Error */
|
||||
#define COMP_MEL_ERR 29
|
||||
/* TRB type 30 reserved */
|
||||
/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */
|
||||
#define COMP_BUFF_OVER 31
|
||||
/* Event Lost Error - xHC has an "internal event overrun condition" */
|
||||
|
|
@ -898,9 +900,9 @@ struct xhci_transfer_event {
|
|||
|
||||
struct xhci_link_trb {
|
||||
/* 64-bit segment pointer*/
|
||||
u64 segment_ptr;
|
||||
u32 intr_target;
|
||||
u32 control;
|
||||
__le64 segment_ptr;
|
||||
__le32 intr_target;
|
||||
__le32 control;
|
||||
};
|
||||
|
||||
/* control bitfields */
|
||||
|
|
@ -909,9 +911,9 @@ struct xhci_link_trb {
|
|||
/* Command completion event TRB */
|
||||
struct xhci_event_cmd {
|
||||
/* Pointer to command TRB, or the value passed by the event data trb */
|
||||
u64 cmd_trb;
|
||||
u32 status;
|
||||
u32 flags;
|
||||
__le64 cmd_trb;
|
||||
__le32 status;
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
/* flags bitmasks */
|
||||
|
|
@ -943,6 +945,8 @@ struct xhci_event_cmd {
|
|||
/* Interrupter Target - which MSI-X vector to target the completion event at */
|
||||
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
|
||||
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
|
||||
#define TRB_TBC(p) (((p) & 0x3) << 7)
|
||||
#define TRB_TLBPC(p) (((p) & 0xf) << 16)
|
||||
|
||||
/* Cycle bit - indicates TRB ownership by HC or HCD */
|
||||
#define TRB_CYCLE (1<<0)
|
||||
|
|
@ -962,15 +966,20 @@ struct xhci_event_cmd {
|
|||
/* The buffer pointer contains immediate data */
|
||||
#define TRB_IDT (1<<6)
|
||||
|
||||
/* Block Event Interrupt */
|
||||
#define TRB_BEI (1<<9)
|
||||
|
||||
/* Control transfer TRB specific fields */
|
||||
#define TRB_DIR_IN (1<<16)
|
||||
#define TRB_TX_TYPE(p) ((p) << 16)
|
||||
#define TRB_DATA_OUT 2
|
||||
#define TRB_DATA_IN 3
|
||||
|
||||
/* Isochronous TRB specific fields */
|
||||
#define TRB_SIA (1<<31)
|
||||
|
||||
struct xhci_generic_trb {
|
||||
u32 field[4];
|
||||
__le32 field[4];
|
||||
};
|
||||
|
||||
union xhci_trb {
|
||||
|
|
@ -1118,10 +1127,10 @@ struct xhci_ring {
|
|||
|
||||
struct xhci_erst_entry {
|
||||
/* 64-bit event ring segment address */
|
||||
u64 seg_addr;
|
||||
u32 seg_size;
|
||||
__le64 seg_addr;
|
||||
__le32 seg_size;
|
||||
/* Set to zero */
|
||||
u32 rsvd;
|
||||
__le32 rsvd;
|
||||
};
|
||||
|
||||
struct xhci_erst {
|
||||
|
|
@ -1286,10 +1295,10 @@ struct xhci_hcd {
|
|||
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
|
||||
u8 *port_array;
|
||||
/* Array of pointers to USB 3.0 PORTSC registers */
|
||||
u32 __iomem **usb3_ports;
|
||||
__le32 __iomem **usb3_ports;
|
||||
unsigned int num_usb3_ports;
|
||||
/* Array of pointers to USB 2.0 PORTSC registers */
|
||||
u32 __iomem **usb2_ports;
|
||||
__le32 __iomem **usb2_ports;
|
||||
unsigned int num_usb2_ports;
|
||||
};
|
||||
|
||||
|
|
@ -1322,12 +1331,12 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
|
|||
/* TODO: copied from ehci.h - can be refactored? */
|
||||
/* xHCI spec says all registers are little endian */
|
||||
static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
|
||||
__u32 __iomem *regs)
|
||||
__le32 __iomem *regs)
|
||||
{
|
||||
return readl(regs);
|
||||
}
|
||||
static inline void xhci_writel(struct xhci_hcd *xhci,
|
||||
const unsigned int val, __u32 __iomem *regs)
|
||||
const unsigned int val, __le32 __iomem *regs)
|
||||
{
|
||||
xhci_dbg(xhci,
|
||||
"`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
|
||||
|
|
@ -1345,7 +1354,7 @@ static inline void xhci_writel(struct xhci_hcd *xhci,
|
|||
* the high dword, and write order is irrelevant.
|
||||
*/
|
||||
static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
|
||||
__u64 __iomem *regs)
|
||||
__le64 __iomem *regs)
|
||||
{
|
||||
__u32 __iomem *ptr = (__u32 __iomem *) regs;
|
||||
u64 val_lo = readl(ptr);
|
||||
|
|
@ -1353,7 +1362,7 @@ static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
|
|||
return val_lo + (val_hi << 32);
|
||||
}
|
||||
static inline void xhci_write_64(struct xhci_hcd *xhci,
|
||||
const u64 val, __u64 __iomem *regs)
|
||||
const u64 val, __le64 __iomem *regs)
|
||||
{
|
||||
__u32 __iomem *ptr = (__u32 __iomem *) regs;
|
||||
u32 val_lo = lower_32_bits(val);
|
||||
|
|
|
|||
|
|
@ -2889,8 +2889,7 @@ static struct usb_driver ftdi_elan_driver = {
|
|||
static int __init ftdi_elan_init(void)
|
||||
{
|
||||
int result;
|
||||
printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
|
||||
__TIME__, __DATE__);
|
||||
printk(KERN_INFO "driver %s\n", ftdi_elan_driver.name);
|
||||
mutex_init(&ftdi_module_lock);
|
||||
INIT_LIST_HEAD(&ftdi_static_list);
|
||||
status_queue = create_singlethread_workqueue("ftdi-status-control");
|
||||
|
|
|
|||
|
|
@ -20,11 +20,6 @@
|
|||
* Derived from Lego USB Tower driver
|
||||
* Copyright (C) 2003 David Glance <advidgsf@sourceforge.net>
|
||||
* 2001-2004 Juergen Stuber <starblue@users.sourceforge.net>
|
||||
*
|
||||
* V0.1 (mh) Initial version
|
||||
* V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint)
|
||||
* V0.12 (mh) Added kmalloc check for string buffer
|
||||
* V0.13 (mh) Added support for LD X-Ray and Machine Test System
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -41,20 +36,39 @@
|
|||
|
||||
/* Define these values to match your devices */
|
||||
#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */
|
||||
#define USB_DEVICE_ID_LD_CASSY 0x1000 /* USB Product ID of CASSY-S */
|
||||
#define USB_DEVICE_ID_LD_CASSY 0x1000 /* USB Product ID of CASSY-S modules with 8 bytes endpoint size */
|
||||
#define USB_DEVICE_ID_LD_CASSY2 0x1001 /* USB Product ID of CASSY-S modules with 64 bytes endpoint size */
|
||||
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 /* USB Product ID of Pocket-CASSY */
|
||||
#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011 /* USB Product ID of Pocket-CASSY 2 (reserved) */
|
||||
#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 /* USB Product ID of Mobile-CASSY */
|
||||
#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021 /* USB Product ID of Mobile-CASSY 2 (reserved) */
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031 /* USB Product ID of Micro-CASSY Voltage */
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032 /* USB Product ID of Micro-CASSY Current */
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 /* USB Product ID of Micro-CASSY Time (reserved) */
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 /* USB Product ID of Micro-CASSY Temperature */
|
||||
#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 /* USB Product ID of Micro-CASSY pH */
|
||||
#define USB_DEVICE_ID_LD_JWM 0x1080 /* USB Product ID of Joule and Wattmeter */
|
||||
#define USB_DEVICE_ID_LD_DMMP 0x1081 /* USB Product ID of Digital Multimeter P (reserved) */
|
||||
#define USB_DEVICE_ID_LD_UMIP 0x1090 /* USB Product ID of UMI P */
|
||||
#define USB_DEVICE_ID_LD_XRAY1 0x1100 /* USB Product ID of X-Ray Apparatus */
|
||||
#define USB_DEVICE_ID_LD_XRAY2 0x1101 /* USB Product ID of X-Ray Apparatus */
|
||||
#define USB_DEVICE_ID_LD_UMIC 0x10A0 /* USB Product ID of UMI C */
|
||||
#define USB_DEVICE_ID_LD_UMIB 0x10B0 /* USB Product ID of UMI B */
|
||||
#define USB_DEVICE_ID_LD_XRAY 0x1100 /* USB Product ID of X-Ray Apparatus 55481 */
|
||||
#define USB_DEVICE_ID_LD_XRAY2 0x1101 /* USB Product ID of X-Ray Apparatus 554800 */
|
||||
#define USB_DEVICE_ID_LD_XRAYCT 0x1110 /* USB Product ID of X-Ray Apparatus CT 554821*/
|
||||
#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 /* USB Product ID of VideoCom */
|
||||
#define USB_DEVICE_ID_LD_MOTOR 0x1210 /* USB Product ID of Motor (reserved) */
|
||||
#define USB_DEVICE_ID_LD_COM3LAB 0x2000 /* USB Product ID of COM3LAB */
|
||||
#define USB_DEVICE_ID_LD_TELEPORT 0x2010 /* USB Product ID of Terminal Adapter */
|
||||
#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 /* USB Product ID of Network Analyser */
|
||||
#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 /* USB Product ID of Converter Control Unit */
|
||||
#define USB_DEVICE_ID_LD_MACHINETEST 0x2040 /* USB Product ID of Machine Test System */
|
||||
#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050 /* USB Product ID of MOST Protocol Analyser */
|
||||
#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051 /* USB Product ID of MOST Protocol Analyser 2 */
|
||||
#define USB_DEVICE_ID_LD_ABSESP 0x2060 /* USB Product ID of ABS ESP */
|
||||
#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070 /* USB Product ID of Automotive Data Buses */
|
||||
#define USB_DEVICE_ID_LD_MCT 0x2080 /* USB Product ID of Microcontroller technique */
|
||||
#define USB_DEVICE_ID_LD_HYBRID 0x2090 /* USB Product ID of Automotive Hybrid */
|
||||
#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 /* USB Product ID of Heat control */
|
||||
|
||||
#define USB_VENDOR_ID_VERNIER 0x08f7
|
||||
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
|
||||
|
|
@ -71,19 +85,37 @@
|
|||
/* table of devices that work with this driver */
|
||||
static const struct usb_device_id ld_usb_table[] = {
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
|
||||
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
|
||||
|
|
@ -91,7 +123,7 @@ static const struct usb_device_id ld_usb_table[] = {
|
|||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, ld_usb_table);
|
||||
MODULE_VERSION("V0.13");
|
||||
MODULE_VERSION("V0.14");
|
||||
MODULE_AUTHOR("Michael Hund <[email protected]>");
|
||||
MODULE_DESCRIPTION("LD USB Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -268,9 +268,9 @@ static inline void simple_fill_buf(struct urb *urb)
|
|||
}
|
||||
}
|
||||
|
||||
static inline unsigned buffer_offset(void *buf)
|
||||
static inline unsigned long buffer_offset(void *buf)
|
||||
{
|
||||
return (unsigned)buf & (ARCH_KMALLOC_MINALIGN - 1);
|
||||
return (unsigned long)buf & (ARCH_KMALLOC_MINALIGN - 1);
|
||||
}
|
||||
|
||||
static int check_guard_bytes(struct usbtest_dev *tdev, struct urb *urb)
|
||||
|
|
@ -329,7 +329,7 @@ static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
|
|||
|
||||
static void simple_free_urb(struct urb *urb)
|
||||
{
|
||||
unsigned offset = buffer_offset(urb->transfer_buffer);
|
||||
unsigned long offset = buffer_offset(urb->transfer_buffer);
|
||||
|
||||
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||
usb_free_coherent(
|
||||
|
|
@ -1030,6 +1030,8 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
|
|||
req.wValue = cpu_to_le16((USB_DT_DEVICE << 8) | 0);
|
||||
/* device descriptor size == 18 bytes */
|
||||
len = udev->descriptor.bMaxPacketSize0;
|
||||
if (udev->speed == USB_SPEED_SUPER)
|
||||
len = 512;
|
||||
switch (len) {
|
||||
case 8:
|
||||
len = 24;
|
||||
|
|
@ -1195,6 +1197,104 @@ static int unlink_simple(struct usbtest_dev *dev, int pipe, int len)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct queued_ctx {
|
||||
struct completion complete;
|
||||
atomic_t pending;
|
||||
unsigned num;
|
||||
int status;
|
||||
struct urb **urbs;
|
||||
};
|
||||
|
||||
static void unlink_queued_callback(struct urb *urb)
|
||||
{
|
||||
int status = urb->status;
|
||||
struct queued_ctx *ctx = urb->context;
|
||||
|
||||
if (ctx->status)
|
||||
goto done;
|
||||
if (urb == ctx->urbs[ctx->num - 4] || urb == ctx->urbs[ctx->num - 2]) {
|
||||
if (status == -ECONNRESET)
|
||||
goto done;
|
||||
/* What error should we report if the URB completed normally? */
|
||||
}
|
||||
if (status != 0)
|
||||
ctx->status = status;
|
||||
|
||||
done:
|
||||
if (atomic_dec_and_test(&ctx->pending))
|
||||
complete(&ctx->complete);
|
||||
}
|
||||
|
||||
static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num,
|
||||
unsigned size)
|
||||
{
|
||||
struct queued_ctx ctx;
|
||||
struct usb_device *udev = testdev_to_usbdev(dev);
|
||||
void *buf;
|
||||
dma_addr_t buf_dma;
|
||||
int i;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
init_completion(&ctx.complete);
|
||||
atomic_set(&ctx.pending, 1); /* One more than the actual value */
|
||||
ctx.num = num;
|
||||
ctx.status = 0;
|
||||
|
||||
buf = usb_alloc_coherent(udev, size, GFP_KERNEL, &buf_dma);
|
||||
if (!buf)
|
||||
return retval;
|
||||
memset(buf, 0, size);
|
||||
|
||||
/* Allocate and init the urbs we'll queue */
|
||||
ctx.urbs = kcalloc(num, sizeof(struct urb *), GFP_KERNEL);
|
||||
if (!ctx.urbs)
|
||||
goto free_buf;
|
||||
for (i = 0; i < num; i++) {
|
||||
ctx.urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!ctx.urbs[i])
|
||||
goto free_urbs;
|
||||
usb_fill_bulk_urb(ctx.urbs[i], udev, pipe, buf, size,
|
||||
unlink_queued_callback, &ctx);
|
||||
ctx.urbs[i]->transfer_dma = buf_dma;
|
||||
ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||||
}
|
||||
|
||||
/* Submit all the URBs and then unlink URBs num - 4 and num - 2. */
|
||||
for (i = 0; i < num; i++) {
|
||||
atomic_inc(&ctx.pending);
|
||||
retval = usb_submit_urb(ctx.urbs[i], GFP_KERNEL);
|
||||
if (retval != 0) {
|
||||
dev_err(&dev->intf->dev, "submit urbs[%d] fail %d\n",
|
||||
i, retval);
|
||||
atomic_dec(&ctx.pending);
|
||||
ctx.status = retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == num) {
|
||||
usb_unlink_urb(ctx.urbs[num - 4]);
|
||||
usb_unlink_urb(ctx.urbs[num - 2]);
|
||||
} else {
|
||||
while (--i >= 0)
|
||||
usb_unlink_urb(ctx.urbs[i]);
|
||||
}
|
||||
|
||||
if (atomic_dec_and_test(&ctx.pending)) /* The extra count */
|
||||
complete(&ctx.complete);
|
||||
wait_for_completion(&ctx.complete);
|
||||
retval = ctx.status;
|
||||
|
||||
free_urbs:
|
||||
for (i = 0; i < num; i++)
|
||||
usb_free_urb(ctx.urbs[i]);
|
||||
kfree(ctx.urbs);
|
||||
free_buf:
|
||||
usb_free_coherent(udev, size, buf, buf_dma);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
|
||||
{
|
||||
int retval;
|
||||
|
|
@ -1970,8 +2070,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
dev->in_iso_pipe, dev->iso_in, 0);
|
||||
break;
|
||||
|
||||
/* FIXME unlink from queue (ring with N urbs) */
|
||||
|
||||
/* FIXME scatterlist cancel (needs helper thread) */
|
||||
|
||||
/* Tests for bulk I/O using DMA mapping by core and odd address */
|
||||
|
|
@ -2064,6 +2162,26 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
dev->in_iso_pipe, dev->iso_in, 1);
|
||||
break;
|
||||
|
||||
/* unlink URBs from a bulk-OUT queue */
|
||||
case 24:
|
||||
if (dev->out_pipe == 0 || !param->length || param->sglen < 4)
|
||||
break;
|
||||
retval = 0;
|
||||
dev_info(&intf->dev, "TEST 17: unlink from %d queues of "
|
||||
"%d %d-byte writes\n",
|
||||
param->iterations, param->sglen, param->length);
|
||||
for (i = param->iterations; retval == 0 && i > 0; --i) {
|
||||
retval = unlink_queued(dev, dev->out_pipe,
|
||||
param->sglen, param->length);
|
||||
if (retval) {
|
||||
dev_err(&intf->dev,
|
||||
"unlink queued writes failed %d, "
|
||||
"iterations left %d\n", retval, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
do_gettimeofday(¶m->duration);
|
||||
param->duration.tv_sec -= start.tv_sec;
|
||||
|
|
@ -2192,6 +2310,9 @@ usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
case USB_SPEED_HIGH:
|
||||
tmp = "high";
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
tmp = "super";
|
||||
break;
|
||||
default:
|
||||
tmp = "unknown";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ config USB_MUSB_HDRC
|
|||
select TWL4030_USB if MACH_OMAP_3430SDP
|
||||
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
|
||||
select USB_OTG_UTILS
|
||||
bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
||||
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
||||
help
|
||||
Say Y here if your system has a dual role high speed USB
|
||||
controller based on the Mentor Graphics silicon IP. Then
|
||||
|
|
@ -30,39 +30,39 @@ config USB_MUSB_HDRC
|
|||
|
||||
If you do not know what this is, please say N.
|
||||
|
||||
# To compile this driver as a module, choose M here; the
|
||||
# module will be called "musb-hdrc".
|
||||
To compile this driver as a module, choose M here; the
|
||||
module will be called "musb-hdrc".
|
||||
|
||||
choice
|
||||
prompt "Platform Glue Layer"
|
||||
depends on USB_MUSB_HDRC
|
||||
|
||||
config USB_MUSB_DAVINCI
|
||||
bool "DaVinci"
|
||||
tristate "DaVinci"
|
||||
depends on ARCH_DAVINCI_DMx
|
||||
|
||||
config USB_MUSB_DA8XX
|
||||
bool "DA8xx/OMAP-L1x"
|
||||
tristate "DA8xx/OMAP-L1x"
|
||||
depends on ARCH_DAVINCI_DA8XX
|
||||
|
||||
config USB_MUSB_TUSB6010
|
||||
bool "TUSB6010"
|
||||
tristate "TUSB6010"
|
||||
depends on ARCH_OMAP
|
||||
|
||||
config USB_MUSB_OMAP2PLUS
|
||||
bool "OMAP2430 and onwards"
|
||||
tristate "OMAP2430 and onwards"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
||||
config USB_MUSB_AM35X
|
||||
bool "AM35x"
|
||||
tristate "AM35x"
|
||||
depends on ARCH_OMAP
|
||||
|
||||
config USB_MUSB_BLACKFIN
|
||||
bool "Blackfin"
|
||||
tristate "Blackfin"
|
||||
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
|
||||
|
||||
config USB_MUSB_UX500
|
||||
bool "U8500 and U5500"
|
||||
tristate "U8500 and U5500"
|
||||
depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500)
|
||||
|
||||
endchoice
|
||||
|
|
@ -153,6 +153,13 @@ config MUSB_PIO_ONLY
|
|||
you can still disable it at run time using the "use_dma=n" module
|
||||
parameter.
|
||||
|
||||
config USB_UX500_DMA
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
|
||||
default USB_MUSB_UX500
|
||||
help
|
||||
Enable DMA transfers on UX500 platforms.
|
||||
|
||||
config USB_INVENTRA_DMA
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
|
||||
|
|
@ -176,11 +183,3 @@ config USB_TUSB_OMAP_DMA
|
|||
help
|
||||
Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
|
||||
|
||||
config USB_MUSB_DEBUG
|
||||
depends on USB_MUSB_HDRC
|
||||
bool "Enable debugging messages"
|
||||
default n
|
||||
help
|
||||
This enables musb debugging. To set the logging level use the debug
|
||||
module parameter. Starting at level 3, per-transfer (urb, usb_request,
|
||||
packet, or dma transfer) tracing may kick in.
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
|
||||
#
|
||||
|
||||
ccflags-$(CONFIG_USB_MUSB_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
|
||||
|
||||
musb_hdrc-y := musb_core.o
|
||||
|
|
@ -39,6 +37,11 @@ ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
|
|||
ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
|
||||
musb_hdrc-y += tusb6010_omap.o
|
||||
|
||||
else
|
||||
ifeq ($(CONFIG_USB_UX500_DMA),y)
|
||||
musb_hdrc-y += ux500_dma.o
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ static void otg_timer(unsigned long _musb)
|
|||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
|
||||
otg_state_string(musb->xceiv->state));
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
switch (musb->xceiv->state) {
|
||||
|
|
@ -202,20 +203,22 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
|
|||
/* Never idle if active, or when VBUS timeout is not set as host */
|
||||
if (musb->is_active || (musb->a_wait_bcon == 0 &&
|
||||
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
|
||||
DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
del_timer(&otg_workaround);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
|
||||
DBG(4, "Longer idle timer already pending, ignoring...\n");
|
||||
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
DBG(4, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
|
||||
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
|
||||
|
|
@ -302,9 +305,9 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
|
|||
}
|
||||
|
||||
/* NOTE: this must complete power-on within 100 ms. */
|
||||
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb),
|
||||
otg_state_string(musb->xceiv->state),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
ret = IRQ_HANDLED;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct bfin_glue {
|
|||
*/
|
||||
void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
|
||||
{
|
||||
struct musb *musb = hw_ep->musb;
|
||||
void __iomem *fifo = hw_ep->fifo;
|
||||
void __iomem *epio = hw_ep->regs;
|
||||
u8 epnum = hw_ep->epnum;
|
||||
|
|
@ -43,7 +44,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
|
|||
|
||||
musb_writew(epio, MUSB_TXCOUNT, len);
|
||||
|
||||
DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n",
|
||||
dev_dbg(musb->controller, "TX ep%d fifo %p count %d buf %p, epio %p\n",
|
||||
hw_ep->epnum, fifo, len, src, epio);
|
||||
|
||||
dump_fifo_data(src, len);
|
||||
|
|
@ -98,6 +99,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
|
|||
*/
|
||||
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
|
||||
{
|
||||
struct musb *musb = hw_ep->musb;
|
||||
void __iomem *fifo = hw_ep->fifo;
|
||||
u8 epnum = hw_ep->epnum;
|
||||
|
||||
|
|
@ -154,7 +156,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
|
|||
*(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);
|
||||
}
|
||||
}
|
||||
DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
|
||||
dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
|
||||
'R', hw_ep->epnum, fifo, len, dst);
|
||||
|
||||
dump_fifo_data(dst, len);
|
||||
|
|
@ -279,12 +281,14 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
DBG(1, "%s state not handled\n", otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "%s state not handled\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
DBG(4, "state is %s\n", otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "state is %s\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
}
|
||||
|
||||
static void bfin_musb_enable(struct musb *musb)
|
||||
|
|
@ -306,9 +310,9 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
|
|||
value = !value;
|
||||
gpio_set_value(musb->config->gpio_vrsel, value);
|
||||
|
||||
DBG(1, "VBUS %s, devctl %02x "
|
||||
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
|
||||
/* otg %3x conf %08x prcm %08x */ "\n",
|
||||
otg_state_string(musb),
|
||||
otg_state_string(musb->xceiv->state),
|
||||
musb_readb(musb->mregs, MUSB_DEVCTL));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ static int cppi_controller_stop(struct dma_controller *c)
|
|||
musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG,
|
||||
DAVINCI_DMA_ALL_CHANNELS_ENABLE);
|
||||
|
||||
DBG(1, "Tearing down RX and TX Channels\n");
|
||||
dev_dbg(musb->controller, "Tearing down RX and TX Channels\n");
|
||||
for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
|
||||
/* FIXME restructure of txdma to use bds like rxdma */
|
||||
controller->tx[i].last_processed = NULL;
|
||||
|
|
@ -301,13 +301,13 @@ cppi_channel_allocate(struct dma_controller *c,
|
|||
*/
|
||||
if (transmit) {
|
||||
if (index >= ARRAY_SIZE(controller->tx)) {
|
||||
DBG(1, "no %cX%d CPPI channel\n", 'T', index);
|
||||
dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'T', index);
|
||||
return NULL;
|
||||
}
|
||||
cppi_ch = controller->tx + index;
|
||||
} else {
|
||||
if (index >= ARRAY_SIZE(controller->rx)) {
|
||||
DBG(1, "no %cX%d CPPI channel\n", 'R', index);
|
||||
dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'R', index);
|
||||
return NULL;
|
||||
}
|
||||
cppi_ch = controller->rx + index;
|
||||
|
|
@ -318,13 +318,13 @@ cppi_channel_allocate(struct dma_controller *c,
|
|||
* with the other DMA engine too
|
||||
*/
|
||||
if (cppi_ch->hw_ep)
|
||||
DBG(1, "re-allocating DMA%d %cX channel %p\n",
|
||||
dev_dbg(musb->controller, "re-allocating DMA%d %cX channel %p\n",
|
||||
index, transmit ? 'T' : 'R', cppi_ch);
|
||||
cppi_ch->hw_ep = ep;
|
||||
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
|
||||
cppi_ch->channel.max_len = 0x7fffffff;
|
||||
|
||||
DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
|
||||
dev_dbg(musb->controller, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
|
||||
return &cppi_ch->channel;
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ static void cppi_channel_release(struct dma_channel *channel)
|
|||
c = container_of(channel, struct cppi_channel, channel);
|
||||
tibase = c->controller->tibase;
|
||||
if (!c->hw_ep)
|
||||
DBG(1, "releasing idle DMA channel %p\n", c);
|
||||
dev_dbg(musb->controller, "releasing idle DMA channel %p\n", c);
|
||||
else if (!c->transmit)
|
||||
core_rxirq_enable(tibase, c->index + 1);
|
||||
|
||||
|
|
@ -597,7 +597,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
|
|||
length = min(n_bds * maxpacket, length);
|
||||
}
|
||||
|
||||
DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
|
||||
dev_dbg(musb->controller, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
|
||||
tx->index,
|
||||
maxpacket,
|
||||
rndis ? "rndis" : "transparent",
|
||||
|
|
@ -654,7 +654,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
|
|||
bd->hw_options |= CPPI_ZERO_SET;
|
||||
}
|
||||
|
||||
DBG(5, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
|
||||
dev_dbg(musb->controller, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
|
||||
bd, bd->hw_next, bd->hw_bufp,
|
||||
bd->hw_off_len, bd->hw_options);
|
||||
|
||||
|
|
@ -819,7 +819,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
|
|||
|
||||
length = min(n_bds * maxpacket, length);
|
||||
|
||||
DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
|
||||
dev_dbg(musb->controller, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
|
||||
"dma 0x%llx len %u %u/%u\n",
|
||||
rx->index, maxpacket,
|
||||
onepacket
|
||||
|
|
@ -936,7 +936,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
|
|||
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
|
||||
& 0xffff;
|
||||
if (i < (2 + n_bds)) {
|
||||
DBG(2, "bufcnt%d underrun - %d (for %d)\n",
|
||||
dev_dbg(musb->controller, "bufcnt%d underrun - %d (for %d)\n",
|
||||
rx->index, i, n_bds);
|
||||
musb_writel(tibase,
|
||||
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
|
||||
|
|
@ -985,7 +985,7 @@ static int cppi_channel_program(struct dma_channel *ch,
|
|||
/* WARN_ON(1); */
|
||||
break;
|
||||
case MUSB_DMA_STATUS_UNKNOWN:
|
||||
DBG(1, "%cX DMA%d not allocated!\n",
|
||||
dev_dbg(musb->controller, "%cX DMA%d not allocated!\n",
|
||||
cppi_ch->transmit ? 'T' : 'R',
|
||||
cppi_ch->index);
|
||||
/* FALLTHROUGH */
|
||||
|
|
@ -1040,7 +1040,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
|
|||
if (!completed && (bd->hw_options & CPPI_OWN_SET))
|
||||
break;
|
||||
|
||||
DBG(5, "C/RXBD %llx: nxt %08x buf %08x "
|
||||
dev_dbg(musb->controller, "C/RXBD %llx: nxt %08x buf %08x "
|
||||
"off.len %08x opt.len %08x (%d)\n",
|
||||
(unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
|
||||
bd->hw_off_len, bd->hw_options,
|
||||
|
|
@ -1062,7 +1062,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
|
|||
* CPPI ignores those BDs even though OWN is still set.
|
||||
*/
|
||||
completed = true;
|
||||
DBG(3, "rx short %d/%d (%d)\n",
|
||||
dev_dbg(musb->controller, "rx short %d/%d (%d)\n",
|
||||
len, bd->buflen,
|
||||
rx->channel.actual_len);
|
||||
}
|
||||
|
|
@ -1112,7 +1112,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
|
|||
musb_ep_select(cppi->mregs, rx->index + 1);
|
||||
csr = musb_readw(regs, MUSB_RXCSR);
|
||||
if (csr & MUSB_RXCSR_DMAENAB) {
|
||||
DBG(4, "list%d %p/%p, last %llx%s, csr %04x\n",
|
||||
dev_dbg(musb->controller, "list%d %p/%p, last %llx%s, csr %04x\n",
|
||||
rx->index,
|
||||
rx->head, rx->tail,
|
||||
rx->last_processed
|
||||
|
|
@ -1175,7 +1175,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
|
||||
dev_dbg(musb->controller, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
|
||||
|
||||
/* process TX channels */
|
||||
for (index = 0; tx; tx = tx >> 1, index++) {
|
||||
|
|
@ -1203,7 +1203,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
|
|||
* that needs to be acknowledged.
|
||||
*/
|
||||
if (NULL == bd) {
|
||||
DBG(1, "null BD\n");
|
||||
dev_dbg(musb->controller, "null BD\n");
|
||||
musb_writel(&tx_ram->tx_complete, 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1218,7 +1218,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
|
|||
if (bd->hw_options & CPPI_OWN_SET)
|
||||
break;
|
||||
|
||||
DBG(5, "C/TXBD %p n %x b %x off %x opt %x\n",
|
||||
dev_dbg(musb->controller, "C/TXBD %p n %x b %x off %x opt %x\n",
|
||||
bd, bd->hw_next, bd->hw_bufp,
|
||||
bd->hw_off_len, bd->hw_options);
|
||||
|
||||
|
|
|
|||
|
|
@ -199,7 +199,8 @@ static void otg_timer(unsigned long _musb)
|
|||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
|
||||
otg_state_string(musb->xceiv->state));
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
switch (musb->xceiv->state) {
|
||||
|
|
@ -273,20 +274,22 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
|
|||
/* Never idle if active, or when VBUS timeout is not set as host */
|
||||
if (musb->is_active || (musb->a_wait_bcon == 0 &&
|
||||
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
|
||||
DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
del_timer(&otg_workaround);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
|
||||
DBG(4, "Longer idle timer already pending, ignoring...\n");
|
||||
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
DBG(4, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
|
||||
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +314,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
|
|||
goto eoi;
|
||||
|
||||
musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status);
|
||||
DBG(4, "USB IRQ %08x\n", status);
|
||||
dev_dbg(musb->controller, "USB IRQ %08x\n", status);
|
||||
|
||||
musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;
|
||||
musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT;
|
||||
|
|
@ -363,9 +366,9 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
|
|||
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
|
||||
}
|
||||
|
||||
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb),
|
||||
otg_state_string(musb->xceiv->state),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
ret = IRQ_HANDLED;
|
||||
|
|
@ -410,7 +413,7 @@ static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
|
|||
break;
|
||||
#endif
|
||||
default:
|
||||
DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
|
||||
dev_dbg(musb->controller, "Trying to set unsupported mode %u\n", musb_mode);
|
||||
}
|
||||
|
||||
__raw_writel(cfgchip2, CFGCHIP2);
|
||||
|
|
|
|||
|
|
@ -220,7 +220,8 @@ static void otg_timer(unsigned long _musb)
|
|||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
|
||||
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
|
||||
otg_state_string(musb->xceiv->state));
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
switch (musb->xceiv->state) {
|
||||
|
|
@ -297,7 +298,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
|
|||
/* ack and handle non-CPPI interrupts */
|
||||
tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
|
||||
musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
|
||||
DBG(4, "IRQ %08x\n", tmp);
|
||||
dev_dbg(musb->controller, "IRQ %08x\n", tmp);
|
||||
|
||||
musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
|
||||
>> DAVINCI_USB_RXINT_SHIFT;
|
||||
|
|
@ -354,9 +355,9 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
|
|||
* (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
|
||||
*/
|
||||
davinci_musb_source_power(musb, drvvbus, 0);
|
||||
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb),
|
||||
otg_state_string(musb->xceiv->state),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
retval = IRQ_HANDLED;
|
||||
|
|
@ -484,7 +485,7 @@ static int davinci_musb_exit(struct musb *musb)
|
|||
break;
|
||||
if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
|
||||
warn = devctl & MUSB_DEVCTL_VBUS;
|
||||
DBG(1, "VBUS %d\n",
|
||||
dev_dbg(musb->controller, "VBUS %d\n",
|
||||
warn >> MUSB_DEVCTL_VBUS_SHIFT);
|
||||
}
|
||||
msleep(1000);
|
||||
|
|
@ -493,7 +494,7 @@ static int davinci_musb_exit(struct musb *musb)
|
|||
|
||||
/* in OTG mode, another host might be connected */
|
||||
if (devctl & MUSB_DEVCTL_VBUS)
|
||||
DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
|
||||
dev_dbg(musb->controller, "VBUS off timeout (devctl %02x)\n", devctl);
|
||||
}
|
||||
|
||||
phy_off();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue