diff options
author | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-14 16:41:03 -0500 |
---|---|---|
committer | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-14 16:41:03 -0500 |
commit | 8a83780a187ba1961380814eaf9c503043345d12 (patch) | |
tree | 80f5d89cca49330e137688c72fb10c9f42dc5663 /drivers/usb | |
parent | 14a4057959f8ee0a2249eb2abd64fd6b1f571d98 (diff) |
Digi Release Code from del-5.6/main2.6.31-digi-201102141643
Diffstat (limited to 'drivers/usb')
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; |