summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/class/cdc-acm.c7
-rw-r--r--drivers/usb/class/cdc-wdm.c30
-rw-r--r--drivers/usb/class/usbtmc.c36
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/devices.c2
-rw-r--r--drivers/usb/core/devio.c61
-rw-r--r--drivers/usb/core/driver.c3
-rw-r--r--drivers/usb/core/generic.c27
-rw-r--r--drivers/usb/core/hcd.c27
-rw-r--r--drivers/usb/core/hub.c19
-rw-r--r--drivers/usb/core/message.c8
-rw-r--r--drivers/usb/core/sysfs.c6
-rw-r--r--drivers/usb/core/usb.c31
-rw-r--r--drivers/usb/gadget/Kconfig9
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/amd5536udc.c49
-rw-r--r--drivers/usb/gadget/arcotg_udc.c451
-rw-r--r--drivers/usb/gadget/arcotg_udc.h11
-rw-r--r--drivers/usb/gadget/composite.c39
-rw-r--r--drivers/usb/gadget/f_acm.c9
-rw-r--r--drivers/usb/gadget/file_storage.c9
-rw-r--r--drivers/usb/host/ehci-arc.c280
-rw-r--r--drivers/usb/host/ehci-hcd.c7
-rw-r--r--drivers/usb/host/ehci-hub.c21
-rw-r--r--drivers/usb/host/ehci-pci.c6
-rw-r--r--drivers/usb/host/ehci-q.c27
-rw-r--r--drivers/usb/host/ehci-sched.c12
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-pci.c20
-rw-r--r--drivers/usb/host/ohci-q.c18
-rw-r--r--drivers/usb/host/ohci.h9
-rw-r--r--drivers/usb/host/sl811-hcd.c8
-rw-r--r--drivers/usb/host/uhci-hcd.c15
-rw-r--r--drivers/usb/host/uhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-dbg.c5
-rw-r--r--drivers/usb/host/xhci-hcd.c370
-rw-r--r--drivers/usb/host/xhci-mem.c74
-rw-r--r--drivers/usb/host/xhci-pci.c13
-rw-r--r--drivers/usb/host/xhci-ring.c239
-rw-r--r--drivers/usb/host/xhci.h41
-rw-r--r--drivers/usb/misc/appledisplay.c4
-rw-r--r--drivers/usb/misc/emi62.c2
-rw-r--r--drivers/usb/mon/mon_bin.c11
-rw-r--r--drivers/usb/musb/musb_gadget.c79
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c15
-rw-r--r--drivers/usb/otg/fsl_otg.c219
-rw-r--r--drivers/usb/serial/ark3116.c46
-rw-r--r--drivers/usb/serial/console.c28
-rw-r--r--drivers/usb/serial/cp210x.c28
-rw-r--r--drivers/usb/serial/cypress_m8.c12
-rw-r--r--drivers/usb/serial/digi_acceleport.c8
-rw-r--r--drivers/usb/serial/empeg.c12
-rw-r--r--drivers/usb/serial/ftdi_sio.c432
-rw-r--r--drivers/usb/serial/ftdi_sio.h10
-rw-r--r--drivers/usb/serial/generic.c4
-rw-r--r--drivers/usb/serial/ipaq.c9
-rw-r--r--drivers/usb/serial/iuu_phoenix.c31
-rw-r--r--drivers/usb/serial/kobil_sct.c22
-rw-r--r--drivers/usb/serial/option.c60
-rw-r--r--drivers/usb/serial/oti6858.c21
-rw-r--r--drivers/usb/serial/pl2303.c9
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/usb/serial/sierra.c23
-rw-r--r--drivers/usb/serial/spcp8x5.c21
-rw-r--r--drivers/usb/serial/usb-serial.c391
-rw-r--r--drivers/usb/serial/whiteheat.c6
-rw-r--r--drivers/usb/storage/initializers.c2
-rw-r--r--drivers/usb/storage/onetouch.c2
-rw-r--r--drivers/usb/storage/transport.c59
-rw-r--r--drivers/usb/storage/unusual_devs.h14
-rw-r--r--drivers/usb/storage/usb.c21
72 files changed, 1969 insertions, 1648 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b8134ad5f05f..b72fa49eb257 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -609,9 +609,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->throttle = 0;
- tasklet_schedule(&acm->urb_task);
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
+ tasklet_schedule(&acm->urb_task);
done:
mutex_unlock(&acm->mutex);
err_out:
@@ -860,10 +860,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
if (!ACM_READY(acm))
return;
- /* FIXME: Needs to support the tty_baud interface */
- /* FIXME: Broken on sparc */
- newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
- (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
+ newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) +
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index ba589d4ca8bc..a9c33994459b 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -313,8 +313,13 @@ static ssize_t wdm_write
r = usb_autopm_get_interface(desc->intf);
if (r < 0)
goto outnp;
- r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
- &desc->flags));
+
+ if (!file->f_flags && O_NONBLOCK)
+ r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
+ &desc->flags));
+ else
+ if (test_bit(WDM_IN_USE, &desc->flags))
+ r = -EAGAIN;
if (r < 0)
goto out;
@@ -377,7 +382,7 @@ outnl:
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- int rv, cntr;
+ int rv, cntr = 0;
int i = 0;
struct wdm_device *desc = file->private_data;
@@ -389,10 +394,23 @@ static ssize_t wdm_read
if (desc->length == 0) {
desc->read = 0;
retry:
+ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ rv = -ENODEV;
+ goto err;
+ }
i++;
- rv = wait_event_interruptible(desc->wait,
- test_bit(WDM_READ, &desc->flags));
+ if (file->f_flags & O_NONBLOCK) {
+ if (!test_bit(WDM_READ, &desc->flags)) {
+ rv = cntr ? cntr : -EAGAIN;
+ goto err;
+ }
+ rv = 0;
+ } else {
+ rv = wait_event_interruptible(desc->wait,
+ test_bit(WDM_READ, &desc->flags));
+ }
+ /* may have happened while we slept */
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = -ENODEV;
goto err;
@@ -448,7 +466,7 @@ retry:
err:
mutex_unlock(&desc->rlock);
- if (rv < 0)
+ if (rv < 0 && rv != -EAGAIN)
dev_err(&desc->intf->dev, "wdm_read: exit error\n");
return rv;
}
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index b09a527f7341..aa145f7b4e25 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -367,13 +367,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
{
struct usbtmc_device_data *data;
struct device *dev;
- unsigned long int n_characters;
+ u32 n_characters;
u8 *buffer;
int actual;
- int done;
- int remaining;
+ size_t done;
+ size_t remaining;
int retval;
- int this_part;
+ size_t this_part;
/* Get pointer to private data structure */
data = filp->private_data;
@@ -455,6 +455,18 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
(buffer[6] << 16) +
(buffer[7] << 24);
+ /* Ensure the instrument doesn't lie about it */
+ if(n_characters > actual - 12) {
+ dev_err(dev, "Device lies about message size: %zu > %zu\n", n_characters, actual - 12);
+ n_characters = actual - 12;
+ }
+
+ /* Ensure the instrument doesn't send more back than requested */
+ if(n_characters > this_part) {
+ dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
+ n_characters = this_part;
+ }
+
/* Copy buffer to user space */
if (copy_to_user(buf + done, &buffer[12], n_characters)) {
/* There must have been an addressing problem */
@@ -465,6 +477,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
done += n_characters;
if (n_characters < USBTMC_SIZE_IOBUFFER)
remaining = 0;
+ else
+ remaining -= n_characters;
}
/* Update file position value */
@@ -531,10 +545,16 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
n_bytes = roundup(12 + this_part, 4);
memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part));
- retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes, &actual, USBTMC_TIMEOUT);
+ do {
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev,
+ data->bulk_out),
+ buffer, n_bytes,
+ &actual, USBTMC_TIMEOUT);
+ if (retval != 0)
+ break;
+ n_bytes -= actual;
+ } while (n_bytes);
data->bTag_last_write = data->bTag;
data->bTag++;
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index a16c538d0132..0d3af6a6ee49 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp->extralen = i;
buffer += i;
size -= i;
- retval = buffer - buffer_start + i;
+ retval = buffer - buffer_start;
if (num_skipped > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
num_skipped, plural(num_skipped),
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 96f11715cd26..355dffcc23b0 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -494,7 +494,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
return 0;
/* allocate 2^1 pages = 8K (on i386);
* should be more than enough for one device */
- pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
+ pages_start = (char *)__get_free_pages(GFP_NOIO, 1);
if (!pages_start)
return -ENOMEM;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4247eccf858c..5ae4099fb4c1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1139,6 +1139,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
free_async(as);
return -ENOMEM;
}
+ /* Isochronous input data may end up being discontiguous
+ * if some of the packets are short. Clear the buffer so
+ * that the gaps don't leak kernel data to userspace.
+ */
+ if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
+ memset(as->urb->transfer_buffer, 0,
+ uurb->buffer_length);
}
as->urb->dev = ps->dev;
as->urb->pipe = (uurb->type << 30) |
@@ -1240,10 +1247,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
void __user *addr = as->userurb;
unsigned int i;
- if (as->userbuffer)
- if (copy_to_user(as->userbuffer, urb->transfer_buffer,
- urb->transfer_buffer_length))
+ if (as->userbuffer && urb->actual_length) {
+ if (urb->number_of_packets > 0) /* Isochronous */
+ i = urb->transfer_buffer_length;
+ else /* Non-Isoc */
+ i = urb->actual_length;
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
goto err_out;
+ }
if (put_user(as->status, &userurb->status))
goto err_out;
if (put_user(urb->actual_length, &userurb->actual_length))
@@ -1262,14 +1273,11 @@ static int processcompl(struct async *as, void __user * __user *arg)
}
}
- free_async(as);
-
if (put_user(addr, (void __user * __user *)arg))
return -EFAULT;
return 0;
err_out:
- free_async(as);
return -EFAULT;
}
@@ -1299,8 +1307,11 @@ static struct async *reap_as(struct dev_state *ps)
static int proc_reapurb(struct dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
- if (as)
- return processcompl(as, (void __user * __user *)arg);
+ if (as) {
+ int retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
if (signal_pending(current))
return -EINTR;
return -EIO;
@@ -1308,11 +1319,16 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
{
+ int retval;
struct async *as;
- if (!(as = async_getcompleted(ps)))
- return -EAGAIN;
- return processcompl(as, (void __user * __user *)arg);
+ as = async_getcompleted(ps);
+ retval = -EAGAIN;
+ if (as) {
+ retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
}
#ifdef CONFIG_COMPAT
@@ -1363,9 +1379,9 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
void __user *addr = as->userurb;
unsigned int i;
- if (as->userbuffer)
+ if (as->userbuffer && urb->actual_length)
if (copy_to_user(as->userbuffer, urb->transfer_buffer,
- urb->transfer_buffer_length))
+ urb->actual_length))
return -EFAULT;
if (put_user(as->status, &userurb->status))
return -EFAULT;
@@ -1385,7 +1401,6 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
}
}
- free_async(as);
if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
return -EFAULT;
return 0;
@@ -1394,8 +1409,11 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
- if (as)
- return processcompl_compat(as, (void __user * __user *)arg);
+ if (as) {
+ int retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
if (signal_pending(current))
return -EINTR;
return -EIO;
@@ -1403,11 +1421,16 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
{
+ int retval;
struct async *as;
- if (!(as = async_getcompleted(ps)))
- return -EAGAIN;
- return processcompl_compat(as, (void __user * __user *)arg);
+ retval = -EAGAIN;
+ as = async_getcompleted(ps);
+ if (as) {
+ retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
}
#endif
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 07f503aa9078..c209dbe4f6c6 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1754,9 +1754,6 @@ int usb_resume(struct device *dev, pm_message_t msg)
udev = to_usb_device(dev);
-/* At otg mode, if it is a device wakeup interrupt, the host should do nothing */
- if (udev->bus->is_b_host)
- return 0;
/* If udev->skip_sys_resume is set then udev was already suspended
* when the system sleep started, so we don't want to resume it
* during this system wakeup.
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 539a2c0dde00..66e8a424c9f4 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -196,6 +196,7 @@ extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
int rc;
+ u32 temp;
/* Normal USB devices suspend through their upstream port.
* Root hubs don't have upstream ports to suspend,
@@ -203,7 +204,25 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
* interfaces manually by doing a bus (or "global") suspend.
*/
if (!udev->parent) {
+ struct usb_hcd *hcd =
+ container_of(udev->bus, struct usb_hcd, self);
+ struct fsl_usb2_platform_data *pdata;
+ pdata = hcd->self.controller->platform_data;
+
rc = hcd_bus_suspend(udev, msg);
+
+ if (device_may_wakeup(hcd->self.controller)) {
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ /* enable remote wake up irq */
+ usb_host_set_wakeup(hcd->self.controller, true);
+
+ /* Put PHY into low power mode */
+ temp = readl(hcd->regs + 0x184);
+ writel(temp | (1 << 23), (hcd->regs + 0x184));
+
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(false);
+ }
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
} else if (msg.event == PM_EVENT_FREEZE ||
msg.event == PM_EVENT_PRETHAW)
@@ -217,6 +236,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
static int generic_resume(struct usb_device *udev, pm_message_t msg)
{
int rc;
+ u32 temp;
/* Normal USB devices resume/reset through their upstream port.
* Root hubs don't have upstream ports to resume or reset,
@@ -224,6 +244,13 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg)
* interfaces manually by doing a bus (or "global") resume.
*/
if (!udev->parent) {
+ struct usb_hcd *hcd =
+ container_of(udev->bus, struct usb_hcd, self);
+
+ if (device_may_wakeup(hcd->self.controller)) {
+ temp = readl(hcd->regs + 0x184);
+ writel(temp & (~(1 << 23)), (hcd->regs + 0x184));
+ }
rc = hcd_bus_resume(udev, msg);
} else
rc = usb_port_resume(udev, msg);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2f47bdc7c93a..d27ad104731c 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1739,7 +1739,6 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
int status;
int old_state = hcd->state;
- printk("%s\n", __func__);
dev_dbg(&rhdev->dev, "bus %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
if (!hcd->driver->bus_suspend) {
@@ -1877,6 +1876,7 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
struct usb_hcd *hcd = __hcd;
+ struct fsl_usb2_platform_data *pdata;
unsigned long flags;
irqreturn_t rc;
@@ -1885,14 +1885,25 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
* assume it's never used.
*/
local_irq_save(flags);
- /* At otg mode, the host does need to handle device interrupt */
- if (hcd->self.is_b_host){
- local_irq_restore(flags);
- return IRQ_NONE;
- }
- else if (unlikely(hcd->state == HC_STATE_HALT ||
- !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ /* Need open clock for register access */
+ pdata = hcd->self.controller->platform_data;
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(true);
+
+ /* if receive a remote wakeup interrrupt after suspend */
+ if (usb_host_wakeup_irq(hcd->self.controller)) {
+ /* disable remote wake up irq */
+ usb_host_set_wakeup(hcd->self.controller, false);
+
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ hcd->driver->irq(hcd);
+ rc = IRQ_HANDLED;
+ } else
rc = IRQ_NONE;
+ } else if (unlikely(hcd->state == HC_STATE_HALT)) {
+ rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE;
} else {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index cc8f911afbc4..3bcd08fbfb71 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -457,7 +457,7 @@ resubmit:
static inline int
hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
{
- return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
tt, NULL, 0, 1000);
}
@@ -1177,6 +1177,12 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
"Unsupported bus topology: hub nested too deep\n");
return -E2BIG;
}
+#ifdef CONFIG_PM
+ /* Defaultly disable autosuspend for hub and reley on sys
+ * to enable it.
+ */
+ hdev->autosuspend_disabled = 1;
+#endif
#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
if (hdev->parent) {
@@ -2298,6 +2304,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
+
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
@@ -2321,15 +2328,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
static int hub_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
- struct usb_hcd *hcd = bus_to_hcd(hub->hdev->bus);
dev_dbg(&intf->dev, "%s\n", __func__);
- /* At otg mode, if the hcd which the hub is attached to is not accessible,
- * It should do nothing.
- */
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
- return 0;
-
hub_activate(hub, HUB_RESUME);
return 0;
}
@@ -3286,6 +3286,9 @@ static void hub_events(void)
USB_PORT_FEAT_C_SUSPEND);
udev = hdev->children[i-1];
if (udev) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+
usb_lock_device(udev);
ret = remote_wakeup(hdev->
children[i-1]);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 9720e699f472..8c929daa71f2 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -923,11 +923,11 @@ char *usb_cache_string(struct usb_device *udev, int index)
if (index <= 0)
return NULL;
- buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
+ buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO);
if (buf) {
len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
if (len > 0) {
- smallbuf = kmalloc(++len, GFP_KERNEL);
+ smallbuf = kmalloc(++len, GFP_NOIO);
if (!smallbuf)
return buf;
memcpy(smallbuf, buf, len);
@@ -1694,7 +1694,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp) {
nintf = cp->desc.bNumInterfaces;
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
- GFP_KERNEL);
+ GFP_NOIO);
if (!new_interfaces) {
dev_err(&dev->dev, "Out of memory\n");
return -ENOMEM;
@@ -1703,7 +1703,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
for (; n < nintf; ++n) {
new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
- GFP_KERNEL);
+ GFP_NOIO);
if (!new_interfaces[n]) {
dev_err(&dev->dev, "Out of memory\n");
ret = -ENOMEM;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index b5c72e458943..7bc1469c8f0e 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -111,6 +111,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
case USB_SPEED_HIGH:
speed = "480";
break;
+ case USB_SPEED_VARIABLE:
+ speed = "480";
+ break;
+ case USB_SPEED_SUPER:
+ speed = "5000";
+ break;
default:
speed = "unknown";
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index a26f73880c32..b661dbd93208 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);
struct find_interface_arg {
int minor;
- struct usb_interface *interface;
+ struct device_driver *drv;
};
static int __find_interface(struct device *dev, void *data)
@@ -143,12 +143,10 @@ static int __find_interface(struct device *dev, void *data)
if (!is_usb_interface(dev))
return 0;
+ if (dev->driver != arg->drv)
+ return 0;
intf = to_usb_interface(dev);
- if (intf->minor != -1 && intf->minor == arg->minor) {
- arg->interface = intf;
- return 1;
- }
- return 0;
+ return intf->minor == arg->minor;
}
/**
@@ -156,21 +154,24 @@ static int __find_interface(struct device *dev, void *data)
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
- * This walks the driver device list and returns a pointer to the interface
- * with the matching minor. Note, this only works for devices that share the
- * USB major number.
+ * This walks the bus device list and returns a pointer to the interface
+ * with the matching minor and driver. Note, this only works for devices
+ * that share the USB major number.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct find_interface_arg argb;
- int retval;
+ struct device *dev;
argb.minor = minor;
- argb.interface = NULL;
- /* eat the error, it will be in argb.interface */
- retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
- __find_interface);
- return argb.interface;
+ argb.drv = &drv->drvwrap.driver;
+
+ dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface);
+
+ /* Drop reference count from bus_find_device */
+ put_device(dev);
+
+ return dev ? to_usb_interface(dev) : NULL;
}
EXPORT_SYMBOL_GPL(usb_find_interface);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c29ebda61b2f..a19d73730470 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -791,15 +791,6 @@ config USB_G_PRINTER
For more information, see Documentation/usb/gadget_printer.txt
which includes sample code for accessing the device file.
-config USB_ANDROID
- tristate "Android Gadget"
- depends on SWITCH
- help
- The Android gadget provides mass storage and adb transport.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "g_android".
-
config USB_CDC_COMPOSITE
tristate "CDC Composite Device (Ethernet and ACM)"
depends on NET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 545c0e256e28..477114e43372 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -41,7 +41,6 @@ gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o
g_printer-objs := printer.o
g_cdc-objs := cdc2.o
-g_android-objs := android.o f_adb.o f_mass_storage.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -52,5 +51,4 @@ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
-obj-$(CONFIG_USB_ANDROID) += g_android.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 77352ccc245e..fb0976643a2f 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
tmp &= AMD_UNMASK_BIT(ep->num);
writel(tmp, &dev->regs->ep_irqmsk);
}
- }
+ } else if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
} else if (ep->dma) {
@@ -2005,18 +2010,17 @@ __acquires(dev->lock)
{
int tmp;
- /* empty queues and init hardware */
- udc_basic_init(dev);
- for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
- empty_req_queue(&dev->ep[tmp]);
- }
-
if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
- /* init */
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+ empty_req_queue(&dev->ep[tmp]);
+
udc_setup_endpoints(dev);
}
@@ -2478,6 +2482,13 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
}
}
+ } else if (!use_dma && ep->in) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
}
}
/* clear status bits */
@@ -3285,6 +3296,17 @@ static int udc_pci_probe(
goto finished;
}
+ spin_lock_init(&dev->lock);
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
@@ -3337,7 +3359,6 @@ static int udc_probe(struct udc *dev)
udc_pollstall_timer.data = 0;
/* device struct setup */
- spin_lock_init(&dev->lock);
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
@@ -3346,16 +3367,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.name = name;
dev->gadget.is_dualspeed = 1;
- /* udc csr registers base */
- dev->csr = dev->virt_addr + UDC_CSR_ADDR;
- /* dev registers base */
- dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
- /* ep registers base */
- dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
- /* fifo's base */
- dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
- dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
-
/* init registers, interrupts, ... */
startup_registers(dev);
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 8e94549f891e..abba4d2ae8d4 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -106,6 +106,19 @@ extern struct resource *otg_get_resources(void);
extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode);
+static inline void
+dr_wake_up_enable(struct fsl_udc *udc, bool enable)
+{
+ struct fsl_usb2_platform_data *pdata;
+ pdata = udc->pdata;
+
+ if (enable && (!device_may_wakeup(udc_controller->gadget.dev.parent)))
+ return;
+
+ if (pdata->wake_up_enable)
+ pdata->wake_up_enable(pdata, enable);
+}
+
#ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW
static void safe_writel(u32 val32, void *addr)
{
@@ -270,12 +283,9 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
static void nuke(struct fsl_ep *ep, int status)
{
ep->stopped = 1;
- /*
- * At udc stop mode, the clock is already off
- * So flush fifo, should be done at clock on mode.
- */
- if (!ep->udc->stopped)
- fsl_ep_fifo_flush(&ep->ep);
+
+ /* Flush fifo */
+ fsl_ep_fifo_flush(&ep->ep);
/* Whether this eq has request linked */
while (!list_empty(&ep->queue)) {
@@ -290,83 +300,31 @@ static void nuke(struct fsl_ep *ep, int status)
/*------------------------------------------------------------------
Internal Hardware related function
------------------------------------------------------------------*/
-static inline void
-dr_wake_up_enable(struct fsl_udc *udc, bool enable)
-{
- struct fsl_usb2_platform_data *pdata;
- pdata = udc->pdata;
- if (pdata && pdata->wake_up_enable)
- pdata->wake_up_enable(pdata, enable);
-}
-static bool clk_stoped = false;
-static inline void dr_clk_gate(bool on)
+static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
{
- struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
+ u32 temp;
- if (!pdata || !pdata->usb_clock_for_pm)
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent))
return;
- if (on && clk_stoped) {
- pdata->usb_clock_for_pm(true);
- clk_stoped = false;
- }
- if (!on && !clk_stoped) {
- pdata->usb_clock_for_pm(false);
- clk_stoped = true;
- }
- if (on)
- reset_phy();
-}
-static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
-{
- struct fsl_usb2_platform_data *pdata = udc->pdata;
- u32 portsc;
+ if (enable) {
+ temp = fsl_readl(&dr_regs->portsc1);
+ temp |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(temp, &dr_regs->portsc1);
- if (pdata && pdata->phy_lowpower_suspend) {
- pdata->phy_lowpower_suspend(enable);
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
} else {
- if (enable){
- portsc = fsl_readl(&dr_regs->portsc1);
- portsc |= PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(portsc, &dr_regs->portsc1);
- } else {
- portsc = fsl_readl(&dr_regs->portsc1);
- portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(portsc, &dr_regs->portsc1);
- }
- }
-}
-
-
-/* workaroud for some boards, maybe there is a large capacitor between the ground and the Vbus
- * that will cause the vbus dropping very slowly when device is detached,
- * may cost 2-3 seconds to below 0.8V */
-static void udc_wait_b_session_low(void)
-{
- u32 temp;
- u32 wait = 5000; /* max wait time is 5000 ms */
- /* if we are in host mode, don't need to care the B session */
- if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0)
- return;
- /* if the udc is dettached , there will be a suspend irq */
- if (udc_controller->usb_state != USB_STATE_SUSPENDED)
- return;
- temp = fsl_readl(&dr_regs->otgsc);
- temp &= ~(OTGSC_B_SESSION_VALID_IRQ_EN );
- fsl_writel(temp, &dr_regs->otgsc);
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
- do {
- if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID))
- break;
- mdelay(1);
- wait -= 1;
- } while(wait);
- if (!wait)
- printk("ERROR!!!!!: the vbus can not be lower then 0.8V for 5 seconds, Pls Check your HW design\n");
- temp = fsl_readl(&dr_regs->otgsc);
- temp |= (OTGSC_B_SESSION_VALID_IRQ_EN );
- fsl_writel(temp, &dr_regs->otgsc);
+ /* Due to mx35/mx25's phy's bug */
+ reset_phy();
+ temp = fsl_readl(&dr_regs->portsc1);
+ temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(temp, &dr_regs->portsc1);
+ }
}
static int dr_controller_setup(struct fsl_udc *udc)
@@ -490,20 +448,23 @@ static void dr_controller_run(struct fsl_udc *udc)
fsl_writel(temp, &dr_regs->usbintr);
- /* enable BSV irq */
- temp = fsl_readl(&dr_regs->otgsc);
- temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
- fsl_writel(temp, &dr_regs->otgsc);
+ if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
+ /* enable BSV irq */
+ temp = fsl_readl(&dr_regs->otgsc);
+ temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
+ fsl_writel(temp, &dr_regs->otgsc);
+ }
/* If vbus not on and used low power mode */
- if (!(temp & OTGSC_B_SESSION_VALID)) {
- /* Set stopped before low power mode */
- udc->stopped = 1;
+ if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)
+ && device_may_wakeup(udc_controller->gadget.dev.parent)) {
/* enable wake up */
dr_wake_up_enable(udc, true);
- /* enter lower power mode */
+ /* Set stopped before low power mode */
+ udc->stopped = 1;
+ /* close PHY clock */
dr_phy_low_power_mode(udc, true);
- printk(KERN_INFO "%s: udc enter low power mode \n", __func__);
+ printk(KERN_INFO "udc enter low power mode \n");
} else {
#ifdef CONFIG_ARCH_MX37
/*
@@ -515,11 +476,11 @@ static void dr_controller_run(struct fsl_udc *udc)
#endif
/* Clear stopped bit */
udc->stopped = 0;
-
- /* The usb line has already been connected to pc */
+ /* Set controller to Run */
temp = fsl_readl(&dr_regs->usbcmd);
temp |= USB_CMD_RUN_STOP;
fsl_writel(temp, &dr_regs->usbcmd);
+ printk(KERN_INFO "udc run \n");
}
return;
@@ -2015,36 +1976,15 @@ static void suspend_irq(struct fsl_udc *udc)
udc->driver->suspend(&udc->gadget);
}
-/* Process Wake up interrupt
- * Be careful that some boards will use ID pin to control the VBUS on/off
- * in these case, after the device enter the lowpower mode(clk off,
- * phy lowpower mode, wakeup enable), then an udisk is attaced to the otg port,
- * there will be an Vbus wakeup event and then an ID change wakeup, But the Vbus
- * event is not expected, so there is an workaround that will detect the ID, if ID=0
- * we just need the ID event so we can not disable the wakeup
- *
- * false: host wakeup event
- * true: device wakeup event
-*/
-static bool wake_up_irq(struct fsl_udc *udc)
-{
- /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will
- * be delayed max 2 ms to show the real ID pin value
- */
- mdelay(3);
-
- /* if the ID=0, let arc host process the wakeup */
- if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) {
- dr_wake_up_enable(udc_controller, false);
- dr_phy_low_power_mode(udc, false);
- printk("device wake up event\n");
- return true;
- }else {/* wakeup is vbus wake event, but not for device so we need to clear b session */
- int irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS);
- fsl_writel(irq_src, &dr_regs->otgsc);
- printk("The host wakeup event, should be handled by host\n");
- return false;
- }
+/* Process Wake up interrupt */
+static void wake_up_irq(struct fsl_udc *udc)
+{
+ pr_debug("%s\n", __func__);
+
+ /* disable wake up irq */
+ dr_wake_up_enable(udc_controller, false);
+
+ udc->stopped = 0;
}
static void bus_resume(struct fsl_udc *udc)
@@ -2113,48 +2053,43 @@ static void reset_irq(struct fsl_udc *udc)
bool try_wake_up_udc(struct fsl_udc *udc)
{
u32 irq_src;
- bool b_device;
/* when udc is stopped, only handle wake up irq */
if (udc->stopped) {
+ if (!device_may_wakeup(&(udc->pdata->pdev->dev)))
+ return false;
+
+ dr_phy_low_power_mode(udc_controller, false);
+
/* check to see if wake up irq */
irq_src = fsl_readl(&dr_regs->usbctrl);
if (irq_src & USB_CTRL_OTG_WUIR) {
- if (wake_up_irq(udc) == false){
- return false; /* host wakeup event */
- }
+ wake_up_irq(udc);
+ } else {
+ dr_phy_low_power_mode(udc_controller, true);
}
}
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent))
+ return true;
+
/* check if Vbus change irq */
irq_src = fsl_readl(&dr_regs->otgsc);
if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) {
u32 tmp;
- /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will
- * be delayed max 2 ms to show the real ID pin value, as it needs to use ID to judge
- * host or device
- */
- mdelay(3);
- b_device = (irq_src & OTGSC_STS_USB_ID)? true:false;
fsl_writel(irq_src, &dr_regs->otgsc);
- if (!b_device)
- return false;
tmp = fsl_readl(&dr_regs->usbcmd);
/* check BSV bit to see if fall or rise */
if (irq_src & OTGSC_B_SESSION_VALID) {
- if (udc->suspended) /*let the system pm resume the udc */
- return true;
udc->stopped = 0;
fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd);
- printk(KERN_INFO "%s: udc out low power mode\n", __func__);
+ printk(KERN_INFO "udc out low power mode\n");
} else {
- printk(KERN_INFO "%s: udc enter low power mode \n", __func__);
- if (udc->driver)
- udc->driver->disconnect(&udc->gadget);
+ printk(KERN_INFO "udc enter low power mode \n");
fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd);
- udc->stopped = 1;
/* enable wake up */
dr_wake_up_enable(udc, true);
+ udc->stopped = 1;
/* close USB PHY clock */
dr_phy_low_power_mode(udc, true);
return false;
@@ -2163,6 +2098,7 @@ bool try_wake_up_udc(struct fsl_udc *udc)
return true;
}
+
/*
* USB device controller interrupt handler
*/
@@ -2173,29 +2109,15 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
irqreturn_t status = IRQ_NONE;
unsigned long flags;
- spin_lock_irqsave(&udc->lock, flags);
- if (udc->stopped)
- dr_clk_gate(true);
-
- if (try_wake_up_udc(udc) == false) {
- goto irq_end;
- }
-#ifdef CONFIG_USB_OTG
- /* if no gadget register in this driver, we need do noting */
- if (udc->transceiver->gadget == NULL)
- goto irq_end;
-
- /* only handle device interrupt event */
- if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
- goto irq_end;
- }
-#endif
+ if (try_wake_up_udc(udc) == false)
+ return IRQ_NONE;
+ spin_lock_irqsave(&udc->lock, flags);
irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
/* Clear notification bits */
fsl_writel(irq_src, &dr_regs->usbsts);
- VDBG("0x%x\n", irq_src);
+ /* VDBG("irq_src [0x%8x]", irq_src); */
/* Need to resume? */
if (udc->usb_state == USB_STATE_SUSPENDED)
@@ -2240,24 +2162,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* Sleep Enable (Suspend) */
if (irq_src & USB_STS_SUSPEND) {
- VDBG("suspend int");
suspend_irq(udc);
status = IRQ_HANDLED;
}
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
- printk(KERN_ERR "Error IRQ %x ", irq_src);
- if (irq_src & USB_STS_SYS_ERR) {
- printk(KERN_ERR "This error can't be recoveried, \
- please reboot your board\n");
- printk(KERN_ERR "If this error happens frequently, \
- please check your dma buffer\n");
- }
- }
-
-irq_end:
- if (udc->stopped){
- dr_clk_gate(false);
+ VDBG("Error IRQ %x ", irq_src);
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -2272,6 +2182,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int retval = -ENODEV;
unsigned long flags = 0;
+ u32 portsc;
if (!udc_controller)
return -ENODEV;
@@ -2289,18 +2200,17 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(&udc_controller->lock, flags);
driver->driver.bus = 0;
- udc_controller->pdata->port_enables = 1;
/* hook up the driver */
udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
- dr_clk_gate(true);
- /* It doesn't need to switch usb from low power mode to normal mode
- * at otg mode
- */
- if (!udc_controller->transceiver){
- dr_phy_low_power_mode(udc_controller, false);
- }
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
+
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
/* bind udc driver to gadget driver */
retval = driver->bind(&udc_controller->gadget);
@@ -2313,30 +2223,30 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (udc_controller->transceiver) {
/* Suspend the controller until OTG enable it */
- udc_controller->suspended = 1;/* let the otg resume it */
+ udc_controller->stopped = 1;
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
dr_wake_up_enable(udc_controller, true);
+ dr_phy_low_power_mode(udc_controller, true);
/* export udc suspend/resume call to OTG */
udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend;
udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume;
/* connect to bus through 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;
+ 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;
+ }
}
- //dr_clk_gate(false);
} else {
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
dr_controller_run(udc_controller);
- if (udc_controller->stopped)
- dr_clk_gate(false);
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
}
@@ -2344,10 +2254,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
udc_controller->gadget.name, driver->driver.name);
out:
- if (retval){
+ if (retval)
printk(KERN_DEBUG "retval %d \n", retval);
- udc_controller->pdata->port_enables = 0;
- }
return retval;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -2357,6 +2265,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct fsl_ep *loop_ep;
unsigned long flags;
+ u32 portsc;
if (!udc_controller)
return -ENODEV;
@@ -2364,16 +2273,15 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
- if(udc_controller->stopped)
- dr_clk_gate(true);
-
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
+ /* open phy clock for following operation */
+ dr_phy_low_power_mode(udc_controller, false);
+
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
- udc_controller->pdata->port_enables = 0;
/* in fact, no needed */
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
@@ -2395,11 +2303,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
udc_controller->gadget.dev.driver = 0;
udc_controller->driver = 0;
- if (udc_controller->gadget.is_otg) {
- dr_wake_up_enable(udc_controller, true);
- }
+ dr_wake_up_enable(udc_controller, false);
- dr_phy_low_power_mode(udc_controller, true);
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
printk(KERN_INFO "unregistered gadget driver '%s'\r\n",
driver->driver.name);
@@ -2814,7 +2725,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err1a;
}
- udc_controller->gadget.is_otg = 1;
#endif
if ((pdev->dev.parent) &&
@@ -2915,6 +2825,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
if (ret < 0)
goto err3;
+ if (udc_controller->transceiver) {
+ udc_controller->gadget.is_otg = 1;
+ /* now didn't support lpm in OTG mode*/
+ device_set_wakeup_capable(&pdev->dev, 0);
+ }
+
/* setup QH and epctrl for ep0 */
ep0_setup(udc_controller);
@@ -2957,29 +2873,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#ifdef POSTPONE_FREE_LAST_DTD
last_free_td = NULL;
#endif
-
#ifndef CONFIG_USB_OTG
/* disable all INTR */
fsl_writel(0, &dr_regs->usbintr);
+
dr_wake_up_enable(udc_controller, false);
-#else
- dr_wake_up_enable(udc_controller, true);
-#endif
+ udc_controller->stopped = 1;
-/*
- * As mx25/mx35 does not implement clk_gate, should not let phy to low
- * power mode due to IC bug
- */
#if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
{
- dr_phy_low_power_mode(udc_controller, true);
+ u32 portsc;
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
}
#endif
- udc_controller->stopped = 1;
-
- /* let the gadget register function open the clk */
- dr_clk_gate(false);
-
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
+#endif
create_proc_file();
return 0;
@@ -3006,6 +2917,9 @@ err1a:
*/
static int __exit fsl_udc_remove(struct platform_device *pdev)
{
+#ifndef CONFIG_USB_OTG
+ struct resource *res;
+#endif
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
DECLARE_COMPLETION(done);
@@ -3014,8 +2928,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
return -ENODEV;
udc_controller->done = &done;
/* open USB PHY clock */
- if (udc_controller->stopped)
- dr_clk_gate(true);
+ dr_phy_low_power_mode(udc_controller, false);
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();
@@ -3038,11 +2951,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
iounmap((u8 __iomem *)dr_regs);
#ifndef CONFIG_USB_OTG
-{
- struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
-}
#endif
device_unregister(&udc_controller->gadget.dev);
@@ -3056,8 +2966,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
if (pdata->platform_uninit)
pdata->platform_uninit(pdata);
- if (udc_controller->stopped)
- dr_clk_gate(false);
return 0;
}
@@ -3065,19 +2973,10 @@ static int udc_suspend(struct fsl_udc *udc)
{
u32 mode, usbcmd;
- /*
- * When it is the PM suspend routine and the device has no
- * abilities to wakeup system, it should not set wakeup enable.
- * Otherwise, the system will wakeup even the user only wants to
- * charge using usb
- */
- if (udc_controller->gadget.dev.parent->power.status
- == DPM_SUSPENDING) {
- if (!device_may_wakeup(udc_controller->gadget.dev.parent))
- dr_wake_up_enable(udc, false);
- else
- dr_wake_up_enable(udc, true);
- }
+ /* open clock for register access */
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
+
mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
usbcmd = fsl_readl(&dr_regs->usbcmd);
@@ -3088,8 +2987,9 @@ static int udc_suspend(struct fsl_udc *udc)
* PM suspend. Remember this fact, so that we will leave the
* controller stopped at PM resume time.
*/
- if (udc->suspended) {
+ if (udc->stopped) {
pr_debug("gadget already stopped, leaving early\n");
+ udc->already_stopped = 1;
goto out;
}
@@ -3098,30 +2998,22 @@ static int udc_suspend(struct fsl_udc *udc)
goto out;
}
- /* For some buggy hardware designs, see comment of this function for detail */
- udc_wait_b_session_low();
-
udc->stopped = 1;
-
- /* stop the controller */
- usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
- fsl_writel(usbcmd, &dr_regs->usbcmd);
-
/* if the suspend is not for switch to host in otg mode */
if ((!(udc->gadget.is_otg)) ||
(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
- if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
- dr_wake_up_enable(udc, true);
- }
+ dr_wake_up_enable(udc, true);
+ dr_phy_low_power_mode(udc, true);
}
- dr_phy_low_power_mode(udc, true);
+ /* stop the controller */
+ usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
+ fsl_writel(usbcmd, &dr_regs->usbcmd);
+
printk(KERN_INFO "USB Gadget suspended\n");
out:
- udc->suspended++;
- if (udc->suspended > 2)
- printk("ERROR: suspended times > 2\n");
-
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
return 0;
}
@@ -3131,24 +3023,13 @@ out:
-----------------------------------------------------------------*/
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
{
- int ret;
-#ifdef CONFIG_USB_OTG
- if (udc_controller->transceiver->gadget == NULL)
- return 0;
-#endif
- if (udc_controller->stopped)
- dr_clk_gate(true);
if (((!(udc_controller->gadget.is_otg)) ||
(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) &&
(udc_controller->usb_state > USB_STATE_POWERED) &&
- (udc_controller->usb_state < USB_STATE_SUSPENDED)) {
- return -EBUSY;/* keep the clk on */
- }
- else
- ret = udc_suspend(udc_controller);
- dr_clk_gate(false);
+ (udc_controller->usb_state < USB_STATE_SUSPENDED))
+ return -EBUSY;
- return ret;
+ return udc_suspend(udc_controller);
}
/*-----------------------------------------------------------------
@@ -3157,54 +3038,30 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
*-----------------------------------------------------------------*/
static int fsl_udc_resume(struct platform_device *pdev)
{
- pr_debug("%s(): stopped %d suspended %d\n", __func__,
- udc_controller->stopped, udc_controller->suspended);
- printk("udc resume\n");
-#ifdef CONFIG_USB_OTG
- if (udc_controller->transceiver->gadget == NULL)
- return 0;
-#endif
- if (udc_controller->stopped)
- dr_clk_gate(true);
+ 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 it is PM resume routine, the udc is at low power mode,
- * and the udc has no abilities to wakeup system, it should
- * set the abilities to wakeup itself. Otherwise, the usb
- * subsystem will not leave from low power mode.
- */
- if (!device_may_wakeup(udc_controller->gadget.dev.parent) &&
- udc_controller->gadget.dev.parent->power.status
- == DPM_RESUMING){
- dr_wake_up_enable(udc_controller, true);
- }
-
- if (--udc_controller->suspended) {
- printk("gadget was already stopped, leaving early\n");
- goto out;
+ if (udc_controller->already_stopped) {
+ udc_controller->already_stopped = 0;
+ pr_debug("gadget was already stopped, leaving early\n");
+ return 0;
}
+
/* Enable DR irq reg and set controller Run */
if (udc_controller->stopped) {
- /* if in host mode, we need to do nothing */
- if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) {
- goto out;
- }
dr_wake_up_enable(udc_controller, false);
dr_phy_low_power_mode(udc_controller, false);
- mdelay(10);
+ mdelay(1);
+
dr_controller_setup(udc_controller);
dr_controller_run(udc_controller);
}
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
-out:
- /* if udc is resume by otg id change and no device
- * connecting to the otg, otg will enter low power mode*/
- if (udc_controller->stopped)
- dr_clk_gate(false);
printk(KERN_INFO "USB Gadget resumed\n");
return 0;
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index 8d344acb8fef..4574954bf4f4 100644
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -266,7 +266,6 @@ struct usb_sys_interface {
#define PORTSCX_SPEED_BIT_POS (26)
/* OTGSC Register Bit Masks */
-#define OTGSC_ID_CHANGE_IRQ_STS (1 << 16)
#define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27)
#define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19)
#define OTGSC_B_SESSION_VALID (1 << 11)
@@ -594,15 +593,9 @@ struct fsl_udc {
struct otg_transceiver *transceiver;
unsigned softconnect:1;
unsigned vbus_active:1;
- unsigned remote_wakeup:1;
- /* we must distinguish the stopped and suspended state,
- * stopped means the udc enter lowpower mode, suspended
- * means the udc is suspended by system pm or by otg
- * switching to host mode.if the udc in suspended state
- * it also in the stopped state, while if the udc in
- * stopped state,it may not be in the suspended state*/
unsigned stopped:1;
- int suspended;
+ unsigned remote_wakeup:1;
+ unsigned already_stopped:1;
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
struct fsl_req *status_req; /* ep0 status request */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 2e79b8c389a4..59e85234fa0a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -236,7 +236,6 @@ static int config_buf(struct usb_configuration *config,
int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
struct usb_function *f;
int status;
- int interfaceCount = 0;
/* write the config descriptor */
c = buf;
@@ -267,16 +266,8 @@ static int config_buf(struct usb_configuration *config,
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
- if (f->hidden || !descriptors || descriptors[0] == NULL) {
- for (; f != config->interface[interfaceCount];) {
- interfaceCount++;
- c->bNumInterfaces--;
- }
+ if (!descriptors)
continue;
- }
- for (; f != config->interface[interfaceCount];)
- interfaceCount++;
-
status = usb_descriptor_fillbuf(next, len,
(const struct usb_descriptor_header **) descriptors);
if (status < 0)
@@ -765,11 +756,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
- if (cdev->config) {
+ if (cdev->config)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
- value = min(w_length, (u16) 1);
- } else
+ else
*(u8 *)req->buf = 0;
+ value = min(w_length, (u16) 1);
break;
/* function drivers must handle get/set altsetting; if there's
@@ -819,9 +810,6 @@ unknown:
*/
if ((ctrl->bRequestType & USB_RECIP_MASK)
== USB_RECIP_INTERFACE) {
- if (cdev->config == NULL)
- return value;
-
f = cdev->config->interface[intf];
if (f && f->setup)
value = f->setup(f, ctrl);
@@ -836,25 +824,6 @@ unknown:
value = c->setup(c, ctrl);
}
- /* If the vendor request is not processed (value < 0),
- * call all device registered configure setup callbacks
- * to process it.
- * This is used to handle the following cases:
- * - vendor request is for the device and arrives before
- * setconfiguration.
- * - Some devices are required to handle vendor request before
- * setconfiguration such as MTP, USBNET.
- */
-
- if (value < 0) {
- struct usb_configuration *cfg;
-
- list_for_each_entry(cfg, &cdev->configs, list) {
- if (cfg && cfg->setup)
- value = cfg->setup(cfg, ctrl);
- }
- }
-
goto done;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7dd1a8bbe382..7953948bfe4a 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -761,12 +761,3 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
kfree(acm);
return status;
}
-
-int __init acm_function_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c)
-{
- int ret = acm_bind_config(c, 0);
- if (ret == 0)
- gserial_setup(c->cdev->gadget, 1);
- return ret;
-}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 8b0a13202573..66105ce49672 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -728,7 +728,6 @@ struct fsg_dev {
#include "fsl_updater.h"
#endif
-static int do_set_interface(struct fsg_dev *fsg, int altsetting);
typedef void (*fsg_routine_t)(struct fsg_dev *);
static int exception_in_progress(struct fsg_dev *fsg)
@@ -1109,14 +1108,6 @@ static void fsg_disconnect(struct usb_gadget *gadget)
struct fsg_dev *fsg = get_gadget_data(gadget);
DBG(fsg, "disconnect or port reset\n");
- /*
- * The disconnect exception will call do_set_config, and therefore will
- * visit controller registers. However it is a delayed event, and will be
- * handled at another process, so the controller maybe have already close the
- * usb clock.*/
- if (fsg->new_config)
- do_set_interface(fsg, -1);/* disable the interface */
-
raise_exception(fsg, FSG_STATE_DISCONNECT);
}
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index 5cfcf169e7c7..21133fb8e47a 100644
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -23,28 +23,9 @@
#include <linux/fsl_devices.h>
#include <linux/usb/otg.h>
-#include "../core/usb.h"
#include "ehci-fsl.h"
#include <mach/fsl_usb.h>
-extern int usb_host_wakeup_irq(struct device *wkup_dev);
-extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
-static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool enable)
-{
- if (enable){
- if (pdata->phy_lowpower_suspend)
- pdata->phy_lowpower_suspend(true);
- } else {
- if (pdata->phy_lowpower_suspend)
- pdata->phy_lowpower_suspend(false);
- }
-}
-
-static void fsl_usb_clk_gate(struct fsl_usb2_platform_data *pdata, bool enable)
-{
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(enable);
-}
#undef EHCI_PROC_PTC
#ifdef EHCI_PROC_PTC /* /proc PORTSC:PTC support */
/*
@@ -109,39 +90,8 @@ static int ehci_testmode_init(struct ehci_hcd *ehci)
#endif /* /proc PORTSC:PTC support */
-/*
- * This irq is used to open the hw access and let usb_hcd_irq process the usb event
- * ehci_fsl_pre_irq will be called before usb_hcd_irq
- */
-static irqreturn_t ehci_fsl_pre_irq(int irq, void *dev)
-{
- struct platform_device *pdev = (struct platform_device *)dev;
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct fsl_usb2_platform_data *pdata;
-
- pdata = hcd->self.controller->platform_data;
-
- /* if it is an otg module and in b device mode, we need to do noting here */
- if (ehci->transceiver && !ehci->transceiver->default_a)
- return IRQ_NONE;
-
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- /* Need to open clk for accessing the register */
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- /* if receive a remote wakeup interrrupt after suspend */
- if (usb_host_wakeup_irq(hcd->self.controller)) {
- printk("host wakeup event happens\n");
- /* disable remote wake up irq */
- usb_host_set_wakeup(hcd->self.controller, false);
- fsl_usb_lowpower_mode(pdata, false);
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- }else {
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
- }
- }
- return IRQ_NONE;
-}
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
/**
* usb_hcd_fsl_probe - initialize FSL-based HCDs
@@ -232,18 +182,9 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
fsl_platform_set_host_mode(hcd);
hcd->power_budget = pdata->power_budget;
- /*
- * The ehci_fsl_pre_irq must be registered before usb_hcd_irq, in that case
- * it can be called before usb_hcd_irq when irq occurs
- */
- retval = request_irq(irq, ehci_fsl_pre_irq, IRQF_SHARED,
- "fsl ehci pre interrupt", (void *)pdev);
- if (retval != 0)
- goto err4;
-
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
- goto err5;
+ goto err4;
fsl_platform_set_vbus_power(pdata, 1);
@@ -258,7 +199,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (!ehci->transceiver) {
printk(KERN_ERR "can't find transceiver\n");
retval = -ENODEV;
- goto err5;
+ goto err4;
}
retval = otg_set_host(ehci->transceiver, &ehci_to_hcd(ehci)->self);
@@ -275,8 +216,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
fsl_platform_set_ahb_burst(hcd);
ehci_testmode_init(hcd_to_ehci(hcd));
return retval;
-err5:
- free_irq(irq, (void *)pdev);
+
err4:
iounmap(hcd->regs);
err3:
@@ -291,6 +231,9 @@ err1:
return retval;
}
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
/**
* usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
* @dev: USB Host Controller being removed
@@ -381,59 +324,6 @@ static int ehci_fsl_reinit(struct ehci_hcd *ehci)
return 0;
}
-static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
-{
- int ret = 0;
- struct fsl_usb2_platform_data *pdata;
- pdata = hcd->self.controller->platform_data;
- pr_debug("%s, %s\n", __func__, pdata->name);
-
- /* the host is already at low power mode */
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- return 0;
- }
-
- pr_debug("%s, it is the host mode, %s\n", __func__, pdata->name);
-
- ehci_bus_suspend(hcd);
-
- if (pdata->platform_suspend)
- pdata->platform_suspend(pdata);
-
- usb_host_set_wakeup(hcd->self.controller, true);
- fsl_usb_lowpower_mode(pdata, true);
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- return ret;
-}
-
-static int ehci_fsl_bus_resume(struct usb_hcd *hcd)
-{
- int ret = 0;
- struct fsl_usb2_platform_data *pdata;
-
- pdata = hcd->self.controller->platform_data;
- pr_debug("%s, %s\n", __func__, pdata->name);
-
- /* if it is a remote wakeup, it will open clock and clear PHCD automatically */
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- usb_host_set_wakeup(hcd->self.controller, false);
- fsl_usb_lowpower_mode(pdata, false);
- }
-
- if (pdata->platform_resume)
- pdata->platform_resume(pdata);
- ret = ehci_bus_resume(hcd);
- if (ret)
- return ret;
-
- return ret;
-}
-
-
/* called during probe() after chip reset completes */
static int ehci_fsl_setup(struct usb_hcd *hcd)
{
@@ -506,8 +396,8 @@ static const struct hc_driver ehci_fsl_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
- .bus_suspend = ehci_fsl_bus_suspend,
- .bus_resume = ehci_fsl_bus_resume,
+ .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,
@@ -548,36 +438,13 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct usb_device *roothub = hcd->self.root_hub;
- u32 port_status;
+ u32 tmp, port_status;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- /* Only handles OTG mode switch event, system suspend event will be done in bus suspend */
- if (pdev->dev.power.status == DPM_SUSPENDING){
- pr_debug("%s, system pm event \n", __func__);
- if (!device_may_wakeup(&(pdev->dev))){
- /* Need open clock for register access */
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- usb_host_set_wakeup(hcd->self.controller, false);
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
- }
- return 0;
- }
- /* only the otg host can go here */
- /* wait for all usb device on the hcd dettached */
- while(roothub->children[0] != NULL)
- msleep(1);
- if ((pdata->operating_mode != FSL_USB2_MPH_HOST) && (!(hcd->state & HC_STATE_SUSPENDED)))
- {
- usb_lock_device(roothub);
- usb_external_suspend_device(roothub, PMSG_USER_SUSPEND);
- usb_unlock_device(roothub);
- }
-
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ if (device_may_wakeup(&(pdev->dev))) {
+ /* Need open clock for register access */
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(true);
}
#ifdef DEBUG
@@ -590,9 +457,27 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
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) {
+ pr_debug("%s: already suspended, leaving early\n", __func__);
+ pdata->already_suspended = 1;
+ goto err1;
+ }
+
+ pr_debug("%s: suspending...\n", __func__);
+
printk(KERN_INFO "USB Host suspended\n");
port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ pdev->dev.power.power_state = PMSG_SUSPEND;
+
+ /* ignore non-host interrupts */
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
/* save EHCI registers */
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
pdata->pm_command &= ~CMD_RUN;
@@ -611,11 +496,25 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
/* clear PHCD bit */
pdata->pm_portsc &= ~PORT_PHCD;
- if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- //fsl_usb_lowpower_mode(pdata ,true);
- //usb_host_set_wakeup(hcd->self.controller, true);
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ pdata->suspended = 1;
+
+ if (!device_may_wakeup(&(pdev->dev))) {
+ /* 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]);
+ goto err1;
+ }
+
+ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+
+ if (pdata->platform_suspend)
+ pdata->platform_suspend(pdata);
+err1:
+ if (device_may_wakeup(&(pdev->dev))) {
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(false);
}
return 0;
}
@@ -624,35 +523,47 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct usb_device *roothub = hcd->self.root_hub;
u32 tmp;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- /* Only handles OTG mode switch event */
- if (pdev->dev.power.status == DPM_RESUMING){
- pr_debug("%s, system pm event \n", __func__);
- if (hcd->self.is_b_host) {
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- }
- usb_host_set_wakeup(hcd->self.controller, true);
-
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
- }
- }
+
+ pr_debug("%s('%s'): suspend=%d already_suspended=%d\n", __func__,
+ pdata->name, pdata->suspended, pdata->already_suspended);
+
+ /*
+ * If the controller was already suspended at suspend time,
+ * then don't resume it now.
+ */
+ if (pdata->already_suspended) {
+ pr_debug("already suspended, leaving early\n");
+ pdata->already_suspended = 0;
return 0;
}
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
- //usb_host_set_wakeup(hcd->self.controller, false);
- //fsl_usb_lowpower_mode(pdata, false);
+
+ if (!pdata->suspended) {
+ pr_debug("not suspended, leaving early\n");
+ return 0;
}
- printk("USB Host resume ... %s\n", pdata->name);
+ /* If hcd is resumed by non-usb wakeup events,
+ * then usb clocks are still not open when come here */
+ if (device_may_wakeup(&(pdev->dev))) {
+ /* Need open clock for register access */
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(true);
+ }
+
+ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+
+ pdata->suspended = 0;
+
+ pr_debug("%s resuming...\n", __func__);
+
/* set host mode */
fsl_platform_set_host_mode(hcd);
+ if (pdata->platform_resume)
+ pdata->platform_resume(pdata);
+
/* restore EHCI registers */
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
@@ -664,21 +575,32 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
ehci_writel(ehci, pdata->pm_configured_flag,
&ehci->regs->configured_flag);
+ /* set bit should be done by wakeup irq routine if may wakeup */
+ if (!device_may_wakeup(&(pdev->dev)))
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ else
+ while (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ msleep(1);
+
+ pdev->dev.power.power_state = PMSG_ON;
tmp = ehci_readl(ehci, &ehci->regs->command);
tmp |= CMD_RUN;
ehci_writel(ehci, tmp, &ehci->regs->command);
- if ((hcd->state & HC_STATE_SUSPENDED)){
- usb_lock_device(roothub);
- usb_external_resume_device(roothub, PMSG_USER_RESUME);
- usb_unlock_device(roothub);
+ usb_hcd_resume_root_hub(hcd);
+
+ printk(KERN_INFO "USB Host resumed\n");
+
+ if (device_may_wakeup(&(pdev->dev))) {
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(false);
}
- printk(KERN_INFO "USB Host resume ok\n");
return 0;
}
-#endif
+#endif /* CONFIG_USB_OTG */
+
MODULE_ALIAS("platform:fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1a9266e7e798..f0d6627fb981 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
@@ -660,6 +661,7 @@ static int ehci_run (struct usb_hcd *hcd)
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
msleep(5);
up_write(&ehci_cf_port_reset_rwsem);
+ ehci->last_periodic_enable = ktime_get_real();
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
@@ -767,9 +769,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* start 20 msec resume signaling from this port,
* and make khubd collect PORT_STAT_C_SUSPEND to
- * stop that signaling.
+ * stop that signaling. Use 5 ms extra for safety,
+ * like usb_port_resume() does.
*/
- ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
}
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 44ff32306362..2eac68f54ccd 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -112,7 +112,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
int port;
int mask;
- printk("%s\n", __func__);
ehci_dbg(ehci, "suspend root hub\n");
if (time_before (jiffies, ehci->next_statechange))
@@ -120,9 +119,26 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
del_timer_sync(&ehci->watchdog);
del_timer_sync(&ehci->iaa_watchdog);
- port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock);
+ /* Once the controller is stopped, port resumes that are already
+ * in progress won't complete. Hence if remote wakeup is enabled
+ * for the root hub and any ports are in the middle of a resume or
+ * remote wakeup, we must fail the suspend.
+ */
+ if (hcd->self.root_hub->do_remote_wakeup) {
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ if (ehci->reset_done[port] != 0) {
+ spin_unlock_irq(&ehci->lock);
+ ehci_dbg(ehci, "suspend failed because "
+ "port %d is resuming\n",
+ port + 1);
+ return -EBUSY;
+ }
+ }
+ }
+
/* stop schedules, clean any completed work */
if (HC_IS_RUNNING(hcd->state)) {
ehci_quiesce (ehci);
@@ -138,6 +154,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
*/
ehci->bus_suspended = 0;
ehci->owned_ports = 0;
+ port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index c2f1b7df918c..c757a706843c 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -72,6 +72,12 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
int retval;
switch (pdev->vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ if (pdev->device == 0x27cc) {
+ ehci->broken_periodic = 1;
+ ehci_info(ehci, "using broken periodic workaround\n");
+ }
+ break;
case PCI_VENDOR_ID_TOSHIBA_2:
/* celleb's companion chip */
if (pdev->device == 0x01b5) {
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 7673554fa64d..1ae9faf1f8c2 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -475,8 +475,20 @@ halt:
* we must clear the TT buffer (11.17.5).
*/
if (unlikely(last_status != -EINPROGRESS &&
- last_status != -EREMOTEIO))
- ehci_clear_tt_buffer(ehci, qh, urb, token);
+ last_status != -EREMOTEIO)) {
+ /* The TT's in some hubs malfunction when they
+ * receive this request following a STALL (they
+ * stop sending isochronous packets). Since a
+ * STALL can't leave the TT buffer in a busy
+ * state (if you believe Figures 11-48 - 11-51
+ * in the USB 2.0 spec), we won't clear the TT
+ * buffer in this case. Strictly speaking this
+ * is a violation of the spec.
+ */
+ if (last_status != -EPIPE)
+ ehci_clear_tt_buffer(ehci, qh, urb,
+ token);
+ }
}
/* if we're removing something not at the queue head,
@@ -790,9 +802,10 @@ qh_make (
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
- dbg ("intr period %d uframes, NYET!",
- urb->interval);
- goto done;
+ urb->interval = 1;
+ } else if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period << 3;
}
} else {
int think_time;
@@ -815,6 +828,10 @@ qh_make (
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
+ if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period;
+ }
}
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index edd61ee90323..c340f1f4b881 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -456,6 +456,8 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* make sure ehci_work scans these */
ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
% (ehci->periodic_size << 3);
+ if (unlikely(ehci->broken_periodic))
+ ehci->last_periodic_enable = ktime_get_real();
return 0;
}
@@ -467,6 +469,16 @@ static int disable_periodic (struct ehci_hcd *ehci)
if (--ehci->periodic_sched)
return 0;
+ if (unlikely(ehci->broken_periodic)) {
+ /* delay experimentally determined */
+ ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
+ ktime_t now = ktime_get_real();
+ s64 delay = ktime_us_delta(safe, now);
+
+ if (unlikely(delay > 0))
+ udelay(delay);
+ }
+
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 4b81f5e77c8b..7a412652cb5d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
unsigned stamp;
unsigned random_frame;
unsigned long next_statechange;
+ ktime_t last_periodic_enable;
u32 command;
/* SILICON QUIRKS */
@@ -126,6 +127,7 @@ struct ehci_hcd { /* one per controller */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned has_amcc_usb23:1;
+ unsigned broken_periodic:1;
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 58151687d351..1ed2a16a61de 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -88,6 +88,7 @@ static int ohci_restart (struct ohci_hcd *ohci);
#ifdef CONFIG_PCI
static void quirk_amd_pll(int state);
static void amd_iso_dev_put(void);
+static void sb800_prefetch(struct ohci_hcd *ohci, int on);
#else
static inline void quirk_amd_pll(int state)
{
@@ -97,6 +98,10 @@ static inline void amd_iso_dev_put(void)
{
return;
}
+static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
+{
+ return;
+}
#endif
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index d2ba04dd785e..b8a1148f248e 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -177,6 +177,13 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
return 0;
pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+
+ /* SB800 needs pre-fetch fix */
+ if ((rev >= 0x40) && (rev <= 0x4f)) {
+ ohci->flags |= OHCI_QUIRK_AMD_PREFETCH;
+ ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
+ }
+
if ((rev > 0x3b) || (rev < 0x30)) {
pci_dev_put(amd_smbus_dev);
amd_smbus_dev = NULL;
@@ -262,6 +269,19 @@ static void amd_iso_dev_put(void)
}
+static void sb800_prefetch(struct ohci_hcd *ohci, int on)
+{
+ struct pci_dev *pdev;
+ u16 misc;
+
+ pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller);
+ pci_read_config_word(pdev, 0x50, &misc);
+ if (on == 0)
+ pci_write_config_word(pdev, 0x50, misc & 0xfcff);
+ else
+ pci_write_config_word(pdev, 0x50, misc | 0x0300);
+}
+
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index c2d80f80448b..2c7409b09e8b 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -49,9 +49,12 @@ __acquires(ohci->lock)
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
- && quirk_amdiso(ohci))
- quirk_amd_pll(1);
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+ if (quirk_amdiso(ohci))
+ quirk_amd_pll(1);
+ if (quirk_amdprefetch(ohci))
+ sb800_prefetch(ohci, 0);
+ }
break;
case PIPE_INTERRUPT:
ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
@@ -680,9 +683,12 @@ static void td_submit_urb (
data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt);
}
- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
- && quirk_amdiso(ohci))
- quirk_amd_pll(0);
+ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
+ if (quirk_amdiso(ohci))
+ quirk_amd_pll(0);
+ if (quirk_amdprefetch(ohci))
+ sb800_prefetch(ohci, 1);
+ }
periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
break;
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 222011f6172c..5bf15fed0d9f 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -402,6 +402,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
+#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
@@ -433,6 +434,10 @@ static inline int quirk_amdiso(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_AMD_ISO;
}
+static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_AMD_PREFETCH;
+}
#else
static inline int quirk_nec(struct ohci_hcd *ohci)
{
@@ -446,6 +451,10 @@ static inline int quirk_amdiso(struct ohci_hcd *ohci)
{
return 0;
}
+static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
+{
+ return 0;
+}
#endif
/* convert between an hcd pointer and the corresponding ohci_hcd */
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index a949259f18b9..5b22a4d1c9e4 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -719,8 +719,12 @@ retry:
/* port status seems weird until after reset, so
* force the reset and make khubd clean up later.
*/
- sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
- | (1 << USB_PORT_FEAT_CONNECTION);
+ if (sl811->stat_insrmv & 1)
+ sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;
+ else
+ sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION);
+
+ sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION;
} else if (irqstat & SL11H_INTMASK_RD) {
if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 274751b4409c..eb37d86bafef 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -749,7 +749,20 @@ static int uhci_rh_suspend(struct usb_hcd *hcd)
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
rc = -ESHUTDOWN;
- else if (!uhci->dead)
+ else if (uhci->dead)
+ ; /* Dead controllers tell no tales */
+
+ /* Once the controller is stopped, port resumes that are already
+ * in progress won't complete. Hence if remote wakeup is enabled
+ * for the root hub and any ports are in the middle of a resume or
+ * remote wakeup, we must fail the suspend.
+ */
+ else if (hcd->self.root_hub->do_remote_wakeup &&
+ uhci->resuming_ports) {
+ dev_dbg(uhci_dev(uhci), "suspend failed because a port "
+ "is resuming\n");
+ rc = -EBUSY;
+ } else
suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
return rc;
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 885b585360b9..8270055848ca 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -167,7 +167,7 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
/* Port received a wakeup request */
set_bit(port, &uhci->resuming_ports);
uhci->ports_timeout = jiffies +
- msecs_to_jiffies(20);
+ msecs_to_jiffies(25);
/* Make sure we see the port again
* after the resuming period is over. */
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 705e34324156..33128d52f212 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -413,7 +413,8 @@ void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
int i;
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
- dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx);
+ dma_addr_t dma = ctx->dma +
+ ((unsigned long)slot_ctx - (unsigned long)ctx->bytes);
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
xhci_dbg(xhci, "Slot Context:\n");
@@ -459,7 +460,7 @@ void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
for (i = 0; i < last_ep_ctx; ++i) {
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
dma_addr_t dma = ctx->dma +
- ((unsigned long)ep_ctx - (unsigned long)ctx);
+ ((unsigned long)ep_ctx - (unsigned long)ctx->bytes);
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 816c39caca1c..e478a63488fb 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -22,12 +22,18 @@
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include "xhci.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
+/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
+static int link_quirk;
+module_param(link_quirk, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
+
/* TODO: copied from ehci-hcd.c - can this be refactored? */
/*
* handshake - spin reading hc until handshake completes or fails
@@ -214,6 +220,12 @@ int xhci_init(struct usb_hcd *hcd)
xhci_dbg(xhci, "xhci_init\n");
spin_lock_init(&xhci->lock);
+ if (link_quirk) {
+ xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
+ xhci->quirks |= XHCI_LINK_TRB_QUIRK;
+ } else {
+ xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
+ }
retval = xhci_mem_init(xhci, GFP_KERNEL);
xhci_dbg(xhci, "Finished xhci_init\n");
@@ -555,13 +567,22 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
return 1 << (xhci_get_endpoint_index(desc) + 1);
}
+/* Find the flag for this endpoint (for use in the control context). Use the
+ * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is
+ * bit 1, etc.
+ */
+unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index)
+{
+ return 1 << (ep_index + 1);
+}
+
/* Compute the last valid endpoint context index. Basically, this is the
* endpoint index plus one. For slot contexts with more than valid endpoint,
* we find the most significant bit set in the added contexts flags.
* e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000
* fls(0b1000) = 4, but the endpoint context index is 3, so subtract one.
*/
-static inline unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
+unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
{
return fls(added_ctxs) - 1;
}
@@ -589,6 +610,70 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
return 1;
}
+static int xhci_configure_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev, struct xhci_virt_device *virt_dev,
+ bool ctx_change);
+
+/*
+ * Full speed devices may have a max packet size greater than 8 bytes, but the
+ * USB core doesn't know that until it reads the first 8 bytes of the
+ * descriptor. If the usb_device's max packet size changes after that point,
+ * we need to issue an evaluate context command and wait on it.
+ */
+static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
+ unsigned int ep_index, struct urb *urb)
+{
+ struct xhci_container_ctx *in_ctx;
+ struct xhci_container_ctx *out_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_ep_ctx *ep_ctx;
+ int max_packet_size;
+ int hw_max_packet_size;
+ int ret = 0;
+
+ 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;
+ 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",
+ max_packet_size);
+ xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
+ hw_max_packet_size);
+ xhci_dbg(xhci, "Issuing evaluate context command.\n");
+
+ /* Set up the modified control endpoint 0 */
+ xhci_endpoint_copy(xhci, xhci->devs[slot_id], 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);
+
+ /* 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->drop_flags = 0;
+
+ xhci_dbg(xhci, "Slot %d input context\n", slot_id);
+ xhci_dbg_ctx(xhci, in_ctx, ep_index);
+ xhci_dbg(xhci, "Slot %d output context\n", slot_id);
+ xhci_dbg_ctx(xhci, out_ctx, ep_index);
+
+ ret = xhci_configure_endpoint(xhci, urb->dev,
+ xhci->devs[slot_id], true);
+
+ /* Clean up the input context for later use by bandwidth
+ * functions.
+ */
+ ctrl_ctx->add_flags = SLOT_FLAG;
+ }
+ return ret;
+}
+
/*
* non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it
@@ -600,13 +685,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
int ret = 0;
unsigned int slot_id, ep_index;
+
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
- spin_lock_irqsave(&xhci->lock, flags);
if (!xhci->devs || !xhci->devs[slot_id]) {
if (!in_interrupt())
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
@@ -619,19 +704,38 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = -ESHUTDOWN;
goto exit;
}
- if (usb_endpoint_xfer_control(&urb->ep->desc))
+ if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ /* Check to see if the max packet size for the default control
+ * endpoint changed during FS device enumeration
+ */
+ if (urb->dev->speed == USB_SPEED_FULL) {
+ ret = xhci_check_maxpacket(xhci, slot_id,
+ ep_index, urb);
+ if (ret < 0)
+ return ret;
+ }
+
/* We have a spinlock and interrupts disabled, so we must pass
* atomic context to this function, which may allocate memory.
*/
+ spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
- else if (usb_endpoint_xfer_bulk(&urb->ep->desc))
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
+ spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
- else
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ } else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
+ spin_lock_irqsave(&xhci->lock, flags);
+ ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
+ slot_id, ep_index);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ } else {
ret = -EINVAL;
+ }
exit:
- spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
}
@@ -930,6 +1034,122 @@ 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, struct xhci_virt_device *virt_dev)
+{
+ int ret;
+
+ switch (virt_dev->cmd_status) {
+ case COMP_ENOMEM:
+ dev_warn(&udev->dev, "Not enough host controller resources "
+ "for new device state.\n");
+ ret = -ENOMEM;
+ /* FIXME: can we allocate more resources for the HC? */
+ break;
+ case COMP_BW_ERR:
+ dev_warn(&udev->dev, "Not enough bandwidth "
+ "for new device state.\n");
+ ret = -ENOSPC;
+ /* FIXME: can we go back to the old state? */
+ break;
+ case COMP_TRB_ERR:
+ /* the HCD set up something wrong */
+ dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, "
+ "add flag = 1, "
+ "and endpoint is not disabled.\n");
+ ret = -EINVAL;
+ break;
+ case COMP_SUCCESS:
+ dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
+ ret = 0;
+ break;
+ default:
+ xhci_err(xhci, "ERROR: unexpected command completion "
+ "code 0x%x.\n", virt_dev->cmd_status);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
+ struct usb_device *udev, struct xhci_virt_device *virt_dev)
+{
+ int ret;
+
+ switch (virt_dev->cmd_status) {
+ case COMP_EINVAL:
+ dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate "
+ "context command.\n");
+ ret = -EINVAL;
+ break;
+ case COMP_EBADSLT:
+ dev_warn(&udev->dev, "WARN: slot not enabled for"
+ "evaluate context command.\n");
+ case COMP_CTX_STATE:
+ dev_warn(&udev->dev, "WARN: invalid context state for "
+ "evaluate context command.\n");
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
+ ret = -EINVAL;
+ break;
+ case COMP_SUCCESS:
+ dev_dbg(&udev->dev, "Successful evaluate context command\n");
+ ret = 0;
+ break;
+ default:
+ xhci_err(xhci, "ERROR: unexpected command completion "
+ "code 0x%x.\n", virt_dev->cmd_status);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/* Issue a configure endpoint command or evaluate context command
+ * and wait for it to finish.
+ */
+static int xhci_configure_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev, struct xhci_virt_device *virt_dev,
+ bool ctx_change)
+{
+ int ret;
+ int timeleft;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ if (!ctx_change)
+ ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
+ udev->slot_id);
+ else
+ ret = xhci_queue_evaluate_context(xhci, virt_dev->in_ctx->dma,
+ udev->slot_id);
+ if (ret < 0) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
+ return -ENOMEM;
+ }
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ /* Wait for the configure endpoint command to complete */
+ timeleft = wait_for_completion_interruptible_timeout(
+ &virt_dev->cmd_completion,
+ USB_CTRL_SET_TIMEOUT);
+ if (timeleft <= 0) {
+ xhci_warn(xhci, "%s while waiting for %s command\n",
+ timeleft == 0 ? "Timeout" : "Signal",
+ ctx_change == 0 ?
+ "configure endpoint" :
+ "evaluate context");
+ /* FIXME cancel the configure endpoint command */
+ return -ETIME;
+ }
+
+ if (!ctx_change)
+ return xhci_configure_endpoint_result(xhci, udev, virt_dev);
+ return xhci_evaluate_context_result(xhci, udev, virt_dev);
+}
+
/* Called after one or more calls to xhci_add_endpoint() or
* xhci_drop_endpoint(). If this call fails, the USB core is expected
* to call xhci_reset_bandwidth().
@@ -944,8 +1164,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
{
int i;
int ret = 0;
- int timeleft;
- unsigned long flags;
struct xhci_hcd *xhci;
struct xhci_virt_device *virt_dev;
struct xhci_input_control_ctx *ctrl_ctx;
@@ -975,56 +1193,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
- spin_lock_irqsave(&xhci->lock, flags);
- ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
- udev->slot_id);
- if (ret < 0) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
- return -ENOMEM;
- }
- xhci_ring_cmd_db(xhci);
- spin_unlock_irqrestore(&xhci->lock, flags);
-
- /* Wait for the configure endpoint command to complete */
- timeleft = wait_for_completion_interruptible_timeout(
- &virt_dev->cmd_completion,
- USB_CTRL_SET_TIMEOUT);
- if (timeleft <= 0) {
- xhci_warn(xhci, "%s while waiting for configure endpoint command\n",
- timeleft == 0 ? "Timeout" : "Signal");
- /* FIXME cancel the configure endpoint command */
- return -ETIME;
- }
-
- switch (virt_dev->cmd_status) {
- case COMP_ENOMEM:
- dev_warn(&udev->dev, "Not enough host controller resources "
- "for new device state.\n");
- ret = -ENOMEM;
- /* FIXME: can we allocate more resources for the HC? */
- break;
- case COMP_BW_ERR:
- dev_warn(&udev->dev, "Not enough bandwidth "
- "for new device state.\n");
- ret = -ENOSPC;
- /* FIXME: can we go back to the old state? */
- break;
- case COMP_TRB_ERR:
- /* the HCD set up something wrong */
- dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, "
- "and endpoint is not disabled.\n");
- ret = -EINVAL;
- break;
- case COMP_SUCCESS:
- dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
- break;
- default:
- xhci_err(xhci, "ERROR: unexpected command completion "
- "code 0x%x.\n", virt_dev->cmd_status);
- ret = -EINVAL;
- break;
- }
+ ret = xhci_configure_endpoint(xhci, udev, virt_dev, false);
if (ret) {
/* Callee should call reset_bandwidth() */
return ret;
@@ -1075,6 +1244,75 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_zero_in_ctx(xhci, virt_dev);
}
+void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
+ unsigned int slot_id, unsigned int ep_index,
+ struct xhci_dequeue_state *deq_state)
+{
+ struct xhci_container_ctx *in_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_ep_ctx *ep_ctx;
+ u32 added_ctxs;
+ dma_addr_t addr;
+
+ xhci_endpoint_copy(xhci, xhci->devs[slot_id], ep_index);
+ in_ctx = xhci->devs[slot_id]->in_ctx;
+ ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
+ addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg,
+ deq_state->new_deq_ptr);
+ if (addr == 0) {
+ xhci_warn(xhci, "WARN Cannot submit config ep after "
+ "reset ep command\n");
+ xhci_warn(xhci, "WARN deq seg = %p, deq ptr = %p\n",
+ deq_state->new_deq_seg,
+ deq_state->new_deq_ptr);
+ return;
+ }
+ ep_ctx->deq = addr | deq_state->new_cycle_state;
+
+ xhci_slot_copy(xhci, xhci->devs[slot_id]);
+
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+ added_ctxs = xhci_get_endpoint_flag_from_index(ep_index);
+ ctrl_ctx->add_flags = added_ctxs | SLOT_FLAG;
+ ctrl_ctx->drop_flags = added_ctxs;
+
+ xhci_dbg(xhci, "Slot ID %d Input Context:\n", slot_id);
+ xhci_dbg_ctx(xhci, in_ctx, ep_index);
+}
+
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ unsigned int ep_index, struct xhci_ring *ep_ring)
+{
+ struct xhci_dequeue_state deq_state;
+
+ xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+ /* We need to move the HW's dequeue pointer past this TD,
+ * or it will attempt to resend it on the next doorbell ring.
+ */
+ xhci_find_new_dequeue_state(xhci, udev->slot_id,
+ ep_index, ep_ring->stopped_td,
+ &deq_state);
+
+ /* HW with the reset endpoint quirk will use the saved dequeue state to
+ * issue a configure endpoint command later.
+ */
+ if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
+ xhci_dbg(xhci, "Queueing new dequeue state\n");
+ xhci_queue_new_dequeue_state(xhci, ep_ring,
+ udev->slot_id,
+ ep_index, &deq_state);
+ } else {
+ /* Better hope no one uses the input context between now and the
+ * reset endpoint completion!
+ */
+ xhci_dbg(xhci, "Setting up input context for "
+ "configure endpoint command\n");
+ xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
+ ep_index, &deq_state);
+ }
+}
+
/* Deal with stalled endpoints. The core should have sent the control message
* to clear the halt condition. However, we need to make the xHCI hardware
* reset its sequence number, since a device will expect a sequence number of
@@ -1089,7 +1327,6 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
unsigned int ep_index;
unsigned long flags;
int ret;
- struct xhci_dequeue_state deq_state;
struct xhci_ring *ep_ring;
xhci = hcd_to_xhci(hcd);
@@ -1106,6 +1343,10 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
ep->desc.bEndpointAddress);
return;
}
+ if (usb_endpoint_xfer_control(&ep->desc)) {
+ xhci_dbg(xhci, "Control endpoint stall already handled.\n");
+ return;
+ }
xhci_dbg(xhci, "Queueing reset endpoint command\n");
spin_lock_irqsave(&xhci->lock, flags);
@@ -1116,16 +1357,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
* command. Better hope that last command worked!
*/
if (!ret) {
- xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
- /* We need to move the HW's dequeue pointer past this TD,
- * or it will attempt to resend it on the next doorbell ring.
- */
- xhci_find_new_dequeue_state(xhci, udev->slot_id,
- ep_index, ep_ring->stopped_td, &deq_state);
- xhci_dbg(xhci, "Queueing new dequeue state\n");
- xhci_queue_new_dequeue_state(xhci, ep_ring,
- udev->slot_id,
- ep_index, &deq_state);
+ xhci_cleanup_stalled_ring(xhci, udev, ep_index, ep_ring);
kfree(ep_ring->stopped_td);
xhci_ring_cmd_db(xhci);
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index e6b9a1c6002d..21146486fdb2 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -94,6 +94,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
val = 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;
}
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
@@ -398,15 +401,28 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* Step 5 */
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
/*
- * See section 4.3 bullet 6:
- * The default Max Packet size for ep0 is "8 bytes for a USB2
- * LS/FS/HS device or 512 bytes for a USB3 SS device"
* XXX: Not sure about wireless USB devices.
*/
- if (udev->speed == USB_SPEED_SUPER)
+ switch (udev->speed) {
+ case USB_SPEED_SUPER:
ep0_ctx->ep_info2 |= MAX_PACKET(512);
- else
+ 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);
+ break;
+ case USB_SPEED_LOW:
ep0_ctx->ep_info2 |= MAX_PACKET(8);
+ break;
+ case USB_SPEED_VARIABLE:
+ xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
+ return -EINVAL;
+ break;
+ default:
+ /* New speed? */
+ 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);
@@ -598,6 +614,44 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
*/
}
+/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
+ * Useful when you want to change one particular aspect of the endpoint and then
+ * issue a configure endpoint command.
+ */
+void xhci_endpoint_copy(struct xhci_hcd *xhci,
+ struct xhci_virt_device *vdev, unsigned int ep_index)
+{
+ struct xhci_ep_ctx *out_ep_ctx;
+ struct xhci_ep_ctx *in_ep_ctx;
+
+ out_ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
+ in_ep_ctx = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
+
+ in_ep_ctx->ep_info = out_ep_ctx->ep_info;
+ in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2;
+ in_ep_ctx->deq = out_ep_ctx->deq;
+ in_ep_ctx->tx_info = out_ep_ctx->tx_info;
+}
+
+/* Copy output xhci_slot_ctx to the input xhci_slot_ctx.
+ * Useful when you want to change one particular aspect of the endpoint and then
+ * issue a configure endpoint command. Only the context entries field matters,
+ * but we'll copy the whole thing anyway.
+ */
+void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev)
+{
+ struct xhci_slot_ctx *in_slot_ctx;
+ struct xhci_slot_ctx *out_slot_ctx;
+
+ in_slot_ctx = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+ out_slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
+ in_slot_ctx->dev_info = out_slot_ctx->dev_info;
+ in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2;
+ in_slot_ctx->tt_info = out_slot_ctx->tt_info;
+ in_slot_ctx->dev_state = out_slot_ctx->dev_state;
+}
+
/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
{
@@ -702,9 +756,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int i;
/* Free the Event Ring Segment Table and the actual Event Ring */
- xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
+ if (xhci->ir_set) {
+ xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
+ }
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
pci_free_consistent(pdev, size,
@@ -741,9 +797,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->dcbaa, xhci->dcbaa->dma);
xhci->dcbaa = NULL;
+ scratchpad_free(xhci);
xhci->page_size = 0;
xhci->page_shift = 0;
- scratchpad_free(xhci);
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 592fe7e623f7..8fb308d43bc1 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -24,6 +24,10 @@
#include "xhci.h"
+/* Device for a quirk */
+#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
+#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
+
static const char hcd_name[] = "xhci_hcd";
/* called after powerup, by probe or system-pm "wakeup" */
@@ -62,6 +66,15 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
xhci_print_registers(xhci);
+ /* Look for vendor-specific quirks */
+ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+ pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
+ pdev->revision == 0x0) {
+ xhci->quirks |= XHCI_RESET_EP_QUIRK;
+ xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
+ " endpoint cmd after reset endpoint\n");
+ }
+
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index aa88a067148b..9874d9a60080 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -172,8 +172,9 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
* have their chain bit cleared (so that each Link TRB is a separate TD).
*
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
- * set, but other sections talk about dealing with the chain bit set.
- * Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB.
+ * set, but other sections talk about dealing with the chain bit set. This was
+ * fixed in the 0.96 specification errata, but we have to assume that all 0.95
+ * xHCI hardware can't handle the chain bit being cleared on a link TRB.
*/
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
{
@@ -191,8 +192,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
while (last_trb(xhci, ring, ring->enq_seg, next)) {
if (!consumer) {
if (ring != xhci->event_ring) {
- next->link.control &= ~TRB_CHAIN;
- next->link.control |= chain;
+ /* If we're not dealing with 0.95 hardware,
+ * carry over the chain bit of the previous TRB
+ * (which may mean the chain bit is cleared).
+ */
+ if (!xhci_link_trb_quirk(xhci)) {
+ next->link.control &= ~TRB_CHAIN;
+ next->link.control |= chain;
+ }
/* Give this link TRB to the hardware */
wmb();
if (next->link.control & TRB_CYCLE)
@@ -462,7 +469,6 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
* ring running.
*/
ep_ring->state |= SET_DEQ_PENDING;
- xhci_ring_cmd_db(xhci);
}
/*
@@ -531,6 +537,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
xhci_queue_new_dequeue_state(xhci, ep_ring,
slot_id, ep_index, &deq_state);
+ xhci_ring_cmd_db(xhci);
} else {
/* Otherwise just ring the doorbell to restart the ring */
ring_ep_doorbell(xhci, slot_id, ep_index);
@@ -644,18 +651,31 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
{
int slot_id;
unsigned int ep_index;
+ struct xhci_ring *ep_ring;
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+ ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
/* This command will only fail if the endpoint wasn't halted,
* but we don't care.
*/
xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
(unsigned int) GET_COMP_CODE(event->status));
- /* Clear our internal halted state and restart the ring */
- xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED;
- ring_ep_doorbell(xhci, slot_id, ep_index);
+ /* HW with the reset endpoint quirk needs to have a configure endpoint
+ * command complete before the endpoint can be used. Queue that here
+ * because the HW can't handle two commands being queued in a row.
+ */
+ if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
+ xhci_dbg(xhci, "Queueing configure endpoint command\n");
+ xhci_queue_configure_endpoint(xhci,
+ xhci->devs[slot_id]->in_ctx->dma, slot_id);
+ xhci_ring_cmd_db(xhci);
+ } else {
+ /* Clear our internal halted state and restart the ring */
+ ep_ring->state &= ~EP_HALTED;
+ ring_ep_doorbell(xhci, slot_id, ep_index);
+ }
}
static void handle_cmd_completion(struct xhci_hcd *xhci,
@@ -664,6 +684,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
int slot_id = TRB_TO_SLOT_ID(event->flags);
u64 cmd_dma;
dma_addr_t cmd_dequeue_dma;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ unsigned int ep_index;
+ struct xhci_ring *ep_ring;
+ unsigned int ep_state;
cmd_dma = event->cmd_trb;
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
@@ -691,6 +715,41 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
xhci_free_virt_device(xhci, slot_id);
break;
case TRB_TYPE(TRB_CONFIG_EP):
+ /*
+ * Configure endpoint commands can come from the USB core
+ * configuration or alt setting changes, or because the HW
+ * needed an extra configure endpoint command after a reset
+ * endpoint command. In the latter case, the xHCI driver is
+ * not waiting on the configure endpoint command.
+ */
+ ctrl_ctx = xhci_get_input_control_ctx(xhci,
+ xhci->devs[slot_id]->in_ctx);
+ /* Input ctx add_flags are the endpoint index plus one */
+ ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
+ ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+ if (!ep_ring) {
+ /* This must have been an initial configure endpoint */
+ xhci->devs[slot_id]->cmd_status =
+ GET_COMP_CODE(event->status);
+ complete(&xhci->devs[slot_id]->cmd_completion);
+ break;
+ }
+ ep_state = ep_ring->state;
+ xhci_dbg(xhci, "Completed config ep cmd - last ep index = %d, "
+ "state = %d\n", ep_index, ep_state);
+ if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
+ ep_state & EP_HALTED) {
+ /* Clear our internal halted state and restart ring */
+ xhci->devs[slot_id]->ep_rings[ep_index]->state &=
+ ~EP_HALTED;
+ ring_ep_doorbell(xhci, slot_id, ep_index);
+ } else {
+ xhci->devs[slot_id]->cmd_status =
+ GET_COMP_CODE(event->status);
+ complete(&xhci->devs[slot_id]->cmd_completion);
+ }
+ break;
+ case TRB_TYPE(TRB_EVAL_CONTEXT):
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion);
break;
@@ -763,9 +822,11 @@ static struct xhci_segment *trb_in_td(
cur_seg = start_seg;
do {
+ if (start_dma == 0)
+ return 0;
/* We may get an event for a Link TRB in the middle of a TD */
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
- &start_seg->trbs[TRBS_PER_SEGMENT - 1]);
+ &cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb);
@@ -792,8 +853,9 @@ static struct xhci_segment *trb_in_td(
}
cur_seg = cur_seg->next;
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
- } while (1);
+ } while (cur_seg != start_seg);
+ return 0;
}
/*
@@ -806,6 +868,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
{
struct xhci_virt_device *xdev;
struct xhci_ring *ep_ring;
+ unsigned int slot_id;
int ep_index;
struct xhci_td *td = 0;
dma_addr_t event_dma;
@@ -814,9 +877,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
struct urb *urb = 0;
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
+ u32 trb_comp_code;
xhci_dbg(xhci, "In %s\n", __func__);
- xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
+ slot_id = TRB_TO_SLOT_ID(event->flags);
+ xdev = xhci->devs[slot_id];
if (!xdev) {
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
return -ENODEV;
@@ -870,7 +935,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
(unsigned int) event->flags);
/* Look for common error cases */
- switch (GET_COMP_CODE(event->transfer_len)) {
+ trb_comp_code = GET_COMP_CODE(event->transfer_len);
+ switch (trb_comp_code) {
/* Skip codes that require special handling depending on
* transfer type
*/
@@ -913,7 +979,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Was this a control transfer? */
if (usb_endpoint_xfer_control(&td->urb->ep->desc)) {
xhci_debug_trb(xhci, xhci->event_ring->dequeue);
- switch (GET_COMP_CODE(event->transfer_len)) {
+ switch (trb_comp_code) {
case COMP_SUCCESS:
if (event_trb == ep_ring->dequeue) {
xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n");
@@ -928,8 +994,39 @@ static int handle_tx_event(struct xhci_hcd *xhci,
break;
case COMP_SHORT_TX:
xhci_warn(xhci, "WARN: short transfer on control ep\n");
- status = -EREMOTEIO;
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+ status = -EREMOTEIO;
+ else
+ status = 0;
break;
+ case COMP_BABBLE:
+ /* The 0.96 spec says a babbling control endpoint
+ * is not halted. The 0.96 spec says it is. Some HW
+ * claims to be 0.95 compliant, but it halts the control
+ * endpoint anyway. Check if a babble halted the
+ * endpoint.
+ */
+ if (ep_ctx->ep_info != EP_STATE_HALTED)
+ break;
+ /* else fall through */
+ case COMP_STALL:
+ /* Did we transfer part of the data (middle) phase? */
+ if (event_trb != ep_ring->dequeue &&
+ event_trb != td->last_trb)
+ td->urb->actual_length =
+ td->urb->transfer_buffer_length
+ - TRB_LEN(event->transfer_len);
+ else
+ td->urb->actual_length = 0;
+
+ ep_ring->stopped_td = td;
+ ep_ring->stopped_trb = event_trb;
+ xhci_queue_reset_ep(xhci, slot_id, ep_index);
+ xhci_cleanup_stalled_ring(xhci,
+ td->urb->dev,
+ ep_index, ep_ring);
+ xhci_ring_cmd_db(xhci);
+ goto td_cleanup;
default:
/* Others already handled above */
break;
@@ -943,7 +1040,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (event_trb == td->last_trb) {
if (td->urb->actual_length != 0) {
/* Don't overwrite a previously set error code */
- if (status == -EINPROGRESS || status == 0)
+ if ((status == -EINPROGRESS ||
+ status == 0) &&
+ (td->urb->transfer_flags
+ & URB_SHORT_NOT_OK))
/* Did we already see a short data stage? */
status = -EREMOTEIO;
} else {
@@ -952,7 +1052,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
}
} else {
/* Maybe the event was for the data stage? */
- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {
+ if (trb_comp_code != COMP_STOP_INVAL) {
/* We didn't stop on a link TRB in the middle */
td->urb->actual_length =
td->urb->transfer_buffer_length -
@@ -964,7 +1064,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
}
}
} else {
- switch (GET_COMP_CODE(event->transfer_len)) {
+ switch (trb_comp_code) {
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
if (event_trb != td->last_trb) {
@@ -975,7 +1075,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
else
status = 0;
} else {
- xhci_dbg(xhci, "Successful bulk transfer!\n");
+ if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
+ xhci_dbg(xhci, "Successful bulk "
+ "transfer!\n");
+ else
+ xhci_dbg(xhci, "Successful interrupt "
+ "transfer!\n");
status = 0;
}
break;
@@ -1001,11 +1106,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td->urb->actual_length =
td->urb->transfer_buffer_length -
TRB_LEN(event->transfer_len);
- if (td->urb->actual_length < 0) {
+ if (td->urb->transfer_buffer_length <
+ td->urb->actual_length) {
xhci_warn(xhci, "HC gave bad length "
"of %d bytes left\n",
TRB_LEN(event->transfer_len));
td->urb->actual_length = 0;
+ if (td->urb->transfer_flags &
+ URB_SHORT_NOT_OK)
+ status = -EREMOTEIO;
+ else
+ status = 0;
}
/* Don't overwrite a previously set error code */
if (status == -EINPROGRESS) {
@@ -1041,14 +1152,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* If the ring didn't stop on a Link or No-op TRB, add
* in the actual bytes transferred from the Normal TRB
*/
- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
+ if (trb_comp_code != COMP_STOP_INVAL)
td->urb->actual_length +=
TRB_LEN(cur_trb->generic.field[2]) -
TRB_LEN(event->transfer_len);
}
}
- if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||
- GET_COMP_CODE(event->transfer_len) == COMP_STOP) {
+ if (trb_comp_code == COMP_STOP_INVAL ||
+ trb_comp_code == COMP_STOP) {
/* The Endpoint Stop Command completion will take care of any
* stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet.
@@ -1056,7 +1167,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep_ring->stopped_td = td;
ep_ring->stopped_trb = event_trb;
} else {
- if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) {
+ if (trb_comp_code == COMP_STALL ||
+ trb_comp_code == COMP_BABBLE) {
/* The transfer is completed from the driver's
* perspective, but we need to issue a set dequeue
* command for this stalled endpoint to move the dequeue
@@ -1072,16 +1184,41 @@ static int handle_tx_event(struct xhci_hcd *xhci,
inc_deq(xhci, ep_ring, false);
}
+td_cleanup:
/* Clean up the endpoint's TD list */
urb = td->urb;
+ /* Do one last check of the actual transfer length.
+ * If the host controller said we transferred more data than
+ * the buffer length, urb->actual_length will be a very big
+ * number (since it's unsigned). Play it safe and say we didn't
+ * transfer anything.
+ */
+ if (urb->actual_length > urb->transfer_buffer_length) {
+ xhci_warn(xhci, "URB transfer length is wrong, "
+ "xHC issue? req. len = %u, "
+ "act. len = %u\n",
+ urb->transfer_buffer_length,
+ urb->actual_length);
+ urb->actual_length = 0;
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+ status = -EREMOTEIO;
+ else
+ status = 0;
+ }
list_del(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list)) {
list_del(&td->cancelled_td_list);
ep_ring->cancels_pending--;
}
- /* Leave the TD around for the reset endpoint function to use */
- if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) {
+ /* Leave the TD around for the reset endpoint function to use
+ * (but only if it's not a control endpoint, since we already
+ * queued the Set TR dequeue pointer command for stalled
+ * control endpoints).
+ */
+ if (usb_endpoint_xfer_control(&urb->ep->desc) ||
+ (trb_comp_code != COMP_STALL &&
+ trb_comp_code != COMP_BABBLE)) {
kfree(td);
}
urb->hcpriv = NULL;
@@ -1094,7 +1231,7 @@ cleanup:
if (urb) {
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
- urb, td->urb->actual_length, status);
+ urb, urb->actual_length, status);
spin_unlock(&xhci->lock);
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
spin_lock(&xhci->lock);
@@ -1335,6 +1472,47 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
ring_ep_doorbell(xhci, slot_id, ep_index);
}
+/*
+ * xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
+ * endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
+ * (comprised of sg list entries) can take several service intervals to
+ * transmit.
+ */
+int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+ struct urb *urb, int slot_id, unsigned int ep_index)
+{
+ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci,
+ xhci->devs[slot_id]->out_ctx, ep_index);
+ int xhci_interval;
+ int ep_interval;
+
+ xhci_interval = EP_INTERVAL_TO_UFRAMES(ep_ctx->ep_info);
+ ep_interval = urb->interval;
+ /* Convert to microframes */
+ if (urb->dev->speed == USB_SPEED_LOW ||
+ urb->dev->speed == USB_SPEED_FULL)
+ ep_interval *= 8;
+ /* FIXME change this to a warning and a suggestion to use the new API
+ * to set the polling interval (once the API is added).
+ */
+ if (xhci_interval != ep_interval) {
+ if (!printk_ratelimit())
+ dev_dbg(&urb->dev->dev, "Driver uses different interval"
+ " (%d microframe%s) than xHCI "
+ "(%d microframe%s)\n",
+ ep_interval,
+ ep_interval == 1 ? "" : "s",
+ xhci_interval,
+ xhci_interval == 1 ? "" : "s");
+ urb->interval = xhci_interval;
+ /* Convert back to frames for LS/FS devices */
+ if (urb->dev->speed == USB_SPEED_LOW ||
+ urb->dev->speed == USB_SPEED_FULL)
+ urb->interval /= 8;
+ }
+ return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+}
+
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
@@ -1733,6 +1911,15 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));
}
+/* Queue an evaluate context command TRB */
+int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+ u32 slot_id)
+{
+ return queue_command(xhci, lower_32_bits(in_ctx_ptr),
+ upper_32_bits(in_ctx_ptr), 0,
+ TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id));
+}
+
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index)
{
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d31d32206ba3..808584153579 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -581,6 +581,7 @@ struct xhci_ep_ctx {
/* bit 15 is Linear Stream Array */
/* Interval - period between requests to an endpoint - 125u increments. */
#define EP_INTERVAL(p) ((p & 0xff) << 16)
+#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
/* ep_info2 bitmasks */
/*
@@ -589,6 +590,7 @@ struct xhci_ep_ctx {
*/
#define FORCE_EVENT (0x1)
#define ERROR_COUNT(p) (((p) & 0x3) << 1)
+#define CTX_TO_EP_TYPE(p) (((p) >> 3) & 0x7)
#define EP_TYPE(p) ((p) << 3)
#define ISOC_OUT_EP 1
#define BULK_OUT_EP 2
@@ -601,6 +603,8 @@ struct xhci_ep_ctx {
/* bit 7 is Host Initiate Disable - for disabling stream selection */
#define MAX_BURST(p) (((p)&0xff) << 8)
#define MAX_PACKET(p) (((p)&0xffff) << 16)
+#define MAX_PACKET_MASK (0xffff << 16)
+#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
/**
@@ -926,6 +930,12 @@ struct xhci_td {
union xhci_trb *last_trb;
};
+struct xhci_dequeue_state {
+ struct xhci_segment *new_deq_seg;
+ union xhci_trb *new_deq_ptr;
+ int new_cycle_state;
+};
+
struct xhci_ring {
struct xhci_segment *first_seg;
union xhci_trb *enqueue;
@@ -952,12 +962,6 @@ struct xhci_ring {
u32 cycle_state;
};
-struct xhci_dequeue_state {
- struct xhci_segment *new_deq_seg;
- union xhci_trb *new_deq_ptr;
- int new_cycle_state;
-};
-
struct xhci_erst_entry {
/* 64-bit event ring segment address */
u64 seg_addr;
@@ -1058,6 +1062,9 @@ struct xhci_hcd {
int noops_submitted;
int noops_handled;
int error_bitmask;
+ unsigned int quirks;
+#define XHCI_LINK_TRB_QUIRK (1 << 0)
+#define XHCI_RESET_EP_QUIRK (1 << 1)
};
/* For testing purposes */
@@ -1136,6 +1143,13 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
writel(val_hi, ptr + 1);
}
+static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
+{
+ u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
+ return ((HC_VERSION(temp) == 0x95) &&
+ (xhci->quirks & XHCI_LINK_TRB_QUIRK));
+}
+
/* xHCI debugging */
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
void xhci_print_registers(struct xhci_hcd *xhci);
@@ -1158,7 +1172,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
+unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
+unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
+void xhci_endpoint_copy(struct xhci_hcd *xhci,
+ struct xhci_virt_device *vdev, unsigned int ep_index);
+void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev);
int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
@@ -1205,8 +1224,12 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
+int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
+ int slot_id, unsigned int ep_index);
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
+int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+ u32 slot_id);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
@@ -1215,6 +1238,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring, unsigned int slot_id,
unsigned int ep_index, struct xhci_dequeue_state *deq_state);
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ unsigned int ep_index, struct xhci_ring *ep_ring);
+void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
+ unsigned int slot_id, unsigned int ep_index,
+ struct xhci_dequeue_state *deq_state);
/* xHCI roothub code */
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 1d8e39a557d9..62ff5e729110 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -72,8 +72,8 @@ struct appledisplay {
struct usb_device *udev; /* usb device */
struct urb *urb; /* usb request block */
struct backlight_device *bd; /* backlight device */
- char *urbdata; /* interrupt URB data buffer */
- char *msgdata; /* control message data buffer */
+ u8 *urbdata; /* interrupt URB data buffer */
+ u8 *msgdata; /* control message data buffer */
struct delayed_work work;
int button_pressed;
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 602ee05ba9ff..59860b328534 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -167,7 +167,7 @@ static int emi62_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
- } while (i > 0);
+ } while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 0f7a30b7d2d1..fb1dd27be76d 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -350,12 +350,12 @@ static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
/*
* Return a few (kilo-)bytes to the head of the buffer.
- * This is used if a DMA fetch fails.
+ * This is used if a data fetch fails.
*/
static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
{
- size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ /* size &= ~(PKT_ALIGN-1); -- we're called with aligned size */
rp->b_cnt -= size;
if (rp->b_in < size)
rp->b_in += rp->b_size;
@@ -442,6 +442,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned int delta;
unsigned int ndesc, lendesc;
unsigned char dir;
struct mon_bin_hdr *ep;
@@ -546,8 +547,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length != 0) {
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
- ep->len_cap = 0;
- mon_buff_area_shrink(rp, length);
+ delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ ep->len_cap -= length;
+ delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ mon_buff_area_shrink(rp, delta);
}
} else {
ep->flag_data = data_tag;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 8b3c4e2ed7b8..74073f9a43f0 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -4,6 +4,7 @@
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -436,14 +437,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~MUSB_TXCSR_P_SENTSTALL;
musb_writew(epio, MUSB_TXCSR, csr);
- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
- dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- musb->dma_controller->channel_abort(dma);
- }
-
- if (request)
- musb_g_giveback(musb_ep, request, -EPIPE);
-
break;
}
@@ -582,15 +575,25 @@ void musb_g_tx(struct musb *musb, u8 epnum)
*/
static void rxstate(struct musb *musb, struct musb_request *req)
{
- u16 csr = 0;
const u8 epnum = req->epnum;
struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
void __iomem *epio = musb->endpoints[epnum].regs;
unsigned fifo_count = 0;
u16 len = musb_ep->packet_sz;
+ u16 csr = musb_readw(epio, MUSB_RXCSR);
- csr = musb_readw(epio, MUSB_RXCSR);
+ /* We shouldn't get here while DMA is active, but we do... */
+ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
+ DBG(4, "DMA pending...\n");
+ return;
+ }
+
+ if (csr & MUSB_RXCSR_P_SENDSTALL) {
+ DBG(5, "%s stalling, RXCSR %04x\n",
+ musb_ep->end_point.name, csr);
+ return;
+ }
if (is_cppi_enabled() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller;
@@ -761,19 +764,10 @@ void musb_g_rx(struct musb *musb, u8 epnum)
csr, dma ? " (dma)" : "", request);
if (csr & MUSB_RXCSR_P_SENTSTALL) {
- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
- dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- (void) musb->dma_controller->channel_abort(dma);
- request->actual += musb_ep->dma->actual_len;
- }
-
csr |= MUSB_RXCSR_P_WZC_BITS;
csr &= ~MUSB_RXCSR_P_SENTSTALL;
musb_writew(epio, MUSB_RXCSR, csr);
-
- if (request)
- musb_g_giveback(musb_ep, request, -EPIPE);
- goto done;
+ return;
}
if (csr & MUSB_RXCSR_P_OVERRUN) {
@@ -795,7 +789,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
DBG((csr & MUSB_RXCSR_DMAENAB) ? 4 : 1,
"%s busy, csr %04x\n",
musb_ep->end_point.name, csr);
- goto done;
+ return;
}
if (dma && (csr & MUSB_RXCSR_DMAENAB)) {
@@ -826,22 +820,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
== musb_ep->packet_sz))
- goto done;
+ return;
#endif
musb_g_giveback(musb_ep, request, 0);
request = next_request(musb_ep);
if (!request)
- goto done;
-
- /* don't start more i/o till the stall clears */
- musb_ep_select(mbase, epnum);
- csr = musb_readw(epio, MUSB_RXCSR);
- if (csr & MUSB_RXCSR_P_SENDSTALL)
- goto done;
+ return;
}
-
/* analyze request if the ep is hot */
if (request)
rxstate(musb, to_musb_request(request));
@@ -849,8 +836,6 @@ void musb_g_rx(struct musb *musb, u8 epnum)
DBG(3, "packet waiting for %s%s request\n",
musb_ep->desc ? "" : "inactive ",
musb_ep->end_point.name);
-
-done:
return;
}
@@ -1244,7 +1229,7 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
void __iomem *mbase;
unsigned long flags;
u16 csr;
- struct musb_request *request = NULL;
+ struct musb_request *request;
int status = 0;
if (!ep)
@@ -1260,24 +1245,29 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_ep_select(mbase, epnum);
- /* cannot portably stall with non-empty FIFO */
request = to_musb_request(next_request(musb_ep));
- if (value && musb_ep->is_in) {
- csr = musb_readw(epio, MUSB_TXCSR);
- if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
- DBG(3, "%s fifo busy, cannot halt\n", ep->name);
- spin_unlock_irqrestore(&musb->lock, flags);
- return -EAGAIN;
+ if (value) {
+ if (request) {
+ DBG(3, "request in progress, cannot halt %s\n",
+ ep->name);
+ status = -EAGAIN;
+ goto done;
+ }
+ /* Cannot portably stall with non-empty FIFO */
+ if (musb_ep->is_in) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
+ DBG(3, "FIFO busy, cannot halt %s\n", ep->name);
+ status = -EAGAIN;
+ goto done;
+ }
}
-
}
/* set/clear the stall and toggle bits */
DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear");
if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
- if (csr & MUSB_TXCSR_FIFONOTEMPTY)
- csr |= MUSB_TXCSR_FLUSHFIFO;
csr |= MUSB_TXCSR_P_WZC_BITS
| MUSB_TXCSR_CLRDATATOG;
if (value)
@@ -1300,14 +1290,13 @@ int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_writew(epio, MUSB_RXCSR, csr);
}
-done:
-
/* maybe start the first request in the queue */
if (!musb_ep->busy && !value && request) {
DBG(3, "restarting the request\n");
musb_ep_restart(musb, request);
}
+done:
spin_unlock_irqrestore(&musb->lock, flags);
return status;
}
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 7a6778675ad3..677cc2ee9fd3 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -199,7 +199,6 @@ service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
{
musb_g_giveback(&musb->endpoints[0].ep_in, req, 0);
- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
}
/*
@@ -647,7 +646,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
break;
default:
- ERR("SetupEnd came in a wrong ep0stage %s",
+ ERR("SetupEnd came in a wrong ep0stage %s\n",
decode_ep0stage(musb->ep0_state));
}
csr = musb_readw(regs, MUSB_CSR0);
@@ -770,12 +769,18 @@ setup:
handled = service_zero_data_request(
musb, &setup);
+ /*
+ * We're expecting no data in any case, so
+ * always set the DATAEND bit -- doing this
+ * here helps avoid SetupEnd interrupt coming
+ * in the idle stage when we're stalling...
+ */
+ musb->ackpend |= MUSB_CSR0_P_DATAEND;
+
/* status stage might be immediate */
- if (handled > 0) {
- musb->ackpend |= MUSB_CSR0_P_DATAEND;
+ if (handled > 0)
musb->ep0_state =
MUSB_EP0_STAGE_STATUSIN;
- }
break;
/* sequence #1 (IN to host), includes GET_STATUS
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 81a2985632b6..6941e0565c03 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -34,7 +34,6 @@
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/timer.h>
-#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -62,8 +61,6 @@
#define DRIVER_DESC "Freescale USB OTG Driver"
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-#define TIMER_FREQ 1000 /* 100 ms*/
-#define IDLE_TIME 5000 /* 1000 ms */
MODULE_DESCRIPTION("Freescale USB OTG Transceiver Driver");
@@ -93,13 +90,6 @@ static struct fsl_otg_config fsl_otg_initdata = {
.otg_port = 1,
};
-/* the timer is used to monitor the otg loading, if idle for some times
- * we will close the otg clk
- */
-static unsigned long last_busy;
-static bool clk_stopped;
-static struct timer_list monitor_timer;
-
int write_ulpi(u8 addr, u8 data)
{
u32 temp;
@@ -149,6 +139,15 @@ void fsl_otg_dischrg_vbus(int on)
/* A-device driver vbus, controlled through PP bit in PORTSC */
void fsl_otg_drv_vbus(struct fsl_usb2_platform_data *pdata, int on)
{
+/* if (on)
+ usb_dr_regs->portsc =
+ cpu_to_le32((le32_to_cpu(usb_dr_regs->portsc) &
+ ~PORTSC_W1C_BITS) | PORTSC_PORT_POWER);
+ else
+ usb_dr_regs->portsc =
+ cpu_to_le32(le32_to_cpu(usb_dr_regs->portsc) &
+ ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER);
+*/
if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power)
pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on);
}
@@ -399,61 +398,6 @@ int fsl_otg_tick_timer(void)
return expired;
}
-static void fsl_otg_clk_gate(bool on)
-{
- struct device *dev = fsl_otg_dev->otg.dev;
- struct fsl_usb2_platform_data *pdata;
-
- if (dev) {
- pdata = dev->platform_data;
- if (pdata && pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(on);
- }
-}
-
-static void fsl_otg_clk_ctl(void)
-{
- if (clk_stopped){
- fsl_otg_clk_gate(true);
- clk_stopped = false;
- }
- last_busy = jiffies;
-}
-
-static void fsl_otg_loading_monitor(unsigned long data)
-{
- unsigned long now = jiffies;
- if (!clk_stopped){
- if (time_after(now, last_busy + msecs_to_jiffies(IDLE_TIME))){
- printk("otg is idle for some times,so we close the clock %x\n", le32_to_cpu(usb_dr_regs->otgsc));
- clk_stopped = true;
- fsl_otg_clk_gate(false);
- printk("close otg clk ok\n");
- }
- }
- mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ));
-}
-
-/**
- * Enable vbus interrupt
- * The otg cares USB_ID interrupt
- * The device cares B Sesstion Valid
- */
-static void b_session_irq_enable(bool enable)
-{
- int osc = le32_to_cpu(usb_dr_regs->otgsc);
- /* The other interrupts' status should not be cleared */
- osc &= ~(OTGSC_INTSTS_USB_ID | OTGSC_INTSTS_A_VBUS_VALID
- | OTGSC_INTSTS_A_SESSION_VALID | OTGSC_INTSTS_B_SESSION_VALID);
- osc |= OTGSC_INTSTS_B_SESSION_VALID;
-
- if (enable)
- osc |= OTGSC_INTR_B_SESSION_VALID_EN;
- else
- osc &= ~OTGSC_INTR_B_SESSION_VALID_EN;
- usb_dr_regs->otgsc = cpu_to_le32(osc);
-}
-
/* Reset controller, not reset the bus */
void otg_reset_controller(void)
{
@@ -540,6 +484,7 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
struct device *dev;
struct platform_driver *gadget_pdrv;
struct platform_device *gadget_pdev;
+
if (!xceiv->gadget || !xceiv->gadget->dev.parent)
return -ENODEV;
@@ -575,6 +520,7 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
if (host) {
VDBG("host off......\n");
+
otg_p->host->otg_port = fsl_otg_initdata.otg_port;
otg_p->host->is_b_host = otg_dev->fsm.id;
/* must leave time for khubd to finish its thing
@@ -691,29 +637,11 @@ static void fsl_otg_event(struct work_struct *work)
{
struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
struct otg_fsm *fsm = &og->fsm;
- struct otg_transceiver *otg = &og->otg;
-
- otg->default_a = (fsm->id == 0);
- /* clear conn information */
- if (fsm->id)
- fsm->b_conn = 0;
- else
- fsm->a_conn = 0;
-
- if (otg->host)
- otg->host->is_b_host = fsm->id;
- if (otg->gadget)
- otg->gadget->is_a_peripheral = !fsm->id;
if (fsm->id) { /* switch to gadget */
- b_session_irq_enable(true);
fsl_otg_start_host(fsm, 0);
otg_drv_vbus(fsm, 0);
fsl_otg_start_gadget(fsm, 1);
- }else { /* switch to host */
- fsl_otg_start_gadget(fsm, 0);
- otg_drv_vbus(fsm, 1);
- fsl_otg_start_host(fsm, 1);
}
}
@@ -753,13 +681,13 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
struct otg_fsm *fsm;
struct fsl_usb2_platform_data *pdata =
(struct fsl_usb2_platform_data *)dev_id;
- struct fsl_otg *f_otg;
+ struct fsl_otg *p_otg;
struct otg_transceiver *otg_trans = otg_get_transceiver();
int value;
- f_otg = container_of(otg_trans, struct fsl_otg, otg);
- fsm = &f_otg->fsm;
- fsl_otg_clk_ctl();
+ p_otg = container_of(otg_trans, struct fsl_otg, otg);
+ fsm = &p_otg->fsm;
+
if (pdata->id_gpio == 0)
return IRQ_NONE;
@@ -771,25 +699,35 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
set_irq_type(gpio_to_irq(pdata->id_gpio), IRQ_TYPE_LEVEL_HIGH);
- if (value == f_otg->fsm.id)
+ if (value == p_otg->fsm.id)
return IRQ_HANDLED;
- f_otg->fsm.id = value;
+ p_otg->fsm.id = value;
- cancel_delayed_work(&f_otg->otg_event);
- schedule_delayed_work(&f_otg->otg_event, msecs_to_jiffies(10));
- /* if host mode, we should clear B_SESSION_VLD event and disable
- * B_SESSION_VLD irq
- */
- if (!f_otg->fsm.id) {
- b_session_irq_enable(false);
- }else {
- //b_session_irq_enable(true);
- }
+ otg_trans->default_a = (fsm->id == 0);
+ /* clear conn information */
+ if (fsm->id)
+ fsm->b_conn = 0;
+ else
+ fsm->a_conn = 0;
+ if (otg_trans->host)
+ otg_trans->host->is_b_host = fsm->id;
+ if (otg_trans->gadget)
+ otg_trans->gadget->is_a_peripheral = !fsm->id;
+
+ VDBG("ID int (ID is %d)\n", fsm->id);
+ if (fsm->id) { /* switch to gadget */
+ schedule_delayed_work(&p_otg->otg_event, 100);
+
+ } else { /* switch to host */
+ cancel_delayed_work(&p_otg->otg_event);
+ fsl_otg_start_gadget(fsm, 0);
+ otg_drv_vbus(fsm, 1);
+ fsl_otg_start_host(fsm, 1);
+ }
return IRQ_HANDLED;
}
-
/* Interrupt handler. OTG/host/peripheral share the same int line.
* OTG driver clears OTGSC interrupts and leaves USB interrupts
* intact. It needs to have knowledge of some USB interrupts
@@ -797,65 +735,71 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
*/
irqreturn_t fsl_otg_isr(int irq, void *dev_id)
{
- struct fsl_otg *fotg = (struct fsl_otg *)dev_id;
- struct otg_transceiver *otg = &fotg->otg;
+ struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
+ struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg;
u32 otg_int_src, otg_sc;
- irqreturn_t ret = IRQ_NONE;
- fsl_otg_clk_ctl();
otg_sc = le32_to_cpu(usb_dr_regs->otgsc);
otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8);
- /* Only clear otg interrupts, expect B_SESSION_VALID,
- * Leave it to be handled by arcotg_udc */
- usb_dr_regs->otgsc = ((usb_dr_regs->otgsc | cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK))&
- (~OTGSC_INTSTS_B_SESSION_VALID));
+ /* Only clear otg interrupts */
+ usb_dr_regs->otgsc |= cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK);
/*FIXME: ID change not generate when init to 0 */
- fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
- otg->default_a = (fotg->fsm.id == 0);
+ fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+ otg->default_a = (fsm->id == 0);
/* process OTG interrupts */
if (otg_int_src) {
if (otg_int_src & OTGSC_INTSTS_USB_ID) {
- fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
-
- printk("ID int (ID is %d)\n", fotg->fsm.id);
-
- cancel_delayed_work(&fotg->otg_event);
- schedule_delayed_work(&fotg->otg_event, msecs_to_jiffies(10));
- /* if host mode, we should clear B_SESSION_VLD event and disable
- * B_SESSION_VLD irq
- */
- if (!fotg->fsm.id) {
- b_session_irq_enable(false);
- }else {
- //b_session_irq_enable(true);
+ fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+ otg->default_a = (fsm->id == 0);
+ /* clear conn information */
+ if (fsm->id)
+ fsm->b_conn = 0;
+ else
+ fsm->a_conn = 0;
+
+ if (otg->host)
+ otg->host->is_b_host = fsm->id;
+ if (otg->gadget)
+ otg->gadget->is_a_peripheral = !fsm->id;
+ VDBG("ID int (ID is %d)\n", fsm->id);
+
+ if (fsm->id) { /* switch to gadget */
+ schedule_delayed_work(&((struct fsl_otg *)
+ dev_id)->otg_event,
+ 100);
+ } else { /* switch to host */
+ cancel_delayed_work(&
+ ((struct fsl_otg *)dev_id)->
+ otg_event);
+ fsl_otg_start_gadget(fsm, 0);
+ otg_drv_vbus(fsm, 1);
+ fsl_otg_start_host(fsm, 1);
}
- ret = IRQ_HANDLED;
+
+ return IRQ_HANDLED;
}
}
- return ret;
+ return IRQ_NONE;
}
static void fsl_otg_fsm_drv_vbus(int on)
{
struct otg_fsm *fsm = &(fsl_otg_dev->fsm);
struct otg_transceiver *xceiv = fsm->transceiver;
+ struct device *dev = NULL;
- struct device *dev;
- /*
- * The host is assigned at otg_set_host
- */
- if (!xceiv->host)
+ if (!xceiv->host) {
return;
- /*
- * The dev is assigned at usb_create_hcd which is called earlier
- * than otg_set_host at host driver's probe
- */
+ }
+
dev = xceiv->host->controller;
+
fsl_otg_drv_vbus(dev->platform_data, on);
+
}
static struct otg_fsm_ops fsl_otg_ops = {
@@ -913,7 +857,6 @@ static int fsl_otg_conf(struct platform_device *pdev)
fsl_otg_tc->otg.set_power = fsl_otg_set_power;
fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp;
fsl_otg_tc->otg.start_srp = fsl_otg_start_srp;
- fsl_otg_tc->otg.dev = &pdev->dev;
fsl_otg_dev = fsl_otg_tc;
@@ -980,8 +923,6 @@ int usb_otg_start(struct platform_device *pdev)
if (pdata->platform_init && pdata->platform_init(pdev) != 0)
return -EINVAL;
- clk_stopped = false; /* platform_init will open the otg clk */
-
/* stop the controller */
temp = readl(&p_otg->dr_mem_map->usbcmd);
temp &= ~USB_CMD_RUN_STOP;
@@ -1308,10 +1249,6 @@ static int __init fsl_otg_probe(struct platform_device *pdev)
return -EIO;
}
- last_busy = jiffies;
- setup_timer(&monitor_timer, fsl_otg_loading_monitor, (unsigned long)pdev);
- mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ));
-
create_proc_file();
return status;
}
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index aec61880f36c..1a50beb32029 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -35,11 +35,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-struct ark3116_private {
- spinlock_t lock;
- u8 termios_initialized;
-};
-
static inline void ARK3116_SND(struct usb_serial *serial, int seq,
__u8 request, __u8 requesttype,
__u16 value, __u16 index)
@@ -82,22 +77,11 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
static int ark3116_attach(struct usb_serial *serial)
{
char *buf;
- struct ark3116_private *priv;
- int i;
-
- for (i = 0; i < serial->num_ports; ++i) {
- priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
- if (!priv)
- goto cleanup;
- spin_lock_init(&priv->lock);
-
- usb_set_serial_port_data(serial->port[i], priv);
- }
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
dbg("error kmalloc -> out of mem?");
- goto cleanup;
+ return -ENOMEM;
}
/* 3 */
@@ -149,13 +133,16 @@ static int ark3116_attach(struct usb_serial *serial)
kfree(buf);
return 0;
+}
-cleanup:
- for (--i; i >= 0; --i) {
- kfree(usb_get_serial_port_data(serial->port[i]));
- usb_set_serial_port_data(serial->port[i], NULL);
- }
- return -ENOMEM;
+static void ark3116_init_termios(struct tty_struct *tty)
+{
+ struct ktermios *termios = tty->termios;
+ *termios = tty_std_termios;
+ termios->c_cflag = B9600 | CS8
+ | CREAD | HUPCL | CLOCAL;
+ termios->c_ispeed = 9600;
+ termios->c_ospeed = 9600;
}
static void ark3116_set_termios(struct tty_struct *tty,
@@ -163,10 +150,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
struct ktermios *termios = tty->termios;
unsigned int cflag = termios->c_cflag;
- unsigned long flags;
int baud;
int ark3116_baud;
char *buf;
@@ -176,16 +161,6 @@ static void ark3116_set_termios(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->termios_initialized) {
- *termios = tty_std_termios;
- termios->c_cflag = B9600 | CS8
- | CREAD | HUPCL | CLOCAL;
- termios->c_ispeed = 9600;
- termios->c_ospeed = 9600;
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
cflag = termios->c_cflag;
termios->c_cflag &= ~(CMSPAR|CRTSCTS);
@@ -455,6 +430,7 @@ static struct usb_serial_driver ark3116_device = {
.num_ports = 1,
.attach = ark3116_attach,
.set_termios = ark3116_set_termios,
+ .init_termios = ark3116_init_termios,
.ioctl = ark3116_ioctl,
.tiocmget = ark3116_tiocmget,
.open = ark3116_open,
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 0e4f2e41ace5..3e49b2ed0266 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/serial.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
@@ -63,7 +64,7 @@ static int usb_console_setup(struct console *co, char *options)
char *s;
struct usb_serial *serial;
struct usb_serial_port *port;
- int retval = 0;
+ int retval;
struct tty_struct *tty = NULL;
struct ktermios *termios = NULL, dummy;
@@ -116,13 +117,17 @@ static int usb_console_setup(struct console *co, char *options)
return -ENODEV;
}
- port = serial->port[0];
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto error_get_interface;
+
+ port = serial->port[co->index - serial->minor];
tty_port_tty_set(&port->port, NULL);
info->port = port;
++port->port.count;
- if (port->port.count == 1) {
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
if (serial->type->set_termios) {
/*
* allocate a fake tty so the driver can initialize
@@ -168,6 +173,7 @@ static int usb_console_setup(struct console *co, char *options)
kfree(termios);
kfree(tty);
}
+ set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
/* Now that any required fake tty operations are completed restore
* the tty port count */
@@ -175,18 +181,22 @@ static int usb_console_setup(struct console *co, char *options)
/* The console is special in terms of closing the device so
* indicate this port is now acting as a system console. */
port->console = 1;
- retval = 0;
-out:
+ mutex_unlock(&serial->disc_mutex);
return retval;
-free_termios:
+
+ free_termios:
kfree(termios);
tty_port_tty_set(&port->port, NULL);
-free_tty:
+ free_tty:
kfree(tty);
-reset_open_count:
+ reset_open_count:
port->port.count = 0;
- goto out;
+ usb_autopm_put_interface(serial->interface);
+ error_get_interface:
+ usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
+ return retval;
}
static void usb_console_write(struct console *co,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 985cbcf48bda..2367325e80b0 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -51,6 +51,8 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_startup(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
+static int cp210x_carrier_raised(struct usb_serial_port *p);
static int debug;
@@ -114,6 +116,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
{ } /* Terminating Entry */
};
@@ -143,6 +146,8 @@ static struct usb_serial_driver cp210x_device = {
.tiocmset = cp210x_tiocmset,
.attach = cp210x_startup,
.disconnect = cp210x_disconnect,
+ .dtr_rts = cp210x_dtr_rts,
+ .carrier_raised = cp210x_carrier_raised
};
/* Config request types */
@@ -399,12 +404,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
/* Configure the termios structure */
cp210x_get_termios(tty, port);
-
- /* Set the DTR and RTS pins low */
- cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
- : port,
- NULL, TIOCM_DTR | TIOCM_RTS, 0);
-
return 0;
}
@@ -753,6 +752,14 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,
return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
}
+static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
+{
+ if (on)
+ cp210x_tiocmset_port(p, NULL, TIOCM_DTR|TIOCM_RTS, 0);
+ else
+ cp210x_tiocmset_port(p, NULL, 0, TIOCM_DTR|TIOCM_RTS);
+}
+
static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
@@ -775,6 +782,15 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
return result;
}
+static int cp210x_carrier_raised(struct usb_serial_port *p)
+{
+ unsigned int control;
+ cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1);
+ if (control & CONTROL_DCD)
+ return 1;
+ return 0;
+}
+
static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 59adfe123110..27b5a271fe4a 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -659,15 +659,7 @@ static int cypress_open(struct tty_struct *tty,
spin_unlock_irqrestore(&priv->lock, flags);
/* Set termios */
- result = cypress_write(tty, port, NULL, 0);
-
- if (result) {
- dev_err(&port->dev,
- "%s - failed setting the control lines - error %d\n",
- __func__, result);
- return result;
- } else
- dbg("%s - success setting the control lines", __func__);
+ cypress_send(port);
if (tty)
cypress_set_termios(tty, port, &priv->tmp_termios);
@@ -1005,6 +997,8 @@ static void cypress_set_termios(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
+ /* We can't clean this one up as we don't know the device type
+ early enough */
if (!priv->termios_initialized) {
if (priv->chiptype == CT_EARTHMATE) {
*(tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index f4808091c47c..9bd82b487005 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -899,16 +899,16 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
spin_lock_irqsave(&priv->dp_port_lock, flags);
- /* turn throttle off */
- priv->dp_throttled = 0;
- priv->dp_throttle_restart = 0;
-
/* restart read chain */
if (priv->dp_throttle_restart) {
port->read_urb->dev = port->serial->dev;
ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
}
+ /* turn throttle off */
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
+
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret)
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 80cb3471adbe..3433f9db4418 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -90,8 +90,7 @@ static int empeg_chars_in_buffer(struct tty_struct *tty);
static void empeg_throttle(struct tty_struct *tty);
static void empeg_unthrottle(struct tty_struct *tty);
static int empeg_startup(struct usb_serial *serial);
-static void empeg_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios);
+static void empeg_init_termios(struct tty_struct *tty);
static void empeg_write_bulk_callback(struct urb *urb);
static void empeg_read_bulk_callback(struct urb *urb);
@@ -123,7 +122,7 @@ static struct usb_serial_driver empeg_device = {
.throttle = empeg_throttle,
.unthrottle = empeg_unthrottle,
.attach = empeg_startup,
- .set_termios = empeg_set_termios,
+ .init_termios = empeg_init_termios,
.write = empeg_write,
.write_room = empeg_write_room,
.chars_in_buffer = empeg_chars_in_buffer,
@@ -150,9 +149,6 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
dbg("%s - port %d", __func__, port->number);
- /* Force default termio settings */
- empeg_set_termios(tty, port, NULL) ;
-
bytes_in = 0;
bytes_out = 0;
@@ -425,11 +421,9 @@ static int empeg_startup(struct usb_serial *serial)
}
-static void empeg_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
+static void empeg_init_termios(struct tty_struct *tty)
{
struct ktermios *termios = tty->termios;
- dbg("%s - port %d", __func__, port->number);
/*
* The empeg-car player wants these particular tty settings.
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8fec5d4455c9..84102014ed5b 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -76,13 +76,7 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
- __u8 rx_flags; /* receive state flags (throttling) */
- spinlock_t rx_lock; /* spinlock for receive state */
- struct delayed_work rx_work;
struct usb_serial_port *port;
- int rx_processed;
- unsigned long rx_bytes;
-
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
@@ -176,6 +170,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
@@ -694,6 +691,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(DE_VID, WHT_PID) },
{ USB_DEVICE(ADI_VID, ADI_GNICE_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -702,6 +701,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
+ { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -730,10 +731,6 @@ static const char *ftdi_chip_name[] = {
/* Constants for read urb and write urb */
#define BUFSZ 512
-/* rx_flags */
-#define THROTTLED 0x01
-#define ACTUALLY_THROTTLED 0x02
-
/* Used for TIOCMIWAIT */
#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
@@ -757,7 +754,7 @@ static int ftdi_write_room(struct tty_struct *tty);
static int ftdi_chars_in_buffer(struct tty_struct *tty);
static void ftdi_write_bulk_callback(struct urb *urb);
static void ftdi_read_bulk_callback(struct urb *urb);
-static void ftdi_process_read(struct work_struct *work);
+static void ftdi_process_read(struct usb_serial_port *port);
static void ftdi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int ftdi_tiocmget(struct tty_struct *tty, struct file *file);
@@ -1228,7 +1225,6 @@ static int set_serial_info(struct tty_struct *tty,
(new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
- tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
check_and_exit:
@@ -1521,7 +1517,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
}
kref_init(&priv->kref);
- spin_lock_init(&priv->rx_lock);
spin_lock_init(&priv->tx_lock);
init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
@@ -1543,7 +1538,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
port->read_urb->transfer_buffer_length = BUFSZ;
}
- INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read);
priv->port = port;
/* Free port's existing write urb and transfer buffer. */
@@ -1680,6 +1674,26 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
return 0;
}
+static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
+{
+ struct urb *urb = port->read_urb;
+ struct usb_serial *serial = port->serial;
+ int result;
+
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ ftdi_read_bulk_callback, port);
+ result = usb_submit_urb(urb, mem_flags);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
+ return result;
+}
+
static int ftdi_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{ /* ftdi_open */
@@ -1695,12 +1709,6 @@ static int ftdi_open(struct tty_struct *tty,
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_bytes = 0;
spin_unlock_irqrestore(&priv->tx_lock, flags);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_bytes = 0;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
-
- if (tty)
- tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
@@ -1720,23 +1728,14 @@ static int ftdi_open(struct tty_struct *tty,
ftdi_set_termios(tty, port, tty->termios);
/* Not throttled */
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttled = 0;
+ port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
/* Start reading from the device */
- priv->rx_processed = 0;
- usb_fill_bulk_urb(port->read_urb, dev,
- usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ftdi_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __func__, result);
- else
+ result = ftdi_submit_read_urb(port, GFP_KERNEL);
+ if (!result)
kref_get(&priv->kref);
return result;
@@ -1782,10 +1781,6 @@ static void ftdi_close(struct usb_serial_port *port)
dbg("%s", __func__);
-
- /* cancel any scheduled reading */
- cancel_delayed_work_sync(&priv->rx_work);
-
/* shutdown our bulk read */
usb_kill_urb(port->read_urb);
kref_put(&priv->kref, ftdi_sio_priv_release);
@@ -1944,7 +1939,7 @@ static void ftdi_write_bulk_callback(struct urb *urb)
return;
}
/* account for transferred data */
- countback = urb->actual_length;
+ countback = urb->transfer_buffer_length;
data_offset = priv->write_offset;
if (data_offset > 0) {
/* Subtract the control bytes */
@@ -1957,7 +1952,6 @@ static void ftdi_write_bulk_callback(struct urb *urb)
if (status) {
dbg("nonzero write bulk status received: %d", status);
- return;
}
usb_serial_port_softint(port);
@@ -2008,271 +2002,121 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty)
return buffered;
}
-static void ftdi_read_bulk_callback(struct urb *urb)
+static int ftdi_process_packet(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ftdi_private *priv,
+ char *packet, int len)
{
- struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
- struct ftdi_private *priv;
- unsigned long countread;
- unsigned long flags;
- int status = urb->status;
-
- if (urb->number_of_packets > 0) {
- dev_err(&port->dev, "%s transfer_buffer_length %d "
- "actual_length %d number of packets %d\n", __func__,
- urb->transfer_buffer_length,
- urb->actual_length, urb->number_of_packets);
- dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
- urb->transfer_flags);
- }
+ int i;
+ char status;
+ char flag;
+ char *ch;
dbg("%s - port %d", __func__, port->number);
- if (port->port.count <= 0)
- return;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
- return;
+ if (len < 2) {
+ dbg("malformed packet");
+ return 0;
}
- priv = usb_get_serial_port_data(port);
- if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __func__);
- goto out;
+ /* Compare new line status to the old one, signal if different/
+ N.B. packet may be processed more than once, but differences
+ are only processed once. */
+ status = packet[0] & FTDI_STATUS_B0_MASK;
+ if (status != priv->prev_status) {
+ priv->diff_status |= status ^ priv->prev_status;
+ wake_up_interruptible(&priv->delta_msr_wait);
+ priv->prev_status = status;
}
- if (urb != port->read_urb)
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
-
- if (status) {
- /* This will happen at close every time so it is a dbg not an
- err */
- dbg("(this is ok on close) nonzero read bulk status received: %d", status);
- goto out;
+ /*
+ * Although the device uses a bitmask and hence can have multiple
+ * errors on a packet - the order here sets the priority the error is
+ * returned to the tty layer.
+ */
+ flag = TTY_NORMAL;
+ if (packet[1] & FTDI_RS_OE) {
+ flag = TTY_OVERRUN;
+ dbg("OVERRRUN error");
+ }
+ if (packet[1] & FTDI_RS_BI) {
+ flag = TTY_BREAK;
+ dbg("BREAK received");
+ usb_serial_handle_break(port);
+ }
+ if (packet[1] & FTDI_RS_PE) {
+ flag = TTY_PARITY;
+ dbg("PARITY error");
+ }
+ if (packet[1] & FTDI_RS_FE) {
+ flag = TTY_FRAME;
+ dbg("FRAMING error");
}
- /* count data bytes, but not status bytes */
- countread = urb->actual_length;
- countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_bytes += countread;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
-
- ftdi_process_read(&priv->rx_work.work);
-out:
- tty_kref_put(tty);
-} /* ftdi_read_bulk_callback */
-
+ len -= 2;
+ if (!len)
+ return 0; /* status only */
+ ch = packet + 2;
+
+ if (!(port->console && port->sysrq) && flag == TTY_NORMAL)
+ tty_insert_flip_string(tty, ch, len);
+ else {
+ for (i = 0; i < len; i++, ch++) {
+ if (!usb_serial_handle_sysrq_char(tty, port, *ch))
+ tty_insert_flip_char(tty, *ch, flag);
+ }
+ }
+ return len;
+}
-static void ftdi_process_read(struct work_struct *work)
-{ /* ftdi_process_read */
- struct ftdi_private *priv =
- container_of(work, struct ftdi_private, rx_work.work);
- struct usb_serial_port *port = priv->port;
- struct urb *urb;
+static void ftdi_process_read(struct usb_serial_port *port)
+{
+ struct urb *urb = port->read_urb;
struct tty_struct *tty;
- char error_flag;
- unsigned char *data;
-
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ char *data = (char *)urb->transfer_buffer;
int i;
- int result;
- int need_flip;
- int packet_offset;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
- if (port->port.count <= 0)
- return;
+ int len;
+ int count = 0;
tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
+ if (!tty)
return;
- }
- priv = usb_get_serial_port_data(port);
- if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __func__);
- goto out;
- }
-
- urb = port->read_urb;
- if (!urb) {
- dbg("%s - bad read_urb pointer - exiting", __func__);
- goto out;
+ for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
+ len = min_t(int, urb->actual_length - i, priv->max_packet_size);
+ count += ftdi_process_packet(tty, port, priv, &data[i], len);
}
- data = urb->transfer_buffer;
-
- if (priv->rx_processed) {
- dbg("%s - already processed: %d bytes, %d remain", __func__,
- priv->rx_processed,
- urb->actual_length - priv->rx_processed);
- } else {
- /* The first two bytes of every read packet are status */
- if (urb->actual_length > 2)
- usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length, data);
- else
- dbg("Status only: %03oo %03oo", data[0], data[1]);
- }
-
-
- /* TO DO -- check for hung up line and handle appropriately: */
- /* send hangup */
- /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */
- /* if CD is dropped and the line is not CLOCAL then we should hangup */
-
- need_flip = 0;
- for (packet_offset = priv->rx_processed;
- packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
- int length;
-
- /* Compare new line status to the old one, signal if different/
- N.B. packet may be processed more than once, but differences
- are only processed once. */
- char new_status = data[packet_offset + 0] &
- FTDI_STATUS_B0_MASK;
- if (new_status != priv->prev_status) {
- priv->diff_status |=
- new_status ^ priv->prev_status;
- wake_up_interruptible(&priv->delta_msr_wait);
- priv->prev_status = new_status;
- }
-
- length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
- if (length < 0) {
- dev_err(&port->dev, "%s - bad packet length: %d\n",
- __func__, length+2);
- length = 0;
- }
-
- if (priv->rx_flags & THROTTLED) {
- dbg("%s - throttled", __func__);
- break;
- }
- if (tty_buffer_request_room(tty, length) < length) {
- /* break out & wait for throttling/unthrottling to
- happen */
- dbg("%s - receive room low", __func__);
- break;
- }
-
- /* Handle errors and break */
- error_flag = TTY_NORMAL;
- /* Although the device uses a bitmask and hence can have
- multiple errors on a packet - the order here sets the
- priority the error is returned to the tty layer */
-
- if (data[packet_offset+1] & FTDI_RS_OE) {
- error_flag = TTY_OVERRUN;
- dbg("OVERRRUN error");
- }
- if (data[packet_offset+1] & FTDI_RS_BI) {
- error_flag = TTY_BREAK;
- dbg("BREAK received");
- usb_serial_handle_break(port);
- }
- if (data[packet_offset+1] & FTDI_RS_PE) {
- error_flag = TTY_PARITY;
- dbg("PARITY error");
- }
- if (data[packet_offset+1] & FTDI_RS_FE) {
- error_flag = TTY_FRAME;
- dbg("FRAMING error");
- }
- if (length > 0) {
- for (i = 2; i < length+2; i++) {
- /* Note that the error flag is duplicated for
- every character received since we don't know
- which character it applied to */
- if (!usb_serial_handle_sysrq_char(tty, port,
- data[packet_offset + i]))
- tty_insert_flip_char(tty,
- data[packet_offset + i],
- error_flag);
- }
- need_flip = 1;
- }
-
-#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
- /* if a parity error is detected you get status packets forever
- until a character is sent without a parity error.
- This doesn't work well since the application receives a
- never ending stream of bad data - even though new data
- hasn't been sent. Therefore I (bill) have taken this out.
- However - this might make sense for framing errors and so on
- so I am leaving the code in for now.
- */
- else {
- if (error_flag != TTY_NORMAL) {
- dbg("error_flag is not normal");
- /* In this case it is just status - if that is
- an error send a bad character */
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
- tty_insert_flip_char(tty, 0xff, error_flag);
- need_flip = 1;
- }
- }
-#endif
- } /* "for(packet_offset=0..." */
-
- /* Low latency */
- if (need_flip)
+ if (count)
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
- if (packet_offset < urb->actual_length) {
- /* not completely processed - record progress */
- priv->rx_processed = packet_offset;
- dbg("%s - incomplete, %d bytes processed, %d remain",
- __func__, packet_offset,
- urb->actual_length - packet_offset);
- /* check if we were throttled while processing */
- spin_lock_irqsave(&priv->rx_lock, flags);
- if (priv->rx_flags & THROTTLED) {
- priv->rx_flags |= ACTUALLY_THROTTLED;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- dbg("%s - deferring remainder until unthrottled",
- __func__);
- goto out;
- }
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- /* if the port is closed stop trying to read */
- if (port->port.count > 0)
- /* delay processing of remainder */
- schedule_delayed_work(&priv->rx_work, 1);
- else
- dbg("%s - port is closed", __func__);
- goto out;
- }
-
- /* urb is completely processed */
- priv->rx_processed = 0;
+static void ftdi_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned long flags;
- /* if the port is closed stop trying to read */
- if (port->port.count > 0) {
- /* Continue trying to always read */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ftdi_read_bulk_callback, port);
+ dbg("%s - port %d", __func__, port->number);
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __func__, urb->status);
+ return;
}
-out:
- tty_kref_put(tty);
-} /* ftdi_process_read */
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
+ ftdi_process_read(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttled = port->throttle_req;
+ if (!port->throttled) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ ftdi_submit_read_urb(port, GFP_ATOMIC);
+ } else
+ spin_unlock_irqrestore(&port->lock, flags);
+}
static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
{
@@ -2604,33 +2448,31 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
static void ftdi_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_flags |= THROTTLED;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttle_req = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
}
-
-static void ftdi_unthrottle(struct tty_struct *tty)
+void ftdi_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- int actually_throttled;
+ int was_throttled;
unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
- actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
- priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ was_throttled = port->throttled;
+ port->throttled = port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
- if (actually_throttled)
- schedule_delayed_work(&priv->rx_work, 0);
+ /* Resubmit urb if throttled and open. */
+ if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ftdi_submit_read_urb(port, GFP_KERNEL);
}
static int __init ftdi_init(void)
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 8c92b88166ae..6f31e0d71898 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -81,6 +81,9 @@
/* OpenDCC (www.opendcc.de) product id */
#define FTDI_OPENDCC_PID 0xBFD8
+#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
+#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
+#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
/* Sprog II (Andrew Crosland's SprogII DCC interface) */
#define FTDI_SPROG_II 0xF0C8
@@ -930,6 +933,7 @@
*/
#define ADI_VID 0x0456
#define ADI_GNICE_PID 0xF000
+#define ADI_GNICEPLUS_PID 0xF001
/*
* JETI SPECTROMETER SPECBOS 1201
@@ -968,6 +972,12 @@
#define MARVELL_OPENRD_PID 0x9e90
/*
+ * Hameg HO820 and HO870 interface (using VID 0x0403)
+ */
+#define HAMEG_HO820_PID 0xed74
+#define HAMEG_HO870_PID 0xed71
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index ce57f6a32bdf..6463fee644b9 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -480,6 +480,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
if (port->serial->type->max_in_flight_urbs) {
+ kfree(urb->transfer_buffer);
+
spin_lock_irqsave(&port->lock, flags);
--port->urbs_in_flight;
port->tx_bytes_flight -= urb->transfer_buffer_length;
@@ -530,7 +532,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
if (was_throttled) {
/* Resume reading from device */
- usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
+ flush_and_resubmit_read_urb(port);
}
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 2545d45ce16f..c4d02064e5f1 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -971,6 +971,15 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
static int ipaq_startup(struct usb_serial *serial)
{
dbg("%s", __func__);
+
+ /* Some of the devices in ipaq_id_table[] are composite, and we
+ * shouldn't bind to all the interfaces. This test will rule out
+ * some obviously invalid possibilities.
+ */
+ if (serial->num_bulk_in < serial->num_ports ||
+ serial->num_bulk_out < serial->num_ports)
+ return -ENODEV;
+
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
/*
* FIXME: HP iPaq rx3715, possibly others, have 1 config that
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 96873a7a32b0..af6df6c788b9 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -71,7 +71,6 @@ struct iuu_private {
spinlock_t lock; /* store irq state */
wait_queue_head_t delta_msr_wait;
u8 line_status;
- u8 termios_initialized;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
u8 reset; /* if 1 reset is needed */
int poll; /* number of poll */
@@ -1018,6 +1017,18 @@ static void iuu_close(struct usb_serial_port *port)
}
}
+static void iuu_init_termios(struct tty_struct *tty)
+{
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ | TIOCM_CTS | CSTOPB | PARENB;
+ tty->termios->c_ispeed = 9600;
+ tty->termios->c_ospeed = 9600;
+ tty->termios->c_lflag = 0;
+ tty->termios->c_oflag = 0;
+ tty->termios->c_iflag = 0;
+}
+
static int iuu_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
@@ -1025,7 +1036,6 @@ static int iuu_open(struct tty_struct *tty,
u8 *buf;
int result;
u32 actual;
- unsigned long flags;
struct iuu_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __func__, port->number);
@@ -1064,21 +1074,7 @@ static int iuu_open(struct tty_struct *tty,
port->bulk_in_buffer, 512,
NULL, NULL);
- /* set the termios structure */
- spin_lock_irqsave(&priv->lock, flags);
- if (tty && !priv->termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
- | TIOCM_CTS | CSTOPB | PARENB;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
- tty->termios->c_lflag = 0;
- tty->termios->c_oflag = 0;
- tty->termios->c_iflag = 0;
- priv->termios_initialized = 1;
- priv->poll = 0;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
+ priv->poll = 0;
/* initialize writebuf */
#define FISH(a, b, c, d) do { \
@@ -1201,6 +1197,7 @@ static struct usb_serial_driver iuu_device = {
.tiocmget = iuu_tiocmget,
.tiocmset = iuu_tiocmset,
.set_termios = iuu_set_termios,
+ .init_termios = iuu_init_termios,
.attach = iuu_startup,
.release = iuu_release,
};
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 6db0e561f680..46d47d1463c9 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -85,7 +85,7 @@ static void kobil_read_int_callback(struct urb *urb);
static void kobil_write_callback(struct urb *purb);
static void kobil_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
-
+static void kobil_init_termios(struct tty_struct *tty);
static struct usb_device_id id_table [] = {
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
@@ -120,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.release = kobil_release,
.ioctl = kobil_ioctl,
.set_termios = kobil_set_termios,
+ .init_termios = kobil_init_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@@ -210,6 +211,15 @@ static void kobil_release(struct usb_serial *serial)
kfree(usb_get_serial_port_data(serial->port[i]));
}
+static void kobil_init_termios(struct tty_struct *tty)
+{
+ /* Default to echo off and other sane device settings */
+ tty->termios->c_lflag = 0;
+ tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+ tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+ /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
+ tty->termios->c_oflag &= ~ONLCR;
+}
static int kobil_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
@@ -226,16 +236,6 @@ static int kobil_open(struct tty_struct *tty,
/* someone sets the dev to 0 if the close method has been called */
port->interrupt_in_urb->dev = port->serial->dev;
- if (tty) {
-
- /* Default to echo off and other sane device settings */
- tty->termios->c_lflag = 0;
- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN |
- XCASE);
- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
- /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
- tty->termios->c_oflag &= ~ONLCR;
- }
/* allocate memory for transfer buffer */
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (!transfer_buffer)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index c784ddbe7b61..c7b42ca00d56 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -166,6 +166,7 @@ static int option_resume(struct usb_serial *serial);
#define HUAWEI_PRODUCT_E143D 0x143D
#define HUAWEI_PRODUCT_E143E 0x143E
#define HUAWEI_PRODUCT_E143F 0x143F
+#define HUAWEI_PRODUCT_E14AC 0x14AC
#define QUANTA_VENDOR_ID 0x0408
#define QUANTA_PRODUCT_Q101 0xEA02
@@ -292,6 +293,7 @@ static int option_resume(struct usb_serial *serial);
#define TELIT_VENDOR_ID 0x1bc7
#define TELIT_PRODUCT_UC864E 0x1003
+#define TELIT_PRODUCT_UC864G 0x1004
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
@@ -300,12 +302,14 @@ static int option_resume(struct usb_serial *serial);
#define ZTE_PRODUCT_MF626 0x0031
#define ZTE_PRODUCT_CDMA_TECH 0xfffe
#define ZTE_PRODUCT_AC8710 0xfff1
+#define ZTE_PRODUCT_AC2726 0xfff5
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
#define DLINK_VENDOR_ID 0x1186
#define DLINK_PRODUCT_DWM_652 0x3e04
+#define DLINK_PRODUCT_DWM_652_U5 0xce16
#define QISDA_VENDOR_ID 0x1da5
#define QISDA_PRODUCT_H21_4512 0x4512
@@ -313,10 +317,14 @@ static int option_resume(struct usb_serial *serial);
#define QISDA_PRODUCT_H20_4515 0x4515
#define QISDA_PRODUCT_H20_4519 0x4519
+/* TLAYTECH PRODUCTS */
+#define TLAYTECH_VENDOR_ID 0x20B9
+#define TLAYTECH_PRODUCT_TEU800 0x1682
/* TOSHIBA PRODUCTS */
#define TOSHIBA_VENDOR_ID 0x0930
#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302
+#define TOSHIBA_PRODUCT_G450 0x0d45
#define ALINK_VENDOR_ID 0x1e0e
#define ALINK_PRODUCT_3GU 0x9200
@@ -325,6 +333,13 @@ static int option_resume(struct usb_serial *serial);
#define ALCATEL_VENDOR_ID 0x1bbb
#define ALCATEL_PRODUCT_X060S 0x0000
+/* Airplus products */
+#define AIRPLUS_VENDOR_ID 0x1011
+#define AIRPLUS_PRODUCT_MCD650 0x3198
+
+/* Haier products */
+#define HAIER_VENDOR_ID 0x201e
+#define HAIER_PRODUCT_CE100 0x2009
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -423,6 +438,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */
@@ -503,6 +519,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
@@ -564,24 +581,67 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0145, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0146, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0148, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0149, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0150, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0154, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
+ { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
+ { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
+ { USB_DEVICE(ALINK_VENDOR_ID, 0xce16) },
{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
+ { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
+ { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
+ { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 3cece27325e7..ef34cffabdf8 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -146,6 +146,7 @@ static int oti6858_open(struct tty_struct *tty,
static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
+static void oti6858_init_termios(struct tty_struct *tty);
static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
static void oti6858_read_int_callback(struct urb *urb);
@@ -186,6 +187,7 @@ static struct usb_serial_driver oti6858_device = {
.write = oti6858_write,
.ioctl = oti6858_ioctl,
.set_termios = oti6858_set_termios,
+ .init_termios = oti6858_init_termios,
.tiocmget = oti6858_tiocmget,
.tiocmset = oti6858_tiocmset,
.read_bulk_callback = oti6858_read_bulk_callback,
@@ -206,7 +208,6 @@ struct oti6858_private {
struct {
u8 read_urb_in_use;
u8 write_urb_in_use;
- u8 termios_initialized;
} flags;
struct delayed_work delayed_write_work;
@@ -447,6 +448,14 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
return chars;
}
+static void oti6858_init_termios(struct tty_struct *tty)
+{
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios->c_ispeed = 38400;
+ tty->termios->c_ospeed = 38400;
+}
+
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -464,16 +473,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
return;
}
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->flags.termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 38400;
- tty->termios->c_ospeed = 38400;
- priv->flags.termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
cflag = tty->termios->c_cflag;
spin_lock_irqsave(&priv->lock, flags);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3e86815b2705..600097de714f 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -96,6 +96,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
+ { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -994,13 +995,15 @@ static void pl2303_push_data(struct tty_struct *tty,
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- if (port->console && port->sysrq) {
+
+ if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ else {
int i;
for (i = 0; i < urb->actual_length; ++i)
if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
tty_insert_flip_char(tty, data[i], tty_flag);
- } else
- tty_insert_flip_string(tty, data, urb->actual_length);
+ }
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index ee9505e1dd92..d640dc951568 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -130,3 +130,7 @@
/* Sony, USB data cable for CMD-Jxx mobile phones */
#define SONY_VENDOR_ID 0x054c
#define SONY_QN3USB_PRODUCT_ID 0x0437
+
+/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
+#define SANWA_VENDOR_ID 0x11ad
+#define SANWA_PRODUCT_ID 0x0001
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index f48d05e0acc1..c5fbaa5dde05 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -287,6 +287,8 @@ static int sierra_send_setup(struct usb_serial_port *port)
struct sierra_port_private *portdata;
__u16 interface = 0;
int val = 0;
+ int do_send = 0;
+ int retval;
dev_dbg(&port->dev, "%s\n", __func__);
@@ -305,10 +307,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
*/
if (port->interrupt_in_urb) {
/* send control message */
- return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22, 0x21, val, interface,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
+ do_send = 1;
}
}
@@ -320,12 +319,18 @@ static int sierra_send_setup(struct usb_serial_port *port)
interface = 1;
else if (port->bulk_out_endpointAddress == 5)
interface = 2;
- return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22, 0x21, val, interface,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+ do_send = 1;
}
- return 0;
+ if (!do_send)
+ return 0;
+
+ usb_autopm_get_interface(serial->interface);
+ retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ usb_autopm_put_interface(serial->interface);
+
+ return retval;
}
static void sierra_set_termios(struct tty_struct *tty,
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 3c249d8e8b8e..993a6d5a1b7a 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -299,7 +299,6 @@ struct spcp8x5_private {
wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
- u8 termios_initialized;
};
/* desc : when device plug in,this function would be called.
@@ -498,6 +497,15 @@ static void spcp8x5_close(struct usb_serial_port *port)
dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
}
+static void spcp8x5_init_termios(struct tty_struct *tty)
+{
+ /* for the 1st time call this function */
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios->c_ispeed = 115200;
+ tty->termios->c_ospeed = 115200;
+}
+
/* set the serial param for transfer. we should check if we really need to
* transfer. if we set flow control we should do this too. */
static void spcp8x5_set_termios(struct tty_struct *tty,
@@ -514,16 +522,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
int i;
u8 control;
- /* for the 1st time call this function */
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 115200;
- tty->termios->c_ospeed = 115200;
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
/* check that they really want us to change something */
if (!tty_termios_hw_change(tty->termios, old_termios))
@@ -1011,6 +1009,7 @@ static struct usb_serial_driver spcp8x5_device = {
.carrier_raised = spcp8x5_carrier_raised,
.write = spcp8x5_write,
.set_termios = spcp8x5_set_termios,
+ .init_termios = spcp8x5_init_termios,
.ioctl = spcp8x5_ioctl,
.tiocmget = spcp8x5_tiocmget,
.tiocmset = spcp8x5_tiocmset,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 99188c92068b..3292e0391e28 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -43,8 +43,6 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
-static void port_free(struct usb_serial_port *port);
-
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
@@ -68,6 +66,11 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
+/*
+ * Look up the serial structure. If it is found and it hasn't been
+ * disconnected, return with its disc_mutex held and its refcount
+ * incremented. Otherwise return NULL.
+ */
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial;
@@ -75,8 +78,15 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
mutex_lock(&table_lock);
serial = serial_table[index];
- if (serial)
- kref_get(&serial->kref);
+ if (serial) {
+ mutex_lock(&serial->disc_mutex);
+ if (serial->disconnected) {
+ mutex_unlock(&serial->disc_mutex);
+ serial = NULL;
+ } else {
+ kref_get(&serial->kref);
+ }
+ }
mutex_unlock(&table_lock);
return serial;
}
@@ -125,8 +135,10 @@ static void return_serial(struct usb_serial *serial)
dbg("%s", __func__);
+ mutex_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i)
serial_table[serial->minor + i] = NULL;
+ mutex_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -143,163 +155,160 @@ static void destroy_serial(struct kref *kref)
if (serial->minor != SERIAL_TTY_NO_MINOR)
return_serial(serial);
- serial->type->release(serial);
+ if (serial->attached)
+ serial->type->release(serial);
- for (i = 0; i < serial->num_ports; ++i) {
+ /* Now that nothing is using the ports, they can be freed */
+ for (i = 0; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
- if (port)
+ if (port) {
+ port->serial = NULL;
put_device(&port->dev);
- }
-
- /* If this is a "fake" port, we have to clean it up here, as it will
- * not get cleaned up in port_release() as it was never registered with
- * the driver core */
- if (serial->num_ports < serial->num_port_pointers) {
- for (i = serial->num_ports;
- i < serial->num_port_pointers; ++i) {
- port = serial->port[i];
- if (port)
- port_free(port);
}
}
usb_put_dev(serial->dev);
-
- /* free up any memory that we allocated */
kfree(serial);
}
void usb_serial_put(struct usb_serial *serial)
{
- mutex_lock(&table_lock);
kref_put(&serial->kref, destroy_serial);
- mutex_unlock(&table_lock);
}
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
-static int serial_open (struct tty_struct *tty, struct file *filp)
+
+/**
+ * serial_install - install tty
+ * @driver: the driver (USB in our case)
+ * @tty: the tty being created
+ *
+ * Create the termios objects for this tty. We use the default
+ * USB serial settings but permit them to be overridden by
+ * serial->type->init_termios.
+ *
+ * This is the first place a new tty gets used. Hence this is where we
+ * acquire references to the usb_serial structure and the driver module,
+ * where we store a pointer to the port, and where we do an autoresume.
+ * All these actions are reversed in serial_release().
+ */
+static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
{
+ int idx = tty->index;
struct usb_serial *serial;
struct usb_serial_port *port;
- unsigned int portNumber;
- int retval = 0;
- int first = 0;
+ int retval = -ENODEV;
dbg("%s", __func__);
- /* get the serial object associated with this tty pointer */
- serial = usb_serial_get_by_index(tty->index);
- if (!serial) {
- tty->driver_data = NULL;
- return -ENODEV;
- }
+ serial = usb_serial_get_by_index(idx);
+ if (!serial)
+ return retval;
- mutex_lock(&serial->disc_mutex);
- portNumber = tty->index - serial->minor;
- port = serial->port[portNumber];
- if (!port || serial->disconnected)
- retval = -ENODEV;
- else
- get_device(&port->dev);
- /*
- * Note: Our locking order requirement does not allow port->mutex
- * to be acquired while serial->disc_mutex is held.
- */
- mutex_unlock(&serial->disc_mutex);
+ port = serial->port[idx - serial->minor];
+ if (!port)
+ goto error_no_port;
+ if (!try_module_get(serial->type->driver.owner))
+ goto error_module_get;
+
+ /* perform the standard setup */
+ retval = tty_init_termios(tty);
if (retval)
- goto bailout_serial_put;
+ goto error_init_termios;
- if (mutex_lock_interruptible(&port->mutex)) {
- retval = -ERESTARTSYS;
- goto bailout_port_put;
- }
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto error_get_interface;
+
+ mutex_unlock(&serial->disc_mutex);
- ++port->port.count;
+ /* allow the driver to update the settings */
+ if (serial->type->init_termios)
+ serial->type->init_termios(tty);
- /* set up our port structure making the tty driver
- * remember our port object, and us it */
tty->driver_data = port;
- tty_port_tty_set(&port->port, tty);
- /* If the console is attached, the device is already open */
- if (port->port.count == 1 && !port->console) {
- first = 1;
- /* lock this module before we call it
- * this may fail, which means we must bail out,
- * safe because we are called with BKL held */
- if (!try_module_get(serial->type->driver.owner)) {
- retval = -ENODEV;
- goto bailout_mutex_unlock;
- }
+ /* Final install (we use the default method) */
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+ return retval;
+ error_get_interface:
+ error_init_termios:
+ module_put(serial->type->driver.owner);
+ error_module_get:
+ error_no_port:
+ usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
+ return retval;
+}
+
+static int serial_open(struct tty_struct *tty, struct file *filp)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ int retval;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irq(&port->port.lock);
+ if (!tty_hung_up_p(filp))
+ ++port->port.count;
+ spin_unlock_irq(&port->port.lock);
+ tty_port_tty_set(&port->port, tty);
+
+ /* Do the device-specific open only if the hardware isn't
+ * already initialized.
+ */
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+ if (mutex_lock_interruptible(&port->mutex))
+ return -ERESTARTSYS;
mutex_lock(&serial->disc_mutex);
if (serial->disconnected)
retval = -ENODEV;
else
- retval = usb_autopm_get_interface(serial->interface);
- if (retval)
- goto bailout_module_put;
-
- /* only call the device specific open if this
- * is the first time the port is opened */
- retval = serial->type->open(tty, port, filp);
- if (retval)
- goto bailout_interface_put;
+ retval = port->serial->type->open(tty, port, filp);
mutex_unlock(&serial->disc_mutex);
+ mutex_unlock(&port->mutex);
+ if (retval)
+ return retval;
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
- mutex_unlock(&port->mutex);
+
/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
- if (retval == 0) {
- if (!first)
- usb_serial_put(serial);
- return 0;
- }
- mutex_lock(&port->mutex);
- if (first == 0)
- goto bailout_mutex_unlock;
- /* Undo the initial port actions */
- mutex_lock(&serial->disc_mutex);
-bailout_interface_put:
- usb_autopm_put_interface(serial->interface);
-bailout_module_put:
- mutex_unlock(&serial->disc_mutex);
- module_put(serial->type->driver.owner);
-bailout_mutex_unlock:
- port->port.count = 0;
- tty->driver_data = NULL;
- tty_port_tty_set(&port->port, NULL);
- mutex_unlock(&port->mutex);
-bailout_port_put:
- put_device(&port->dev);
-bailout_serial_put:
- usb_serial_put(serial);
return retval;
}
/**
- * serial_do_down - shut down hardware
- * @port: port to shut down
- *
- * Shut down a USB port unless it is the console. We never shut down the
- * console hardware as it will always be in use.
+ * serial_down - shut down hardware
+ * @port: port to shut down
*
- * Don't free any resources at this point
+ * Shut down a USB serial port unless it is the console. We never
+ * shut down the console hardware as it will always be in use.
*/
-static void serial_do_down(struct usb_serial_port *port)
+static void serial_down(struct usb_serial_port *port)
{
struct usb_serial_driver *drv = port->serial->type;
struct usb_serial *serial;
struct module *owner;
- /* The console is magical, do not hang up the console hardware
- or there will be tears */
+ /*
+ * The console is magical. Do not hang up the console hardware
+ * or there will be tears.
+ */
if (port->console)
return;
+ /* Don't call the close method if the hardware hasn't been
+ * initialized.
+ */
+ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ return;
+
mutex_lock(&port->mutex);
serial = port->serial;
owner = serial->type->driver.owner;
@@ -310,79 +319,69 @@ static void serial_do_down(struct usb_serial_port *port)
mutex_unlock(&port->mutex);
}
-/**
- * serial_do_free - free resources post close/hangup
- * @port: port to free up
- *
- * Do the resource freeing and refcount dropping for the port. We must
- * be careful about ordering and we must avoid freeing up the console.
- */
-
-static void serial_do_free(struct usb_serial_port *port)
+static void serial_hangup(struct tty_struct *tty)
{
- struct usb_serial *serial;
- struct module *owner;
+ struct usb_serial_port *port = tty->driver_data;
- /* The console is magical, do not hang up the console hardware
- or there will be tears */
- if (port->console)
- return;
+ dbg("%s - port %d", __func__, port->number);
- serial = port->serial;
- owner = serial->type->driver.owner;
- put_device(&port->dev);
- /* Mustn't dereference port any more */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- usb_autopm_put_interface(serial->interface);
- mutex_unlock(&serial->disc_mutex);
- usb_serial_put(serial);
- /* Mustn't dereference serial any more */
- module_put(owner);
+ serial_down(port);
+ tty_port_hangup(&port->port);
}
static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- /* FIXME:
- This leaves a very narrow race. Really we should do the
- serial_do_free() on tty->shutdown(), but tty->shutdown can
- be called from IRQ context and serial_do_free can sleep.
-
- The right fix is probably to make the tty free (which is rare)
- and thus tty->shutdown() occur via a work queue and simplify all
- the drivers that use it.
- */
- if (tty_hung_up_p(filp)) {
- /* serial_hangup already called serial_down at this point.
- Another user may have already reopened the port but
- serial_do_free is refcounted */
- serial_do_free(port);
+ if (tty_hung_up_p(filp))
return;
- }
-
if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
-
- serial_do_down(port);
+ serial_down(port);
tty_port_close_end(&port->port, tty);
tty_port_tty_set(&port->port, NULL);
- serial_do_free(port);
}
-static void serial_hangup(struct tty_struct *tty)
+/**
+ * serial_release - free resources post close/hangup
+ * @port: port to free up
+ *
+ * Do the resource freeing and refcount dropping for the port.
+ * Avoid freeing the console.
+ *
+ * Called when the last tty kref is dropped.
+ */
+static void serial_release(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- serial_do_down(port);
- tty_port_hangup(&port->port);
- /* We must not free port yet - the USB serial layer depends on it's
- continued existence */
+ struct usb_serial *serial;
+ struct module *owner;
+
+ /* The console is magical. Do not hang up the console hardware
+ * or there will be tears.
+ */
+ if (port->console)
+ return;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ /* Standard shutdown processing */
+ tty_shutdown(tty);
+
+ tty->driver_data = NULL;
+
+ serial = port->serial;
+ owner = serial->type->driver.owner;
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ usb_autopm_put_interface(serial->interface);
+ mutex_unlock(&serial->disc_mutex);
+
+ usb_serial_put(serial);
+ module_put(owner);
}
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@@ -527,6 +526,7 @@ static int serial_proc_show(struct seq_file *m, void *v)
seq_putc(m, '\n');
usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
}
return 0;
}
@@ -596,14 +596,6 @@ static void usb_serial_port_work(struct work_struct *work)
tty_kref_put(tty);
}
-static void port_release(struct device *dev)
-{
- struct usb_serial_port *port = to_usb_serial_port(dev);
-
- dbg ("%s - %s", __func__, dev_name(dev));
- port_free(port);
-}
-
static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
@@ -623,8 +615,12 @@ static void kill_traffic(struct usb_serial_port *port)
usb_kill_urb(port->interrupt_out_urb);
}
-static void port_free(struct usb_serial_port *port)
+static void port_release(struct device *dev)
{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+
+ dbg ("%s - %s", __func__, dev_name(dev));
+
/*
* Stop all the traffic before cancelling the work, so that
* nobody will restart it by calling usb_serial_port_softint.
@@ -935,6 +931,11 @@ int usb_serial_probe(struct usb_interface *interface,
mutex_init(&port->mutex);
INIT_WORK(&port->work, usb_serial_port_work);
serial->port[i] = port;
+ port->dev.parent = &interface->dev;
+ port->dev.driver = NULL;
+ port->dev.bus = &usb_serial_bus_type;
+ port->dev.release = &port_release;
+ device_initialize(&port->dev);
}
/* set up the endpoint information */
@@ -1060,12 +1061,15 @@ int usb_serial_probe(struct usb_interface *interface,
module_put(type->driver.owner);
if (retval < 0)
goto probe_error;
+ serial->attached = 1;
if (retval > 0) {
/* quietly accept this device, but don't bind to a
serial port as it's about to disappear */
serial->num_ports = 0;
goto exit;
}
+ } else {
+ serial->attached = 1;
}
if (get_free_serial(serial, num_ports, &minor) == NULL) {
@@ -1077,15 +1081,10 @@ int usb_serial_probe(struct usb_interface *interface,
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
- port->dev.parent = &interface->dev;
- port->dev.driver = NULL;
- port->dev.bus = &usb_serial_bus_type;
- port->dev.release = &port_release;
-
dev_set_name(&port->dev, "ttyUSB%d", port->number);
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
port->dev_state = PORT_REGISTERING;
- retval = device_register(&port->dev);
+ retval = device_add(&port->dev);
if (retval) {
dev_err(&port->dev, "Error registering port device, "
"continuing\n");
@@ -1103,39 +1102,7 @@ exit:
return 0;
probe_error:
- for (i = 0; i < num_bulk_in; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->read_urb);
- kfree(port->bulk_in_buffer);
- }
- for (i = 0; i < num_bulk_out; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->write_urb);
- kfree(port->bulk_out_buffer);
- }
- for (i = 0; i < num_interrupt_in; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->interrupt_in_urb);
- kfree(port->interrupt_in_buffer);
- }
- for (i = 0; i < num_interrupt_out; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->interrupt_out_urb);
- kfree(port->interrupt_out_buffer);
- }
-
- /* free up any memory that we allocated */
- for (i = 0; i < serial->num_port_pointers; ++i)
- kfree(serial->port[i]);
- kfree(serial);
+ usb_serial_put(serial);
return -EIO;
}
EXPORT_SYMBOL_GPL(usb_serial_probe);
@@ -1161,10 +1128,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (port) {
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) {
- /* The hangup will occur asynchronously but
- the object refcounts will sort out all the
- cleanup */
- tty_hangup(tty);
+ tty_vhangup(tty);
tty_kref_put(tty);
}
kill_traffic(port);
@@ -1189,8 +1153,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
}
serial->type->disconnect(serial);
- /* let the last holder of this object
- * cause it to be cleaned up */
+ /* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
@@ -1246,6 +1209,8 @@ static const struct tty_operations serial_ops = {
.chars_in_buffer = serial_chars_in_buffer,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
+ .shutdown = serial_release,
+ .install = serial_install,
.proc_fops = &serial_proc_fops,
};
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 8d126dd7a02e..f7232b1bce51 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -259,7 +259,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,
__u8 *data, __u8 datasize);
static int firm_open(struct usb_serial_port *port);
static int firm_close(struct usb_serial_port *port);
-static int firm_setup_port(struct tty_struct *tty);
+static void firm_setup_port(struct tty_struct *tty);
static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
@@ -1211,7 +1211,7 @@ static int firm_close(struct usb_serial_port *port)
}
-static int firm_setup_port(struct tty_struct *tty)
+static void firm_setup_port(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_port_settings port_settings;
@@ -1286,7 +1286,7 @@ static int firm_setup_port(struct tty_struct *tty)
port_settings.lloop = 0;
/* now send the message to the device */
- return firm_send_command(port, WHITEHEAT_SETUP_PORT,
+ firm_send_command(port, WHITEHEAT_SETUP_PORT,
(__u8 *)&port_settings, sizeof(port_settings));
}
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index ec17c96371af..105d900150c1 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -102,5 +102,5 @@ int usb_stor_huawei_e220_init(struct us_data *us)
USB_TYPE_STANDARD | USB_RECIP_DEVICE,
0x01, 0x0, NULL, 0x0, 1000);
US_DEBUGP("Huawei mode set result is %d\n", result);
- return (result ? 0 : -ENODEV);
+ return 0;
}
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 380233bd6a39..80e65f29921c 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -163,7 +163,7 @@ static void usb_onetouch_pm_hook(struct us_data *us, int action)
usb_kill_urb(onetouch->irq);
break;
case US_RESUME:
- if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0)
+ if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
dev_err(&onetouch->irq->dev->dev,
"usb_submit_urb failed\n");
break;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index e20dc525d177..cc313d16d727 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -666,10 +666,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* to wait for at least one CHECK_CONDITION to determine
* SANE_SENSE support
*/
- if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
+ if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
result == USB_STOR_TRANSPORT_GOOD &&
!(us->fflags & US_FL_SANE_SENSE) &&
- !(srb->cmnd[2] & 0x20)) {
+ !(us->fflags & US_FL_BAD_SENSE) &&
+ !(srb->cmnd[2] & 0x20))) {
US_DEBUGP("-- SAT supported, increasing auto-sense\n");
us->fflags |= US_FL_SANE_SENSE;
}
@@ -696,7 +697,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* device supports and needs bigger sense buffer */
if (us->fflags & US_FL_SANE_SENSE)
sense_size = ~0;
-
+Retry_Sense:
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
@@ -718,8 +719,30 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
US_DEBUGP("-- auto-sense aborted\n");
srb->result = DID_ABORT << 16;
+
+ /* If SANE_SENSE caused this problem, disable it */
+ if (sense_size != US_SENSE_SIZE) {
+ us->fflags &= ~US_FL_SANE_SENSE;
+ us->fflags |= US_FL_BAD_SENSE;
+ }
goto Handle_Errors;
}
+
+ /* Some devices claim to support larger sense but fail when
+ * trying to request it. When a transport failure happens
+ * using US_FS_SANE_SENSE, we always retry with a standard
+ * (small) sense request. This fixes some USB GSM modems
+ */
+ if (temp_result == USB_STOR_TRANSPORT_FAILED &&
+ sense_size != US_SENSE_SIZE) {
+ US_DEBUGP("-- auto-sense failure, retry small sense\n");
+ sense_size = US_SENSE_SIZE;
+ us->fflags &= ~US_FL_SANE_SENSE;
+ us->fflags |= US_FL_BAD_SENSE;
+ goto Retry_Sense;
+ }
+
+ /* Other failures */
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n");
@@ -739,6 +762,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) &&
!(us->fflags & US_FL_SANE_SENSE) &&
+ !(us->fflags & US_FL_BAD_SENSE) &&
(srb->sense_buffer[0] & 0x7C) == 0x70) {
US_DEBUGP("-- SANE_SENSE support enabled\n");
us->fflags |= US_FL_SANE_SENSE;
@@ -768,17 +792,32 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
- /* If things are really okay, then let's show that. Zero
- * out the sense buffer so the higher layers won't realize
- * we did an unsolicited auto-sense. */
- if (result == USB_STOR_TRANSPORT_GOOD &&
- /* Filemark 0, ignore EOM, ILI 0, no sense */
+ /* We often get empty sense data. This could indicate that
+ * everything worked or that there was an unspecified
+ * problem. We have to decide which.
+ */
+ if ( /* Filemark 0, ignore EOM, ILI 0, no sense */
(srb->sense_buffer[2] & 0xaf) == 0 &&
/* No ASC or ASCQ */
srb->sense_buffer[12] == 0 &&
srb->sense_buffer[13] == 0) {
- srb->result = SAM_STAT_GOOD;
- srb->sense_buffer[0] = 0x0;
+
+ /* If things are really okay, then let's show that.
+ * Zero out the sense buffer so the higher layers
+ * won't realize we did an unsolicited auto-sense.
+ */
+ if (result == USB_STOR_TRANSPORT_GOOD) {
+ srb->result = SAM_STAT_GOOD;
+ srb->sense_buffer[0] = 0x0;
+
+ /* If there was a problem, report an unspecified
+ * hardware error to prevent the higher layers from
+ * entering an infinite retry loop.
+ */
+ } else {
+ srb->result = DID_ERROR << 16;
+ srb->sense_buffer[2] = HARDWARE_ERROR;
+ }
}
}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 7477d411959f..5ef11f435330 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -838,6 +838,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Daniel Kukula <daniel.kuku@gmail.com> */
+UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100,
+ "Prolific Technology, Inc.",
+ "Prolific Storage Gadget",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_BAD_SENSE ),
+
/* Reported by Rogerio Brito <rbrito@ime.usp.br> */
UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001,
"Prolific Technology, Inc.",
@@ -1820,13 +1827,6 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW ),
-/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
-UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
- "INTOVA",
- "Pixtreme",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Frederic Marchal <frederic.marchal@wowcompany.com>
* Mio Moov 330
*/
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 11dd37de45c7..f3ba49f62408 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -228,6 +228,7 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data,
if (data_len<36) // You lose.
return;
+ memset(data+8, ' ', 28);
if(data[0]&0x20) { /* USB device currently not connected. Return
peripheral qualifier 001b ("...however, the
physical device is not currently connected
@@ -237,15 +238,15 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data,
device, it may return zeros or ASCII spaces
(20h) in those fields until the data is
available from the device."). */
- memset(data+8,0,28);
} else {
u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
- memcpy(data+8, us->unusual_dev->vendorName,
- strlen(us->unusual_dev->vendorName) > 8 ? 8 :
- strlen(us->unusual_dev->vendorName));
- memcpy(data+16, us->unusual_dev->productName,
- strlen(us->unusual_dev->productName) > 16 ? 16 :
- strlen(us->unusual_dev->productName));
+ int n;
+
+ n = strlen(us->unusual_dev->vendorName);
+ memcpy(data+8, us->unusual_dev->vendorName, min(8, n));
+ n = strlen(us->unusual_dev->productName);
+ memcpy(data+16, us->unusual_dev->productName, min(16, n));
+
data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
@@ -432,7 +433,8 @@ static void adjust_quirks(struct us_data *us)
u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
unsigned f = 0;
- unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY |
+ unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE |
+ US_FL_FIX_CAPACITY |
US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
@@ -462,6 +464,9 @@ static void adjust_quirks(struct us_data *us)
case 'a':
f |= US_FL_SANE_SENSE;
break;
+ case 'b':
+ f |= US_FL_BAD_SENSE;
+ break;
case 'c':
f |= US_FL_FIX_CAPACITY;
break;