diff --git a/kernel/drivers/usb/Kconfig b/kernel/drivers/usb/Kconfig index c4e4fdf7..43bc972e 100644 --- a/kernel/drivers/usb/Kconfig +++ b/kernel/drivers/usb/Kconfig @@ -49,7 +49,8 @@ config USB_ARCH_HAS_OHCI default y if CPU_SUBTYPE_SH7721 default y if CPU_SUBTYPE_SH7763 default y if CPU_SUBTYPE_SH7786 - default y if CPU_SUBTYPE_FLI7510 + default y if CPU_SUBTYPE_FLI75XX + default y if CPU_SUBTYPE_STXH205 default y if CPU_SUBTYPE_STX5197 default y if CPU_SUBTYPE_STX5206 default y if CPU_SUBTYPE_STX7100 @@ -69,7 +70,8 @@ config USB_ARCH_HAS_EHCI default y if ARCH_IXP4XX default y if ARCH_W90X900 default y if ARCH_AT91SAM9G45 - default y if CPU_SUBTYPE_FLI7510 + default y if CPU_SUBTYPE_FLI75XX + default y if CPU_SUBTYPE_STXH205 default y if CPU_SUBTYPE_STX5197 default y if CPU_SUBTYPE_STX5206 default y if CPU_SUBTYPE_STX7100 diff --git a/kernel/drivers/usb/class/cdc-acm.c b/kernel/drivers/usb/class/cdc-acm.c index 2fc5dd3a..8ad9dfb7 100644 --- a/kernel/drivers/usb/class/cdc-acm.c +++ b/kernel/drivers/usb/class/cdc-acm.c @@ -1120,7 +1120,8 @@ skip_normal_probe: } - if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) + if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 || + control_interface->cur_altsetting->desc.bNumEndpoints == 0) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; @@ -1264,6 +1265,8 @@ made_compressed_probe: i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); + acm->country_codes = NULL; + acm->country_code_size = 0; goto skip_countries; } @@ -1272,6 +1275,8 @@ made_compressed_probe: if (i < 0) { device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); + acm->country_codes = NULL; + acm->country_code_size = 0; goto skip_countries; } } @@ -1528,6 +1533,16 @@ static struct usb_device_id acm_ids[] = { }, { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ }, + /* Motorola H24 HSPA module: */ + { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ + { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ + { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ + { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ + { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ + { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ + { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on data interface instead of @@ -1606,6 +1621,9 @@ static struct usb_device_id acm_ids[] = { { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ + /* Support for Owen devices */ + { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ + /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ /* control interfaces without any protocol set */ diff --git a/kernel/drivers/usb/class/cdc-wdm.c b/kernel/drivers/usb/class/cdc-wdm.c index 3e564bfe..01ae5191 100644 --- a/kernel/drivers/usb/class/cdc-wdm.c +++ b/kernel/drivers/usb/class/cdc-wdm.c @@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_READ 4 #define WDM_INT_STALL 5 #define WDM_POLL_RUNNING 6 +#define WDM_OVERFLOW 10 #define WDM_MAX 16 @@ -115,6 +116,7 @@ static void wdm_in_callback(struct urb *urb) { struct wdm_device *desc = urb->context; int status = urb->status; + int length = urb->actual_length; spin_lock(&desc->iuspin); @@ -144,9 +146,17 @@ static void wdm_in_callback(struct urb *urb) } desc->rerr = status; - desc->reslength = urb->actual_length; - memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); - desc->length += desc->reslength; + if (length + desc->length > desc->wMaxCommand) { + /* The buffer would overflow */ + set_bit(WDM_OVERFLOW, &desc->flags); + } else { + /* we may already be in overflow */ + if (!test_bit(WDM_OVERFLOW, &desc->flags)) { + memmove(desc->ubuf + desc->length, desc->inbuf, length); + desc->length += length; + desc->reslength = length; + } + } wake_up(&desc->wait); set_bit(WDM_READ, &desc->flags); @@ -277,7 +287,7 @@ static void cleanup(struct wdm_device *desc) desc->sbuf, desc->validity->transfer_dma); usb_buffer_free(interface_to_usbdev(desc->intf), - desc->wMaxCommand, + desc->bMaxPacketSize0, desc->inbuf, desc->response->transfer_dma); kfree(desc->orq); @@ -314,7 +324,7 @@ static ssize_t wdm_write if (r < 0) goto outnp; - if (!file->f_flags && O_NONBLOCK) + if (!(file->f_flags & O_NONBLOCK)) r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); else @@ -398,6 +408,11 @@ retry: rv = -ENODEV; goto err; } + if (test_bit(WDM_OVERFLOW, &desc->flags)) { + clear_bit(WDM_OVERFLOW, &desc->flags); + rv = -ENOBUFS; + goto err; + } i++; if (file->f_flags & O_NONBLOCK) { if (!test_bit(WDM_READ, &desc->flags)) { @@ -440,7 +455,10 @@ retry: spin_unlock_irq(&desc->iuspin); goto retry; } + if (!desc->reslength) { /* zero length read */ + dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); + clear_bit(WDM_READ, &desc->flags); spin_unlock_irq(&desc->iuspin); goto retry; } @@ -458,7 +476,9 @@ retry: for (i = 0; i < desc->length - cntr; i++) desc->ubuf[i] = desc->ubuf[i + cntr]; + spin_lock_irq(&desc->iuspin); desc->length -= cntr; + spin_unlock_irq(&desc->iuspin); /* in case we had outstanding data */ if (!desc->length) clear_bit(WDM_READ, &desc->flags); @@ -840,6 +860,7 @@ static int wdm_post_reset(struct usb_interface *intf) struct wdm_device *desc = usb_get_intfdata(intf); int rv; + clear_bit(WDM_OVERFLOW, &desc->flags); rv = recover_from_urb_loss(desc); mutex_unlock(&desc->plock); return 0; diff --git a/kernel/drivers/usb/class/usbtmc.c b/kernel/drivers/usb/class/usbtmc.c index d9461c91..ae1ffbc6 100644 --- a/kernel/drivers/usb/class/usbtmc.c +++ b/kernel/drivers/usb/class/usbtmc.c @@ -267,7 +267,7 @@ usbtmc_abort_bulk_in_status: dev_err(dev, "usb_bulk_msg returned %d\n", rv); goto exit; } - } while ((actual = max_size) && + } while ((actual == max_size) && (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); if (actual == max_size) { diff --git a/kernel/drivers/usb/core/devio.c b/kernel/drivers/usb/core/devio.c index 582aa87c..48742ffe 100644 --- a/kernel/drivers/usb/core/devio.c +++ b/kernel/drivers/usb/core/devio.c @@ -403,7 +403,7 @@ static void async_completed(struct urb *urb) sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; - pid = as->pid; + pid = get_pid(as->pid); uid = as->uid; euid = as->euid; secid = as->secid; @@ -416,9 +416,11 @@ static void async_completed(struct urb *urb) cancel_bulk_urbs(ps, as->bulk_addr); spin_unlock(&ps->lock); - if (signr) + if (signr) { kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, euid, secid); + put_pid(pid); + } wake_up(&ps->wait); } @@ -1452,10 +1454,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; - if (as->userbuffer && urb->actual_length) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, - urb->actual_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)) return -EFAULT; + } if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) diff --git a/kernel/drivers/usb/core/driver.c b/kernel/drivers/usb/core/driver.c index d784a8b3..3ac64a58 100644 --- a/kernel/drivers/usb/core/driver.c +++ b/kernel/drivers/usb/core/driver.c @@ -1187,13 +1187,22 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) for (; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; status = usb_suspend_interface(udev, intf, msg); + + /* Ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; if (status != 0) break; } } - if (status == 0) + if (status == 0) { status = usb_suspend_device(udev, msg); + /* Again, ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; + } + /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { pm_message_t msg2; diff --git a/kernel/drivers/usb/core/hub.c b/kernel/drivers/usb/core/hub.c index 03eed28d..e7dce0c5 100644 --- a/kernel/drivers/usb/core/hub.c +++ b/kernel/drivers/usb/core/hub.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -458,10 +459,8 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) * talking to TTs must queue control transfers (not just bulk and iso), so * both can talk to the same hub concurrently. */ -static void hub_tt_work(struct work_struct *work) +void _hub_tt_work(struct usb_hub *hub) { - struct usb_hub *hub = - container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; int limit = 100; @@ -496,6 +495,14 @@ static void hub_tt_work(struct work_struct *work) spin_unlock_irqrestore (&hub->tt.lock, flags); } +void hub_tt_work(struct work_struct *work) +{ + struct usb_hub *hub = + container_of(work, struct usb_hub, tt.clear_work); + + _hub_tt_work(hub); +} + /** * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub * @urb: an URB associated with the failed or incomplete split transaction @@ -543,7 +550,20 @@ int usb_hub_clear_tt_buffer(struct urb *urb) /* tell keventd to clear state for this TT */ spin_lock_irqsave (&tt->lock, flags); list_add_tail (&clear->clear_list, &tt->clear_list); - schedule_work(&tt->clear_work); + /* don't schedule on kevent if we're running on keventd (e.g., + * in hid_reset we can get here on kevent) unless on >=2.6.36 + */ + if (!current_is_keventd()) + /* put it on keventd */ + schedule_work(&tt->clear_work); + else { + /* let khubd do it */ + struct usb_hub *hub = + container_of(&tt->clear_work, struct usb_hub, + tt.clear_work); + kick_khubd(hub); + } + spin_unlock_irqrestore (&tt->lock, flags); return 0; } @@ -1812,6 +1832,16 @@ int usb_new_device(struct usb_device *udev) /* Tell the world! */ announce_device(udev); +#if 0 + if (udev->serial) + add_device_randomness(udev->serial, strlen(udev->serial)); + if (udev->product) + add_device_randomness(udev->product, strlen(udev->product)); + if (udev->manufacturer) + add_device_randomness(udev->manufacturer, + strlen(udev->manufacturer)); +#endif + /* Register the device. The device driver is responsible * for configuring the device and invoking the add-device * notifier chain (used by usbfs and possibly others). @@ -2188,6 +2218,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + + /* System sleep transitions should never fail */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; } else { /* device has up to 10 msec to fully suspend */ dev_dbg(&udev->dev, "usb %ssuspend\n", @@ -2427,16 +2461,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *hdev = hub->hdev; unsigned port1; - /* fail if children aren't already suspended */ + /* Warn if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; udev = hdev->children [port1-1]; if (udev && udev->can_submit) { - if (!(msg.event & PM_EVENT_AUTO)) - dev_dbg(&intf->dev, "port %d nyet suspended\n", - port1); - return -EBUSY; + dev_warn(&intf->dev, "port %d nyet suspended\n", port1); + if (msg.event & PM_EVENT_AUTO) + return -EBUSY; } } @@ -3271,6 +3304,10 @@ static void hub_events(void) if (hub->quiescing) goto loop_autopm; + /* _hub_tt_work usually run on keventd */ + if (!list_empty(&hub->tt.clear_list)) + _hub_tt_work(hub); + if (hub->error) { dev_dbg (hub_dev, "resetting for error %d\n", hub->error); diff --git a/kernel/drivers/usb/core/quirks.c b/kernel/drivers/usb/core/quirks.c index 62e1cfdc..4923702e 100644 --- a/kernel/drivers/usb/core/quirks.c +++ b/kernel/drivers/usb/core/quirks.c @@ -38,6 +38,51 @@ static const struct usb_device_id usb_quirk_list[] = { /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C200 */ + { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C250 */ + { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam B/C500 */ + { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C600 */ + { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam Pro 9000 */ + { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C905 */ + { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C210 */ + { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C260 */ + { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C310 */ + { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C910 */ + { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C160 */ + { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C270 */ + { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam Pro 9000 */ + { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam E3500 */ + { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam Vision Pro */ + { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Harmony 700-series */ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -69,6 +114,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x06a3, 0x0006), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */ + { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Guillemot Webcam Hercules Dualpix Exchange*/ + { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/kernel/drivers/usb/early/ehci-dbgp.c b/kernel/drivers/usb/early/ehci-dbgp.c index 1206a26e..7565f558 100644 --- a/kernel/drivers/usb/early/ehci-dbgp.c +++ b/kernel/drivers/usb/early/ehci-dbgp.c @@ -449,7 +449,7 @@ static int dbgp_ehci_startup(void) writel(FLAG_CF, &ehci_regs->configured_flag); /* Wait until the controller is no longer halted */ - loop = 10; + loop = 1000; do { status = readl(&ehci_regs->status); if (!(status & STS_HALT)) diff --git a/kernel/drivers/usb/gadget/dummy_hcd.c b/kernel/drivers/usb/gadget/dummy_hcd.c index 5e096648..7adb671c 100644 --- a/kernel/drivers/usb/gadget/dummy_hcd.c +++ b/kernel/drivers/usb/gadget/dummy_hcd.c @@ -1886,6 +1886,7 @@ static int dummy_hcd_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; the_controller = hcd_to_dummy (hcd); + hcd->has_tt = 1; retval = usb_add_hcd(hcd, 0, 0); if (retval != 0) { diff --git a/kernel/drivers/usb/gadget/f_loopback.c b/kernel/drivers/usb/gadget/f_loopback.c index 6cb29d3d..8b4dbfc1 100644 --- a/kernel/drivers/usb/gadget/f_loopback.c +++ b/kernel/drivers/usb/gadget/f_loopback.c @@ -373,7 +373,7 @@ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) /* support autoresume for remote wakeup testing */ if (autoresume) - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; /* support OTG systems */ if (gadget_is_otg(cdev->gadget)) { diff --git a/kernel/drivers/usb/host/ehci-dbg.c b/kernel/drivers/usb/host/ehci-dbg.c index 874d2000..ff37d419 100644 --- a/kernel/drivers/usb/host/ehci-dbg.c +++ b/kernel/drivers/usb/host/ehci-dbg.c @@ -41,7 +41,7 @@ * (host controller _Structural_ parameters) * see EHCI spec, Table 2-4 for each value */ -static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) +static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) { u32 params = ehci_readl(ehci, &ehci->caps->hcs_params); @@ -85,7 +85,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} * (host controller _Capability_ parameters) * see EHCI Spec, Table 2-5 for each value * */ -static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) +static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) { u32 params = ehci_readl(ehci, &ehci->caps->hcc_params); diff --git a/kernel/drivers/usb/host/ehci-hcd.c b/kernel/drivers/usb/host/ehci-hcd.c index fa0e8d3b..3c4973f6 100644 --- a/kernel/drivers/usb/host/ehci-hcd.c +++ b/kernel/drivers/usb/host/ehci-hcd.c @@ -84,7 +84,8 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ -#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */ +#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) + /* 200-ms async qh unlink delay */ /* Initial IRQ latency: faster than hw default */ static int log2_irq_thresh = 0; // 0 to 6 @@ -139,10 +140,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) break; /* case TIMER_ASYNC_SHRINK: */ default: - /* add a jiffie since we synch against the - * 8 KHz uframe counter. - */ - t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1; + t = EHCI_SHRINK_JIFFIES; break; } mod_timer(&ehci->watchdog, t + jiffies); @@ -432,7 +430,7 @@ static void ehci_shutdown(struct usb_hcd *hcd) spin_unlock_irq(&ehci->lock); } -static void ehci_port_power (struct ehci_hcd *ehci, int is_on) +static inline void ehci_port_power(struct ehci_hcd *ehci, int is_on) { unsigned port; diff --git a/kernel/drivers/usb/host/ehci-hub.c b/kernel/drivers/usb/host/ehci-hub.c index 6812eacd..eaa74082 100644 --- a/kernel/drivers/usb/host/ehci-hub.c +++ b/kernel/drivers/usb/host/ehci-hub.c @@ -264,7 +264,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) u32 temp; u32 power_okay; int i; - u8 resume_needed = 0; + unsigned long resume_needed = 0; if (time_before (jiffies, ehci->next_statechange)) msleep(5); @@ -328,7 +328,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) if (test_bit(i, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) { temp |= PORT_RESUME; - resume_needed = 1; + set_bit(i, &resume_needed); } ehci_writel(ehci, temp, &ehci->regs->port_status [i]); } @@ -343,8 +343,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) i = HCS_N_PORTS (ehci->hcs_params); while (i--) { temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - if (test_bit(i, &ehci->bus_suspended) && - (temp & PORT_SUSPEND)) { + if (test_bit(i, &resume_needed)) { temp &= ~(PORT_RWC_BITS | PORT_RESUME); ehci_writel(ehci, temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); @@ -779,10 +778,11 @@ static int ehci_hub_control ( * power switching; they're allowed to just limit the * current. khubd will turn the power back on. */ - if (HCS_PPC (ehci->hcs_params)){ + if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_POWER), status_reg); + temp = ehci_readl(ehci, status_reg); } } diff --git a/kernel/drivers/usb/host/ehci-q.c b/kernel/drivers/usb/host/ehci-q.c index 41a74d27..beba415a 100644 --- a/kernel/drivers/usb/host/ehci-q.c +++ b/kernel/drivers/usb/host/ehci-q.c @@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { unsigned is_out, epnum; - is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); + is_out = qh->is_out; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); @@ -936,6 +936,7 @@ done: hw = qh->hw; hw->hw_info1 = cpu_to_hc32(ehci, info1); hw->hw_info2 = cpu_to_hc32(ehci, info2); + qh->is_out = !is_input; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; @@ -1216,6 +1217,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) prev->hw->hw_next = qh->hw->hw_next; prev->qh_next = qh->qh_next; + if (ehci->qh_scan_next == qh) + ehci->qh_scan_next = qh->qh_next.qh; wmb (); /* If the controller isn't running, we don't have to wait for it */ @@ -1241,53 +1244,49 @@ static void scan_async (struct ehci_hcd *ehci) struct ehci_qh *qh; enum ehci_timer_action action = TIMER_IO_WATCHDOG; - ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); timer_action_done (ehci, TIMER_ASYNC_SHRINK); -rescan: stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state); - qh = ehci->async->qh_next.qh; - if (likely (qh != NULL)) { - do { - /* clean any finished work for this qh */ - if (!list_empty(&qh->qtd_list) && (stopped || - qh->stamp != ehci->stamp)) { - int temp; - /* unlinks could happen here; completion - * reporting drops the lock. rescan using - * the latest schedule, but don't rescan - * qhs we already finished (no looping) - * unless the controller is stopped. - */ - qh = qh_get (qh); - qh->stamp = ehci->stamp; - temp = qh_completions (ehci, qh); - if (qh->needs_rescan) - unlink_async(ehci, qh); - qh_put (qh); - if (temp != 0) { - goto rescan; - } - } + ehci->qh_scan_next = ehci->async->qh_next.qh; + while (ehci->qh_scan_next) { + qh = ehci->qh_scan_next; + ehci->qh_scan_next = qh->qh_next.qh; + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; - /* unlink idle entries, reducing DMA usage as well - * as HCD schedule-scanning costs. delay for any qh - * we just scanned, there's a not-unusual case that it - * doesn't stay idle for long. - * (plus, avoids some kind of re-activation race.) + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why ehci->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then ehci->qh_scan_next is adjusted + * in start_unlink_async(). */ - if (list_empty(&qh->qtd_list) - && qh->qh_state == QH_STATE_LINKED) { - if (!ehci->reclaim && (stopped || - ((ehci->stamp - qh->stamp) & 0x1fff) - >= EHCI_SHRINK_FRAMES * 8)) - start_unlink_async(ehci, qh); - else - action = TIMER_ASYNC_SHRINK; - } + qh = qh_get(qh); + temp = qh_completions(ehci, qh); + if (qh->needs_rescan) + unlink_async(ehci, qh); + qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; + qh_put(qh); + if (temp != 0) + goto rescan; + } - qh = qh->qh_next.qh; - } while (qh); + /* unlink idle entries, reducing DMA usage as well + * as HCD schedule-scanning costs. delay for any qh + * we just scanned, there's a not-unusual case that it + * doesn't stay idle for long. + * (plus, avoids some kind of re-activation race.) + */ + if (list_empty(&qh->qtd_list) + && qh->qh_state == QH_STATE_LINKED) { + if (!ehci->reclaim && (stopped || + time_after_eq(jiffies, qh->unlink_time))) + start_unlink_async(ehci, qh); + else + action = TIMER_ASYNC_SHRINK; + } } if (action == TIMER_ASYNC_SHRINK) timer_action (ehci, TIMER_ASYNC_SHRINK); diff --git a/kernel/drivers/usb/host/ehci-stcore.c b/kernel/drivers/usb/host/ehci-stcore.c index 12600054..0c6b953d 100644 --- a/kernel/drivers/usb/host/ehci-stcore.c +++ b/kernel/drivers/usb/host/ehci-stcore.c @@ -62,7 +62,7 @@ stm_ehci_bus_resume(struct usb_hcd *hcd) static const struct hc_driver ehci_stm_hc_driver = { .description = hcd_name, - .product_desc = "st-ehci", + .product_desc = "STMicroelectronics EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), /* @@ -199,6 +199,7 @@ static struct platform_driver ehci_hcd_stm_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "stm-ehci", + .owner = THIS_MODULE, }, }; @@ -216,7 +217,7 @@ int stm_ehci_hcd_unregister(struct platform_device *dev) ret = ehci_hcd_stm_remove(dev); mutex_unlock(&stm_ehci_usb_mutex); if (ret) - dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev); + dgb_print("[STM][USB] Error on %s %p\n", __func__, dev); return ret; } @@ -230,7 +231,7 @@ int stm_ehci_hcd_register(struct platform_device *dev) ret = ehci_hcd_stm_probe(dev); mutex_unlock(&stm_ehci_usb_mutex); if (ret) - dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev); + dgb_print("[STM][USB] Error on %s %p\n", __func__, dev); return ret; } EXPORT_SYMBOL(stm_ehci_hcd_register); diff --git a/kernel/drivers/usb/host/ehci.h b/kernel/drivers/usb/host/ehci.h index 7f153bfa..87ae0299 100644 --- a/kernel/drivers/usb/host/ehci.h +++ b/kernel/drivers/usb/host/ehci.h @@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; + struct ehci_qh *qh_scan_next; unsigned scanning : 1; /* periodic schedule support */ @@ -116,7 +117,6 @@ struct ehci_hcd { /* one per controller */ struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; - unsigned stamp; unsigned random_frame; unsigned long next_statechange; ktime_t last_periodic_enable; @@ -336,6 +336,7 @@ struct ehci_qh { struct ehci_qh *reclaim; /* next to reclaim */ struct ehci_hcd *ehci; + unsigned long unlink_time; /* * Do NOT use atomic operations for QH refcounting. On some CPUs @@ -367,6 +368,7 @@ struct ehci_qh { #define NO_FRAME ((unsigned short)~0) /* pick new start */ struct usb_device *dev; /* access to TT */ + unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ }; diff --git a/kernel/drivers/usb/host/fhci-sched.c b/kernel/drivers/usb/host/fhci-sched.c index 62a226b6..fc704ceb 100644 --- a/kernel/drivers/usb/host/fhci-sched.c +++ b/kernel/drivers/usb/host/fhci-sched.c @@ -1,7 +1,7 @@ /* * Freescale QUICC Engine USB Host Controller Driver * - * Copyright (c) Freescale Semicondutor, Inc. 2006. + * Copyright (c) Freescale Semicondutor, Inc. 2006, 2011. * Shlomi Gridish * Jerry Huang * Copyright (c) Logic Product Development, Inc. 2007 @@ -810,9 +810,11 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) ed->dev_addr = usb_pipedevice(urb->pipe); ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + /* setup stage */ td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); + /* data stage */ if (data_len > 0) { td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : @@ -820,9 +822,18 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) USB_TD_TOGGLE_DATA1, data, data_len, 0, 0, true); } - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT, - USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + + /* status stage */ + if (data_len > 0) + td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + (usb_pipeout(urb->pipe) ? FHCI_TA_IN : + FHCI_TA_OUT), + USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + else + td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + FHCI_TA_IN, + USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + urb_state = US_CTRL_SETUP; break; case FHCI_TF_ISO: diff --git a/kernel/drivers/usb/host/hcd-stm.c b/kernel/drivers/usb/host/hcd-stm.c index 72eb065a..d0cc1091 100644 --- a/kernel/drivers/usb/host/hcd-stm.c +++ b/kernel/drivers/usb/host/hcd-stm.c @@ -71,20 +71,21 @@ static int stm_usb_boot(struct platform_device *pdev) void *wrapper_base = usb_data->ahb2stbus_wrapper_glue_base; void *protocol_base = usb_data->ahb2stbus_protocol_base; unsigned long reg, req_reg; + unsigned long flags = pl_data->flags; - if (pl_data->flags & - (STM_PLAT_USB_FLAGS_STRAP_8BIT | - STM_PLAT_USB_FLAGS_STRAP_16BIT)) { + + if (flags & (STM_PLAT_USB_FLAGS_STRAP_8BIT | + STM_PLAT_USB_FLAGS_STRAP_16BIT)) { /* Set strap mode */ reg = readl(wrapper_base + AHB2STBUS_STRAP_OFFSET); - if (pl_data->flags & STM_PLAT_USB_FLAGS_STRAP_16BIT) + if (flags & STM_PLAT_USB_FLAGS_STRAP_16BIT) reg |= AHB2STBUS_STRAP_16_BIT; else reg &= ~AHB2STBUS_STRAP_16_BIT; writel(reg, wrapper_base + AHB2STBUS_STRAP_OFFSET); } - if (pl_data->flags & STM_PLAT_USB_FLAGS_STRAP_PLL) { + if (flags & STM_PLAT_USB_FLAGS_STRAP_PLL) { /* Start PLL */ reg = readl(wrapper_base + AHB2STBUS_STRAP_OFFSET); writel(reg | AHB2STBUS_STRAP_PLL, @@ -95,7 +96,7 @@ static int stm_usb_boot(struct platform_device *pdev) mdelay(30); } - if (pl_data->flags & STM_PLAT_USB_FLAGS_OPC_MSGSIZE_CHUNKSIZE) { + if (flags & STM_PLAT_USB_FLAGS_OPC_MSGSIZE_CHUNKSIZE) { /* Set the STBus Opcode Config for load/store 32 */ writel(AHB2STBUS_STBUS_OPC_32BIT, protocol_base + AHB2STBUS_STBUS_OPC_OFFSET); @@ -109,7 +110,7 @@ static int stm_usb_boot(struct platform_device *pdev) protocol_base + AHB2STBUS_CHUNKSIZE_OFFSET); } - if (pl_data->flags & + if (flags & (STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD128 | STM_PLAT_USB_FLAGS_STBUS_CONFIG_THRESHOLD256)) { @@ -134,24 +135,14 @@ static int stm_usb_boot(struct platform_device *pdev) static int stm_usb_remove(struct platform_device *pdev) { - struct resource *res; - struct device *dev = &pdev->dev; struct drv_usb_data *dr_data = platform_get_drvdata(pdev); + platform_device_unregister(dr_data->ehci_device); + platform_device_unregister(dr_data->ohci_device); + stm_device_power(dr_data->device_state, stm_device_power_off); - stm_usb_clk_disable(dr_data); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper"); - devm_release_mem_region(dev, res->start, resource_size(res)); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol"); - devm_release_mem_region(dev, res->start, resource_size(res)); - - if (dr_data->ehci_device) - platform_device_unregister(dr_data->ehci_device); - if (dr_data->ohci_device) - platform_device_unregister(dr_data->ohci_device); - return 0; } @@ -191,7 +182,7 @@ static int __init stm_usb_probe(struct platform_device *pdev) struct drv_usb_data *dr_data; struct device *dev = &pdev->dev; struct resource *res; - int ret = 0, i; + int i; static char __initdata *usb_clks_n[USB_CLKS_NR] = { [USB_48_CLK] = "usb_48_clk", [USB_IC_CLK] = "usb_ic_clk", @@ -200,7 +191,7 @@ static int __init stm_usb_probe(struct platform_device *pdev) resource_size_t len; dgb_print("\n"); - dr_data = kzalloc(sizeof(struct drv_usb_data), GFP_KERNEL); + dr_data = devm_kzalloc(dev, sizeof(*dr_data), GFP_KERNEL); if (!dr_data) return -ENOMEM; @@ -215,57 +206,47 @@ static int __init stm_usb_probe(struct platform_device *pdev) stm_usb_clk_enable(dr_data); - dr_data->device_state = devm_stm_device_init(&pdev->dev, - plat_data->device_config); - if (!dr_data->device_state) { - ret = -EBUSY; - goto err_0; - } + dr_data->device_state = + devm_stm_device_init(&pdev->dev, plat_data->device_config); + if (!dr_data->device_state) + return -EBUSY; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper"); - if (!res) { - ret = -ENXIO; - goto err_0; - } + if (!res) + return -ENXIO; + len = resource_size(res); - if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) { - ret = -EBUSY; - goto err_0; - } + if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) + return -EBUSY; + dr_data->ahb2stbus_wrapper_glue_base = devm_ioremap_nocache(dev, res->start, len); - if (!dr_data->ahb2stbus_wrapper_glue_base) { - ret = -EFAULT; - goto err_1; - } + if (!dr_data->ahb2stbus_wrapper_glue_base) + return -EFAULT; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol"); - if (!res) { - ret = -ENXIO; - goto err_2; - } + if (!res) + return -ENXIO; + len = resource_size(res); - if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) { - ret = -EBUSY; - goto err_2; - } + if (devm_request_mem_region(dev, res->start, len, pdev->name) < 0) + return -EBUSY; + dr_data->ahb2stbus_protocol_base = devm_ioremap_nocache(dev, res->start, len); - if (!dr_data->ahb2stbus_protocol_base) { - ret = -EFAULT; - goto err_3; - } + if (!dr_data->ahb2stbus_protocol_base) + return -EFAULT; + stm_usb_boot(pdev); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); if (res) { dr_data->ehci_device = stm_usb_device_create("stm-ehci", pdev->id, pdev); - if (IS_ERR(dr_data->ehci_device)) { - ret = (int)dr_data->ehci_device; - goto err_4; - } + if (IS_ERR(dr_data->ehci_device)) + return PTR_ERR(dr_data->ehci_device); } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci"); @@ -273,10 +254,8 @@ static int __init stm_usb_probe(struct platform_device *pdev) dr_data->ohci_device = stm_usb_device_create("stm-ohci", pdev->id, pdev); if (IS_ERR(dr_data->ohci_device)) { - if (dr_data->ehci_device) - platform_device_del(dr_data->ehci_device); - ret = (int)dr_data->ohci_device; - goto err_4; + platform_device_del(dr_data->ehci_device); + return PTR_ERR(dr_data->ohci_device); } } @@ -285,21 +264,7 @@ static int __init stm_usb_probe(struct platform_device *pdev) pm_suspend_ignore_children(&pdev->dev, 1); pm_runtime_enable(&pdev->dev); - return ret; - -err_4: - devm_iounmap(dev, dr_data->ahb2stbus_protocol_base); -err_3: - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "protocol"); - devm_release_mem_region(dev, res->start, resource_size(res)); -err_2: - devm_iounmap(dev, dr_data->ahb2stbus_wrapper_glue_base); -err_1: - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper"); - devm_release_mem_region(dev, res->start, resource_size(res)); -err_0: - kfree(dr_data); - return ret; + return 0; } static void stm_usb_shutdown(struct platform_device *pdev) diff --git a/kernel/drivers/usb/host/ohci-stcore.c b/kernel/drivers/usb/host/ohci-stcore.c index 13dc9980..8f4ec3a5 100644 --- a/kernel/drivers/usb/host/ohci-stcore.c +++ b/kernel/drivers/usb/host/ohci-stcore.c @@ -56,7 +56,7 @@ static int stm_ohci_bus_suspend(struct usb_hcd *hcd) static const struct hc_driver ohci_st40_hc_driver = { .description = hcd_name, - .product_desc = "stm-ohci", + .product_desc = "STMicroelectronics OHCI Host Controller", .hcd_priv_size = sizeof(struct ohci_hcd), /* generic hardware linkage */ @@ -165,6 +165,7 @@ static struct platform_driver ohci_hcd_stm_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "stm-ohci", + .owner = THIS_MODULE, }, }; @@ -183,7 +184,7 @@ int stm_ohci_hcd_unregister(struct platform_device *dev) ret = ohci_hcd_stm_remove(dev); mutex_unlock(&stm_ohci_usb_mutex); if (ret) - dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev); + dgb_print("[STM][USB] Error on %s %p\n", __func__, dev); return ret; } EXPORT_SYMBOL(stm_ohci_hcd_unregister); @@ -196,7 +197,7 @@ int stm_ohci_hcd_register(struct platform_device *dev) ret = ohci_hcd_stm_probe(dev); mutex_unlock(&stm_ohci_usb_mutex); if (ret) - dgb_print("[STM][USB] Error on %s 0x%x\n", __func__, dev); + dgb_print("[STM][USB] Error on %s %p\n", __func__, dev); return ret; } diff --git a/kernel/drivers/usb/host/pci-quirks.c b/kernel/drivers/usb/host/pci-quirks.c index 464ed977..01e7fae8 100644 --- a/kernel/drivers/usb/host/pci-quirks.c +++ b/kernel/drivers/usb/host/pci-quirks.c @@ -34,6 +34,8 @@ #define OHCI_INTRSTATUS 0x0c #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 +#define OHCI_FMINTERVAL 0x34 +#define OHCI_HCR (1 << 0) /* host controller reset */ #define OHCI_OCR (1 << 3) /* ownership change request */ #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ #define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ @@ -204,6 +206,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) /* reset controller, preserving RWC (and possibly IR) */ writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); + + /* Some NVIDIA controllers stop working if kept in RESET for too long */ + if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { + u32 fminterval; + int cnt; + + /* drive reset for at least 50 ms (7.1.7.5) */ + msleep(50); + + /* software reset of the controller, preserving HcFmInterval */ + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); + + /* reset requires max 10 us delay */ + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) + break; + udelay(1); + } + writel(fminterval, base + OHCI_FMINTERVAL); + + /* Now we're in the SUSPEND state with all devices reset + * and wakeups and interrupts disabled + */ + } /* * disable interrupts @@ -390,12 +418,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) void __iomem *op_reg_base; u32 val; int timeout; + int len = pci_resource_len(pdev, 0); if (!mmio_resource_enabled(pdev, 0)) return; - base = ioremap_nocache(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + base = ioremap_nocache(pci_resource_start(pdev, 0), len); if (base == NULL) return; @@ -405,9 +433,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) */ ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); do { + if ((ext_cap_offset + sizeof(val)) > len) { + /* We're reading garbage from the controller */ + dev_warn(&pdev->dev, + "xHCI controller failing to respond"); + return; + } + if (!ext_cap_offset) /* We've reached the end of the extended capabilities */ goto hc_init; + val = readl(base + ext_cap_offset); if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) break; @@ -416,7 +452,7 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) /* If the BIOS owns the HC, signal that the OS wants it, and wait */ if (val & XHCI_HC_BIOS_OWNED) { - writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset); + writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset); /* Wait for 5 seconds with 10 microsecond polling interval */ timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED, @@ -430,9 +466,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) } } - /* Disable any BIOS SMIs */ - writel(XHCI_LEGACY_DISABLE_SMI, - base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); + val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); + /* Mask off (turn off) any enabled SMIs */ + val &= XHCI_LEGACY_DISABLE_SMI; + /* Mask all SMI events bits, RW1C */ + val |= XHCI_LEGACY_SMI_EVENTS; + /* Disable any BIOS SMIs and clear all SMI events*/ + writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); hc_init: op_reg_base = base + XHCI_HC_LENGTH(readl(base)); @@ -470,6 +510,22 @@ hc_init: static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) { + /* Skip Netlogic mips SoC's internal PCI USB controller. + * This device does not need/support EHCI/OHCI handoff + */ + if (pdev->vendor == 0x184e) /* vendor Netlogic */ + return; + if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && + pdev->class != PCI_CLASS_SERIAL_USB_OHCI && + pdev->class != PCI_CLASS_SERIAL_USB_EHCI && + pdev->class != PCI_CLASS_SERIAL_USB_XHCI) + return; + + if (pci_enable_device(pdev) < 0) { + dev_warn(&pdev->dev, "Can't enable PCI device, " + "BIOS handoff failed.\n"); + return; + } if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) quirk_usb_handoff_uhci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) @@ -478,5 +534,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) quirk_usb_disable_ehci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) quirk_usb_handoff_xhci(pdev); + pci_disable_device(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); diff --git a/kernel/drivers/usb/host/whci/qset.c b/kernel/drivers/usb/host/whci/qset.c index 1b9dc157..921cf806 100644 --- a/kernel/drivers/usb/host/whci/qset.c +++ b/kernel/drivers/usb/host/whci/qset.c @@ -104,7 +104,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) { qset->td_start = qset->td_end = qset->ntds = 0; - qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); + qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.err_count = 0; qset->qh.scratch[0] = 0; diff --git a/kernel/drivers/usb/host/xhci-ext-caps.h b/kernel/drivers/usb/host/xhci-ext-caps.h index 78c4edac..e2acc97b 100644 --- a/kernel/drivers/usb/host/xhci-ext-caps.h +++ b/kernel/drivers/usb/host/xhci-ext-caps.h @@ -62,8 +62,9 @@ /* USB Legacy Support Control and Status Register - section 7.1.2 */ /* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ #define XHCI_LEGACY_CONTROL_OFFSET (0x04) -/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ -#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) +/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ +#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17)) +#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29) /* command register values to disable interrupts and halt the HC */ /* start/stop HC execution - do not write unless HC is halted*/ diff --git a/kernel/drivers/usb/host/xhci-hcd.c b/kernel/drivers/usb/host/xhci-hcd.c index a24a92f7..0641633b 100644 --- a/kernel/drivers/usb/host/xhci-hcd.c +++ b/kernel/drivers/usb/host/xhci-hcd.c @@ -150,7 +150,7 @@ int xhci_reset(struct xhci_hcd *xhci) xhci_to_hcd(xhci)->state = HC_STATE_HALT; ret = handshake(xhci, &xhci->op_regs->command, - CMD_RESET, 0, 250 * 1000); + CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; @@ -979,6 +979,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, u32 added_ctxs; unsigned int last_ctx; u32 new_add_flags, new_drop_flags, new_slot_info; + struct xhci_virt_device *virt_dev; int ret = 0; ret = xhci_check_args(hcd, udev, ep, 1, __func__); @@ -1007,11 +1008,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return -EINVAL; } - in_ctx = xhci->devs[udev->slot_id]->in_ctx; - out_ctx = xhci->devs[udev->slot_id]->out_ctx; + virt_dev = xhci->devs[udev->slot_id]; + in_ctx = virt_dev->in_ctx; + out_ctx = virt_dev->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + + /* If this endpoint is already in use, and the upper layers are trying + * to add it again without dropping it, reject the addition. + */ + if (virt_dev->eps[ep_index].ring && + !(le32_to_cpu(ctrl_ctx->drop_flags) & + xhci_get_endpoint_flag(&ep->desc))) { + xhci_warn(xhci, "Trying to add endpoint 0x%x " + "without dropping it.\n", + (unsigned int) ep->desc.bEndpointAddress); + return -EINVAL; + } + /* If the HCD has already noted the endpoint is enabled, * ignore this request. */ @@ -1026,8 +1041,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * process context, not interrupt context (or so documenation * for usb_set_interface() and usb_set_configuration() claim). */ - if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id], - udev, ep, GFP_KERNEL) < 0) { + if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) { dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", __func__, ep->desc.bEndpointAddress); return -ENOMEM; diff --git a/kernel/drivers/usb/host/xhci-mem.c b/kernel/drivers/usb/host/xhci-mem.c index fce7b5e1..776fd430 100644 --- a/kernel/drivers/usb/host/xhci-mem.c +++ b/kernel/drivers/usb/host/xhci-mem.c @@ -110,18 +110,20 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) struct xhci_segment *seg; struct xhci_segment *first_seg; - if (!ring || !ring->first_seg) + if (!ring) return; - first_seg = ring->first_seg; - seg = first_seg->next; - xhci_dbg(xhci, "Freeing ring at %p\n", ring); - while (seg != first_seg) { - struct xhci_segment *next = seg->next; - xhci_segment_free(xhci, seg); - seg = next; + if (ring->first_seg) { + first_seg = ring->first_seg; + seg = first_seg->next; + xhci_dbg(xhci, "Freeing ring at %p\n", ring); + while (seg != first_seg) { + struct xhci_segment *next = seg->next; + xhci_segment_free(xhci, seg); + seg = next; + } + xhci_segment_free(xhci, first_seg); + ring->first_seg = NULL; } - xhci_segment_free(xhci, first_seg); - ring->first_seg = NULL; kfree(ring); } @@ -470,26 +472,42 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, } /* - * Convert bInterval expressed in frames (in 1-255 range) to exponent of + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of * microframes, rounded down to nearest power of 2. */ -static unsigned int xhci_parse_frame_interval(struct usb_device *udev, - struct usb_host_endpoint *ep) +static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, + struct usb_host_endpoint *ep, unsigned int desc_interval, + unsigned int min_exponent, unsigned int max_exponent) { unsigned int interval; - interval = fls(8 * ep->desc.bInterval) - 1; - interval = clamp_val(interval, 3, 10); - if ((1 << interval) != 8 * ep->desc.bInterval) + interval = fls(desc_interval) - 1; + interval = clamp_val(interval, min_exponent, max_exponent); + if ((1 << interval) != desc_interval) dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", ep->desc.bEndpointAddress, 1 << interval, - 8 * ep->desc.bInterval); + desc_interval); return interval; } +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + return xhci_microframes_to_exponent(udev, ep, + ep->desc.bInterval, 0, 15); +} + + +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + return xhci_microframes_to_exponent(udev, ep, + ep->desc.bInterval * 8, 3, 10); +} + /* Return the polling or NAK interval. * * The polling interval is expressed in "microframes". If xHCI's Interval field @@ -508,7 +526,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, /* Max NAK rate */ if (usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_bulk(&ep->desc)) { - interval = ep->desc.bInterval; + interval = xhci_parse_microframe_interval(udev, ep); break; } /* Fall through - SS and HS isoc/int have same decoding */ @@ -916,11 +934,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) int i; /* Free the Event Ring Segment Table and the actual Event Ring */ - 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, @@ -932,7 +945,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); - xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); + xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -951,7 +964,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->device_pool = NULL; xhci_dbg(xhci, "Freed device context pool\n"); - xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); if (xhci->dcbaa) pci_free_consistent(pdev, sizeof(*xhci->dcbaa), xhci->dcbaa, xhci->dcbaa->dma); @@ -1128,6 +1140,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) fail: xhci_warn(xhci, "Couldn't initialize memory\n"); + xhci_halt(xhci); + xhci_reset(xhci); xhci_mem_cleanup(xhci); return -ENOMEM; } diff --git a/kernel/drivers/usb/misc/isight_firmware.c b/kernel/drivers/usb/misc/isight_firmware.c index b897f655..6199f12d 100644 --- a/kernel/drivers/usb/misc/isight_firmware.c +++ b/kernel/drivers/usb/misc/isight_firmware.c @@ -54,8 +54,9 @@ static int isight_firmware_load(struct usb_interface *intf, ptr = firmware->data; + buf[0] = 0x01; if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, 300) != 1) { printk(KERN_ERR "Failed to initialise isight firmware loader\n"); @@ -99,8 +100,9 @@ static int isight_firmware_load(struct usb_interface *intf, } } + buf[0] = 0x00; if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, 300) != 1) { printk(KERN_ERR "isight firmware loading completion failed\n"); ret = -ENODEV; diff --git a/kernel/drivers/usb/misc/usbsevseg.c b/kernel/drivers/usb/misc/usbsevseg.c index cd8726c3..6bc0bf3b 100644 --- a/kernel/drivers/usb/misc/usbsevseg.c +++ b/kernel/drivers/usb/misc/usbsevseg.c @@ -24,7 +24,7 @@ #define VENDOR_ID 0x0fc5 #define PRODUCT_ID 0x1227 -#define MAXLEN 6 +#define MAXLEN 8 /* table of devices that work with this driver */ static struct usb_device_id id_table[] = { diff --git a/kernel/drivers/usb/mon/mon_bin.c b/kernel/drivers/usb/mon/mon_bin.c index 9231b25d..f74f1825 100644 --- a/kernel/drivers/usb/mon/mon_bin.c +++ b/kernel/drivers/usb/mon/mon_bin.c @@ -1041,7 +1041,7 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, nevents = mon_bin_queued(rp); sp = (struct mon_bin_stats __user *)arg; - if (put_user(rp->cnt_lost, &sp->dropped)) + if (put_user(ndropped, &sp->dropped)) return -EFAULT; if (put_user(nevents, &sp->queued)) return -EFAULT; diff --git a/kernel/drivers/usb/serial/cp210x.c b/kernel/drivers/usb/serial/cp210x.c index f77908b1..feb96e9b 100644 --- a/kernel/drivers/usb/serial/cp210x.c +++ b/kernel/drivers/usb/serial/cp210x.c @@ -94,6 +94,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ @@ -135,10 +136,13 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; @@ -359,8 +363,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port, * Quantises the baud rate as per AN205 Table 1 */ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { - if (baud <= 56) baud = 0; - else if (baud <= 300) baud = 300; + if (baud <= 300) + baud = 300; else if (baud <= 600) baud = 600; else if (baud <= 1200) baud = 1200; else if (baud <= 1800) baud = 1800; diff --git a/kernel/drivers/usb/serial/ftdi_sio.c b/kernel/drivers/usb/serial/ftdi_sio.c index afc4bd3e..dd958e92 100644 --- a/kernel/drivers/usb/serial/ftdi_sio.c +++ b/kernel/drivers/usb/serial/ftdi_sio.c @@ -105,6 +105,7 @@ static int ftdi_jtag_probe(struct usb_serial *serial); static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); static int ftdi_NDI_device_setup(struct usb_serial *serial); static int ftdi_stmclite_probe(struct usb_serial *serial); +static int ftdi_8u2232c_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); @@ -132,6 +133,10 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = { .probe = ftdi_stmclite_probe, }; +static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { + .probe = ftdi_8u2232c_probe, +}; + /* * The 8U232AM has the same API as the sio except for: * - it can support MUCH higher baudrates; up to: @@ -155,6 +160,7 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = { * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! */ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, @@ -181,7 +187,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) , + .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk }, { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, @@ -203,6 +210,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, @@ -730,6 +739,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), @@ -740,6 +750,8 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, @@ -786,6 +798,7 @@ static struct usb_device_id id_table_combined [] = { .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(HORNBY_VID, HORNBY_ELITE_PID) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, @@ -794,6 +807,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, TI_XDS100V2_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, @@ -825,11 +840,13 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -1339,8 +1356,7 @@ static int set_serial_info(struct tty_struct *tty, goto check_and_exit; } - if ((new_serial.baud_base != priv->baud_base) && - (new_serial.baud_base < 9600)) { + if (new_serial.baud_base != priv->baud_base) { unlock_kernel(); return -EINVAL; } @@ -1762,6 +1778,19 @@ static int ftdi_jtag_probe(struct usb_serial *serial) return 0; } +static int ftdi_8u2232c_probe(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + + dbg("%s", __func__); + + if ((udev->manufacturer) && + (strcmp(udev->manufacturer, "CALAO Systems") == 0)) + return ftdi_jtag_probe(serial); + + return 0; +} + /* * First and second port on STMCLiteadaptors is reserved for JTAG interface * and the forth port for pio @@ -1841,6 +1870,7 @@ static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) { /* ftdi_open */ + struct ktermios dummy; struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; @@ -1868,8 +1898,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) This is same behaviour as serial.c/rs_open() - Kuba */ /* ftdi_set_termios will send usb control messages */ - if (tty) - ftdi_set_termios(tty, port, tty->termios); + if (tty) { + memset(&dummy, 0, sizeof(dummy)); + ftdi_set_termios(tty, port, &dummy); + } /* Not throttled */ spin_lock_irqsave(&port->lock, flags); @@ -2332,13 +2364,23 @@ static void ftdi_set_termios(struct tty_struct *tty, cflag = termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to - compare old_termios and tty->termios */ + if (!old_termios) + goto no_skip; + + if (old_termios->c_cflag == termios->c_cflag + && old_termios->c_ispeed == termios->c_ispeed + && old_termios->c_ospeed == termios->c_ospeed) + goto no_c_cflag_changes; + /* NOTE These routines can get interrupted by ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ + if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == + (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) + goto no_data_parity_stop_changes; + +no_skip: /* Set number of data bits, parity, stop bits */ termios->c_cflag &= ~CMSPAR; @@ -2375,6 +2417,7 @@ static void ftdi_set_termios(struct tty_struct *tty, } /* Now do the baudrate */ +no_data_parity_stop_changes: if ((cflag & CBAUD) == B0) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -2400,6 +2443,7 @@ static void ftdi_set_termios(struct tty_struct *tty, /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ +no_c_cflag_changes: if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __func__); if (usb_control_msg(dev, diff --git a/kernel/drivers/usb/serial/ftdi_sio_ids.h b/kernel/drivers/usb/serial/ftdi_sio_ids.h index 40ac7c7f..7bc0abd7 100644 --- a/kernel/drivers/usb/serial/ftdi_sio_ids.h +++ b/kernel/drivers/usb/serial/ftdi_sio_ids.h @@ -38,6 +38,13 @@ /* www.candapter.com Ewert Energy Systems CANdapter device */ #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ /* US Interface Navigator (http://www.usinterface.com/) */ @@ -53,6 +60,7 @@ /* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ #define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 #define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */ @@ -110,6 +118,7 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 /* Lenz LI-USB Computer Interface. */ #define FTDI_LENZ_LIUSB_PID 0xD780 @@ -419,9 +428,11 @@ #define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ /* - * DSS-20 Sync Station for Sony Ericsson P800 + * Sony Ericsson product ids */ -#define FTDI_DSS20_PID 0xFC82 +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ @@ -519,6 +530,12 @@ #define ADI_GNICE_PID 0xF000 #define ADI_GNICEPLUS_PID 0xF001 +/* + * Hornby Elite + */ +#define HORNBY_VID 0x04D8 +#define HORNBY_ELITE_PID 0x000A + /* * RATOC REX-USB60F */ @@ -1164,4 +1181,21 @@ /* USB-Nano-485*/ #define FTDI_CTI_NANO_PID 0xF60B +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 diff --git a/kernel/drivers/usb/serial/garmin_gps.c b/kernel/drivers/usb/serial/garmin_gps.c index 867d97b6..7c3ac7b8 100644 --- a/kernel/drivers/usb/serial/garmin_gps.c +++ b/kernel/drivers/usb/serial/garmin_gps.c @@ -974,10 +974,7 @@ static void garmin_close(struct usb_serial_port *port) if (!serial) return; - mutex_lock(&port->serial->disc_mutex); - - if (!port->serial->disconnected) - garmin_clear(garmin_data_p); + garmin_clear(garmin_data_p); /* shutdown our urbs */ usb_kill_urb(port->read_urb); @@ -986,8 +983,6 @@ static void garmin_close(struct usb_serial_port *port) /* keep reset state so we know that we must start a new session */ if (garmin_data_p->state != STATE_RESET) garmin_data_p->state = STATE_DISCONNECTED; - - mutex_unlock(&port->serial->disc_mutex); } diff --git a/kernel/drivers/usb/serial/io_ti.c b/kernel/drivers/usb/serial/io_ti.c index fbdbac5a..cf515f02 100644 --- a/kernel/drivers/usb/serial/io_ti.c +++ b/kernel/drivers/usb/serial/io_ti.c @@ -574,6 +574,9 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, wait_queue_t wait; unsigned long flags; + if (!tty) + return; + if (!timeout) timeout = (HZ * EDGE_CLOSING_WAIT)/100; @@ -2664,15 +2667,7 @@ cleanup: static void edge_disconnect(struct usb_serial *serial) { - int i; - struct edgeport_port *edge_port; - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - edge_remove_sysfs_attrs(edge_port->port); - } } static void edge_release(struct usb_serial *serial) @@ -2927,6 +2922,7 @@ static struct usb_serial_driver edgeport_1port_device = { .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_create_sysfs_attrs, + .port_remove = edge_remove_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -2957,6 +2953,7 @@ static struct usb_serial_driver edgeport_2port_device = { .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_create_sysfs_attrs, + .port_remove = edge_remove_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, diff --git a/kernel/drivers/usb/serial/mos7840.c b/kernel/drivers/usb/serial/mos7840.c index 9fdcee2e..c802c77e 100644 --- a/kernel/drivers/usb/serial/mos7840.c +++ b/kernel/drivers/usb/serial/mos7840.c @@ -1181,9 +1181,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) } spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) - if (mos7840_port->busy[i]) - chars += URB_TRANSFER_BUFFER_SIZE; + for (i = 0; i < NUM_URBS; ++i) { + if (mos7840_port->busy[i]) { + struct urb *urb = mos7840_port->write_urb_pool[i]; + chars += urb->transfer_buffer_length; + } + } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); dbg("%s - returns %d", __func__, chars); return chars; @@ -2566,7 +2569,6 @@ error: kfree(mos7840_port->ctrl_buf); usb_free_urb(mos7840_port->control_urb); kfree(mos7840_port); - serial->port[i] = NULL; } return status; } @@ -2633,6 +2635,7 @@ static void mos7840_release(struct usb_serial *serial) mos7840_port = mos7840_get_port_private(serial->port[i]); dbg("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { + usb_free_urb(mos7840_port->control_urb); kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); diff --git a/kernel/drivers/usb/serial/omninet.c b/kernel/drivers/usb/serial/omninet.c index 06226503..c116bd90 100644 --- a/kernel/drivers/usb/serial/omninet.c +++ b/kernel/drivers/usb/serial/omninet.c @@ -317,7 +317,7 @@ static int omninet_write_room(struct tty_struct *tty) int room = 0; /* Default: no room */ /* FIXME: no consistent locking for write_urb_busy */ - if (wport->write_urb_busy) + if (!wport->write_urb_busy) room = wport->bulk_out_size - OMNINET_HEADERLEN; dbg("%s - returns %d", __func__, room); diff --git a/kernel/drivers/usb/serial/option.c b/kernel/drivers/usb/serial/option.c index 8390eec8..39179716 100644 --- a/kernel/drivers/usb/serial/option.c +++ b/kernel/drivers/usb/serial/option.c @@ -618,6 +618,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, diff --git a/kernel/drivers/usb/serial/pl2303.c b/kernel/drivers/usb/serial/pl2303.c index b3360179..9f89940e 100644 --- a/kernel/drivers/usb/serial/pl2303.c +++ b/kernel/drivers/usb/serial/pl2303.c @@ -100,6 +100,8 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -615,10 +617,28 @@ static void pl2303_set_termios(struct tty_struct *tty, baud = 6000000; } dbg("%s - baud set = %d", __func__, baud); - buf[0] = baud & 0xff; - buf[1] = (baud >> 8) & 0xff; - buf[2] = (baud >> 16) & 0xff; - buf[3] = (baud >> 24) & 0xff; + if (baud <= 115200) { + buf[0] = baud & 0xff; + buf[1] = (baud >> 8) & 0xff; + buf[2] = (baud >> 16) & 0xff; + buf[3] = (baud >> 24) & 0xff; + } else { + /* apparently the formula for higher speeds is: + * baudrate = 12M * 32 / (2^buf[1]) / buf[0] + */ + unsigned tmp = 12*1000*1000*32 / baud; + buf[3] = 0x80; + buf[2] = 0; + buf[1] = (tmp >= 256); + while (tmp >= 256) { + tmp >>= 2; + buf[1] <<= 1; + } + if (tmp > 256) { + tmp %= 256; + } + buf[0] = tmp; + } } /* For reference buf[4]=0 is 1 stop bits */ diff --git a/kernel/drivers/usb/serial/pl2303.h b/kernel/drivers/usb/serial/pl2303.h index 4d043e4f..c38b8c00 100644 --- a/kernel/drivers/usb/serial/pl2303.h +++ b/kernel/drivers/usb/serial/pl2303.h @@ -5,7 +5,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * */ #define BENQ_VENDOR_ID 0x04a5 @@ -140,3 +140,12 @@ /* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ #define SANWA_VENDOR_ID 0x11ad #define SANWA_PRODUCT_ID 0x0001 + +/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 + diff --git a/kernel/drivers/usb/serial/qcserial.c b/kernel/drivers/usb/serial/qcserial.c index cde67cac..06865dd9 100644 --- a/kernel/drivers/usb/serial/qcserial.c +++ b/kernel/drivers/usb/serial/qcserial.c @@ -28,6 +28,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ + {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ @@ -45,6 +46,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ + {USB_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ @@ -78,6 +80,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ + {USB_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ diff --git a/kernel/drivers/usb/serial/sierra.c b/kernel/drivers/usb/serial/sierra.c index 1b5c9f80..0cbf847b 100644 --- a/kernel/drivers/usb/serial/sierra.c +++ b/kernel/drivers/usb/serial/sierra.c @@ -925,6 +925,7 @@ static void sierra_release(struct usb_serial *serial) continue; kfree(portdata); } + kfree(serial->private); } #ifdef CONFIG_PM diff --git a/kernel/drivers/usb/serial/usb-serial.c b/kernel/drivers/usb/serial/usb-serial.c index bd3fa7ff..0670b7f8 100644 --- a/kernel/drivers/usb/serial/usb-serial.c +++ b/kernel/drivers/usb/serial/usb-serial.c @@ -1071,6 +1071,12 @@ int usb_serial_probe(struct usb_interface *interface, serial->attached = 1; } + /* Avoid race with tty_open and serial_install by setting the + * disconnected flag and not clearing it until all ports have been + * registered. + */ + serial->disconnected = 1; + if (get_free_serial(serial, num_ports, &minor) == NULL) { dev_err(&interface->dev, "No more free serial devices\n"); goto probe_error; @@ -1093,6 +1099,8 @@ int usb_serial_probe(struct usb_interface *interface, } } + serial->disconnected = 0; + usb_serial_console_init(debug, minor); exit: diff --git a/kernel/drivers/usb/serial/whiteheat.c b/kernel/drivers/usb/serial/whiteheat.c index 1093d2eb..1247be12 100644 --- a/kernel/drivers/usb/serial/whiteheat.c +++ b/kernel/drivers/usb/serial/whiteheat.c @@ -576,6 +576,7 @@ no_firmware: "%s: please contact support@connecttech.com\n", serial->type->description); kfree(result); + kfree(command); return -ENODEV; no_command_private: diff --git a/kernel/drivers/usb/storage/protocol.c b/kernel/drivers/usb/storage/protocol.c index fc310f75..0fded39e 100644 --- a/kernel/drivers/usb/storage/protocol.c +++ b/kernel/drivers/usb/storage/protocol.c @@ -58,7 +58,9 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) { - /* Pad the SCSI command with zeros out to 12 bytes + /* + * Pad the SCSI command with zeros out to 12 bytes. If the + * command already is 12 bytes or longer, leave it alone. * * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available @@ -66,9 +68,6 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; - /* set command length to 12 bytes */ - srb->cmd_len = 12; - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); } diff --git a/kernel/drivers/usb/storage/transport.c b/kernel/drivers/usb/storage/transport.c index cc313d16..ac115fdd 100644 --- a/kernel/drivers/usb/storage/transport.c +++ b/kernel/drivers/usb/storage/transport.c @@ -693,6 +693,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int temp_result; struct scsi_eh_save ses; int sense_size = US_SENSE_SIZE; + struct scsi_sense_hdr sshdr; + const u8 *scdd; + u8 fm_ili; /* device supports and needs bigger sense buffer */ if (us->fflags & US_FL_SANE_SENSE) @@ -776,32 +779,30 @@ Retry_Sense: srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } + scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, + &sshdr); + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - srb->sense_buffer[0], - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); + sshdr.response_code, sshdr.sense_key, + sshdr.asc, sshdr.ascq); #ifdef CONFIG_USB_STORAGE_DEBUG - usb_stor_show_sense( - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); + usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; + scdd = scsi_sense_desc_find(srb->sense_buffer, + SCSI_SENSE_BUFFERSIZE, 4); + fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; + /* 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) { - + if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && + fm_ili == 0) { /* 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. @@ -816,7 +817,10 @@ Retry_Sense: */ } else { srb->result = DID_ERROR << 16; - srb->sense_buffer[2] = HARDWARE_ERROR; + if ((sshdr.response_code & 0x72) == 0x72) + srb->sense_buffer[1] = HARDWARE_ERROR; + else + srb->sense_buffer[2] = HARDWARE_ERROR; } } } diff --git a/kernel/drivers/usb/storage/unusual_devs.h b/kernel/drivers/usb/storage/unusual_devs.h index 6ca33f21..e76e6c44 100644 --- a/kernel/drivers/usb/storage/unusual_devs.h +++ b/kernel/drivers/usb/storage/unusual_devs.h @@ -1857,6 +1857,13 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Qinglin Ye */ +UNUSUAL_DEV( 0x13fe, 0x3600, 0x0100, 0x0100, + "Kingston", + "DT 101 G2", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG ), + /* Reported by Francesco Foresti */ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, "Super Top", @@ -1977,6 +1984,16 @@ UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, "Micro Mini 1GB", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* + * Nick Bowler + * SCSI stack spams (otherwise harmless) error messages. + */ +UNUSUAL_DEV( 0xc251, 0x4003, 0x0100, 0x0100, + "Keil Software, Inc.", + "V2M MotherBoard", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NOT_LOCKABLE), + /* Reported by Andrew Simmons */ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001, "DataStor", diff --git a/kernel/drivers/usb/storage/usb.c b/kernel/drivers/usb/storage/usb.c index 33197fa2..6ce1095d 100644 --- a/kernel/drivers/usb/storage/usb.c +++ b/kernel/drivers/usb/storage/usb.c @@ -1025,6 +1025,7 @@ static struct usb_driver usb_storage_driver = { .post_reset = usb_stor_post_reset, .id_table = usb_storage_usb_ids, .soft_unbind = 1, + .no_dynamic_id = 1, }; static int __init usb_stor_init(void) diff --git a/kernel/include/linux/usb/ehci_def.h b/kernel/include/linux/usb/ehci_def.h index af4b86f3..fb1d825e 100644 --- a/kernel/include/linux/usb/ehci_def.h +++ b/kernel/include/linux/usb/ehci_def.h @@ -46,7 +46,7 @@ struct ehci_caps { #define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ #define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ u8 portroute [8]; /* nibbles for routing - offset 0xC */ -} __attribute__ ((packed)); +}; /* Section 2.3 Host Controller Operational Registers */ @@ -125,7 +125,7 @@ struct ehci_regs { #define PORT_CSC (1<<1) /* connect status change */ #define PORT_CONNECT (1<<0) /* device connected */ #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) -} __attribute__ ((packed)); +}; #define USBMODE 0x68 /* USB Device mode */ #define USBMODE_SDIS (1<<3) /* Stream disable */ @@ -169,7 +169,7 @@ struct ehci_dbg_port { u32 data47; u32 address; #define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) -} __attribute__ ((packed)); +}; #ifdef CONFIG_EARLY_PRINTK_DBGP #include diff --git a/kernel/include/linux/usb/usbnet.h b/kernel/include/linux/usb/usbnet.h index f8147305..cdc4493d 100644 --- a/kernel/include/linux/usb/usbnet.h +++ b/kernel/include/linux/usb/usbnet.h @@ -171,7 +171,8 @@ extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *); enum skb_state { illegal = 0, tx_start, tx_done, - rx_start, rx_done, rx_cleanup + rx_start, rx_done, rx_cleanup, + unlink_start }; struct skb_data { /* skb->cb is one of these */