diff options
author | Scott Wood <scottwood@freescale.com> | 2015-02-13 22:12:06 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2015-02-13 22:19:22 (GMT) |
commit | 6faa2909871d8937cb2f79a10e1b21ffe193fac1 (patch) | |
tree | f558a94f1553814cc122ab8d9e04c0ebad5262a5 /drivers/usb/core | |
parent | fcb2fb84301c673ee15ca04e7a2fc965712d49a0 (diff) | |
download | linux-fsl-qoriq-6faa2909871d8937cb2f79a10e1b21ffe193fac1.tar.xz |
Reset to 3.12.37
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/config.c | 11 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 103 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 104 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 28 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 2 |
8 files changed, 207 insertions, 57 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 6524383..98cb096 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -201,6 +201,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, if (n == 0) n = 9; /* 32 ms = 2^(9-1) uframes */ j = 16; + + /* + * Adjust bInterval for quirked devices. + * This quirk fixes bIntervals reported in + * linear microframes. + */ + if (to_usb_device(ddev)->quirks & + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) { + n = clamp(fls(d->bInterval), i, j); + i = j = n; + } break; default: /* USB_SPEED_FULL or _LOW */ /* For low-speed, 10 ms is the official minimum. diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 71dc5d7..31ffd84 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1413,7 +1413,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, u = (is_in ? URB_DIR_IN : URB_DIR_OUT); if (uurb->flags & USBDEVFS_URB_ISO_ASAP) u |= URB_ISO_ASAP; - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) u |= URB_SHORT_NOT_OK; if (uurb->flags & USBDEVFS_URB_NO_FSBR) u |= URB_NO_FSBR; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 689433c..bfddeb3 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -959,8 +959,7 @@ EXPORT_SYMBOL_GPL(usb_deregister); * it doesn't support pre_reset/post_reset/reset_resume or * because it doesn't support suspend/resume. * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock. */ void usb_forced_unbind_intf(struct usb_interface *intf) { @@ -973,16 +972,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf) intf->needs_binding = 1; } +/* + * Unbind drivers for @udev's marked interfaces. These interfaces have + * the needs_binding flag set, for example by usb_resume_interface(). + * + * The caller must hold @udev's device lock. + */ +static void unbind_marked_interfaces(struct usb_device *udev) +{ + struct usb_host_config *config; + int i; + struct usb_interface *intf; + + config = udev->actconfig; + if (config) { + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intf = config->interface[i]; + if (intf->dev.driver && intf->needs_binding) + usb_forced_unbind_intf(intf); + } + } +} + /* Delayed forced unbinding of a USB interface driver and scan * for rebinding. * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock. * * Note: Rebinds will be skipped if a system sleep transition is in * progress and the PM "complete" callback hasn't occurred yet. */ -void usb_rebind_intf(struct usb_interface *intf) +static void usb_rebind_intf(struct usb_interface *intf) { int rc; @@ -999,68 +1019,66 @@ void usb_rebind_intf(struct usb_interface *intf) } } -#ifdef CONFIG_PM - -/* Unbind drivers for @udev's interfaces that don't support suspend/resume - * There is no check for reset_resume here because it can be determined - * only during resume whether reset_resume is needed. +/* + * Rebind drivers to @udev's marked interfaces. These interfaces have + * the needs_binding flag set. * * The caller must hold @udev's device lock. */ -static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) +static void rebind_marked_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; - struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - - if (intf->dev.driver) { - drv = to_usb_driver(intf->dev.driver); - if (!drv->suspend || !drv->resume) - usb_forced_unbind_intf(intf); - } + if (intf->needs_binding) + usb_rebind_intf(intf); } } } -/* Unbind drivers for @udev's interfaces that failed to support reset-resume. - * These interfaces have the needs_binding flag set by usb_resume_interface(). +/* + * Unbind all of @udev's marked interfaces and then rebind all of them. + * This ordering is necessary because some drivers claim several interfaces + * when they are first probed. * * The caller must hold @udev's device lock. */ -static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) +void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev) { - struct usb_host_config *config; - int i; - struct usb_interface *intf; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - if (intf->dev.driver && intf->needs_binding) - usb_forced_unbind_intf(intf); - } - } + unbind_marked_interfaces(udev); + rebind_marked_interfaces(udev); } -static void do_rebind_interfaces(struct usb_device *udev) +#ifdef CONFIG_PM + +/* Unbind drivers for @udev's interfaces that don't support suspend/resume + * There is no check for reset_resume here because it can be determined + * only during resume whether reset_resume is needed. + * + * The caller must hold @udev's device lock. + */ +static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; + struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - if (intf->needs_binding) - usb_rebind_intf(intf); + + if (intf->dev.driver) { + drv = to_usb_driver(intf->dev.driver); + if (!drv->suspend || !drv->resume) + usb_forced_unbind_intf(intf); + } } } } @@ -1389,7 +1407,7 @@ int usb_resume_complete(struct device *dev) * whose needs_binding flag is set */ if (udev->state != USB_STATE_NOTATTACHED) - do_rebind_interfaces(udev); + rebind_marked_interfaces(udev); return 0; } @@ -1411,7 +1429,7 @@ int usb_resume(struct device *dev, pm_message_t msg) pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); - unbind_no_reset_resume_drivers_interfaces(udev); + unbind_marked_interfaces(udev); } /* Avoid PM error messages for devices disconnected while suspended @@ -1752,10 +1770,13 @@ int usb_runtime_suspend(struct device *dev) if (status == -EAGAIN || status == -EBUSY) usb_mark_last_busy(udev); - /* The PM core reacts badly unless the return code is 0, - * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. + /* + * The PM core reacts badly unless the return code is 0, + * -EAGAIN, or -EBUSY, so always return -EBUSY on an error + * (except for root hubs, because they don't suspend through + * an upstream port like other USB devices). */ - if (status != 0) + if (status != 0 && udev->parent) return -EBUSY; return status; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b9d3c43..5e1a179 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -75,7 +75,7 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, PCI_SLOT(companion->devfn) != slot) continue; companion_hcd = pci_get_drvdata(companion); - if (!companion_hcd) + if (!companion_hcd || !companion_hcd->self.root_hub) continue; fn(pdev, hcd, companion, companion_hcd); } @@ -377,6 +377,8 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && hcd->driver->shutdown) { hcd->driver->shutdown(hcd); + if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) + free_irq(hcd->irq, hcd); pci_disable_device(dev); } } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bf21a21..830063c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1677,9 +1677,9 @@ static void __usb_hcd_giveback_urb(struct urb *urb) * and no one may trigger the above deadlock situation when * running complete() in tasklet. */ - local_irq_save_nort(flags); + local_irq_save(flags); urb->complete(urb); - local_irq_restore_nort(flags); + local_irq_restore(flags); atomic_dec(&urb->use_count); if (unlikely(atomic_read(&urb->reject))) @@ -2053,6 +2053,8 @@ int usb_alloc_streams(struct usb_interface *interface, return -EINVAL; if (dev->speed != USB_SPEED_SUPER) return -EINVAL; + if (dev->state < USB_STATE_CONFIGURED) + return -ENODEV; /* Streams only apply to bulk endpoints. */ for (i = 0; i < num_eps; i++) @@ -2331,7 +2333,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) * when the first handler doesn't use it. So let's just * assume it's never used. */ - local_irq_save_nort(flags); + local_irq_save(flags); if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; @@ -2340,7 +2342,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) else rc = IRQ_HANDLED; - local_irq_restore_nort(flags); + local_irq_restore(flags); return rc; } EXPORT_SYMBOL_GPL(usb_hcd_irq); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3670086..420bf9b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -891,6 +891,25 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) if (!hub_is_superspeed(hub->hdev)) return -EINVAL; + ret = hub_port_status(hub, port1, &portstatus, &portchange); + if (ret < 0) + return ret; + + /* + * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI + * Controller [1022:7814] will have spurious result making the following + * usb 3.0 device hotplugging route to the 2.0 root hub and recognized + * as high-speed device if we set the usb 3.0 port link state to + * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we + * check the state here to avoid the bug. + */ + if ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_RX_DETECT) { + dev_dbg(&hub->ports[port1 - 1]->dev, + "Not disabling port; link state is RxDetect\n"); + return ret; + } + ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); if (ret) return ret; @@ -1152,7 +1171,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Tell khubd to disconnect the device or * check for a new connection */ - if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) + if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portstatus & USB_PORT_STAT_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1685,11 +1705,28 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) * - Change autosuspend delay of hub can avoid unnecessary auto * suspend timer for hub, also may decrease power consumption * of USB bus. + * + * - If user has indicated to prevent autosuspend by passing + * usbcore.autosuspend = -1 then keep autosuspend disabled. + */ +#ifdef CONFIG_PM_RUNTIME + if (hdev->dev.power.autosuspend_delay >= 0) + pm_runtime_set_autosuspend_delay(&hdev->dev, 0); +#endif + + /* + * Hubs have proper suspend/resume support, except for root hubs + * where the controller driver doesn't have bus_suspend and + * bus_resume methods. */ - pm_runtime_set_autosuspend_delay(&hdev->dev, 0); + if (hdev->parent) { /* normal device */ + usb_enable_autosuspend(hdev); + } else { /* root hub */ + const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; - /* Hubs have proper suspend/resume support. */ - usb_enable_autosuspend(hdev); + if (drv->bus_suspend && drv->bus_resume) + usb_enable_autosuspend(hdev); + } if (hdev->level == MAX_TOPO_LEVEL) { dev_err(&intf->dev, @@ -1921,8 +1958,10 @@ void usb_set_device_state(struct usb_device *udev, || new_state == USB_STATE_SUSPENDED) ; /* No change to wakeup settings */ else if (new_state == USB_STATE_CONFIGURED) - wakeup = udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP; + wakeup = (udev->quirks & + USB_QUIRK_IGNORE_REMOTE_WAKEUP) ? 0 : + udev->actconfig->desc.bmAttributes & + USB_CONFIG_ATT_WAKEUP; else wakeup = 0; } @@ -3138,6 +3177,43 @@ static int finish_port_resume(struct usb_device *udev) } /* + * There are some SS USB devices which take longer time for link training. + * XHCI specs 4.19.4 says that when Link training is successful, port + * sets CSC bit to 1. So if SW reads port status before successful link + * training, then it will not find device to be present. + * USB Analyzer log with such buggy devices show that in some cases + * device switch on the RX termination after long delay of host enabling + * the VBUS. In few other cases it has been seen that device fails to + * negotiate link training in first attempt. It has been + * reported till now that few devices take as long as 2000 ms to train + * the link after host enabling its VBUS and termination. Following + * routine implements a 2000 ms timeout for link training. If in a case + * link trains before timeout, loop will exit earlier. + * + * FIXME: If a device was connected before suspend, but was removed + * while system was asleep, then the loop in the following routine will + * only exit at timeout. + * + * This routine should only be called when persist is enabled for a SS + * device. + */ +static int wait_for_ss_port_enable(struct usb_device *udev, + struct usb_hub *hub, int *port1, + u16 *portchange, u16 *portstatus) +{ + int status = 0, delay_ms = 0; + + while (delay_ms < 2000) { + if (status || *portstatus & USB_PORT_STAT_CONNECTION) + break; + msleep(20); + delay_ms += 20; + status = hub_port_status(hub, *port1, portstatus, portchange); + } + return status; +} + +/* * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate, not a root hub * Context: must be able to sleep; device not locked; pm locks held @@ -3239,6 +3315,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) clear_bit(port1, hub->busy_bits); + if (udev->persist_enabled && hub_is_superspeed(hub->hdev)) + status = wait_for_ss_port_enable(udev, hub, &port1, &portchange, + &portstatus); + status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) @@ -4267,6 +4347,9 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) struct usb_qualifier_descriptor *qual; int status; + if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER) + return; + qual = kmalloc (sizeof *qual, GFP_KERNEL); if (qual == NULL) return; @@ -4655,9 +4738,10 @@ static void hub_events(void) hub = list_entry(tmp, struct usb_hub, event_list); kref_get(&hub->kref); + hdev = hub->hdev; + usb_get_dev(hdev); spin_unlock_irq(&hub_event_lock); - hdev = hub->hdev; hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", @@ -4870,6 +4954,7 @@ static void hub_events(void) usb_autopm_put_interface(intf); loop_disconnected: usb_unlock_device(hdev); + usb_put_dev(hdev); kref_put(&hub->kref, hub_release); } /* end while (1) */ @@ -5308,10 +5393,11 @@ int usb_reset_device(struct usb_device *udev) else if (cintf->condition == USB_INTERFACE_BOUND) rebind = 1; + if (rebind) + cintf->needs_binding = 1; } - if (ret == 0 && rebind) - usb_rebind_intf(cintf); } + usb_unbind_and_rebind_marked_interfaces(udev); } usb_autosuspend_device(udev); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 1053eb6..aa77595 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Microsoft Wireless Laser Mouse 6000 Receiver */ + { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -92,6 +95,16 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04e8, 0x6601), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Elan Touchscreen */ + { USB_DEVICE(0x04f3, 0x0089), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + + { USB_DEVICE(0x04f3, 0x009b), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + + { USB_DEVICE(0x04f3, 0x016f), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -147,6 +160,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Razer - Razer Blade Keyboard */ + { USB_DEVICE(0x1532, 0x0116), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* BUILDWIN Photo Frame */ { USB_DEVICE(0x1908, 0x1315), .driver_info = USB_QUIRK_HONOR_BNUMINTERFACES }, @@ -154,6 +171,13 @@ static const struct usb_device_id usb_quirk_list[] = { /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + /* USB3503 */ + { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* ASUS Base Station(T100) */ + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + { } /* terminating entry must be last */ }; @@ -162,6 +186,10 @@ static const struct usb_device_id usb_interface_quirk_list[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0), .driver_info = USB_QUIRK_RESET_RESUME }, + /* ASUS Base Station(T100) */ + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 8238577..0923add7 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -55,7 +55,7 @@ extern int usb_match_one_id_intf(struct usb_device *dev, extern int usb_match_device(struct usb_device *dev, const struct usb_device_id *id); extern void usb_forced_unbind_intf(struct usb_interface *intf); -extern void usb_rebind_intf(struct usb_interface *intf); +extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, struct dev_state *owner); |