diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 38 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 7 | ||||
-rw-r--r-- | drivers/usb/core/file.c | 24 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 122 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 182 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 37 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 64 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 44 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 1 |
13 files changed, 321 insertions, 209 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index db535b0aa17..fed7f68d025 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -28,7 +28,7 @@ config USB_DEFAULT_PERSIST bool "Enable USB persist by default" default y help - Say N here if you don't want USB power session persistance + Say N here if you don't want USB power session persistence enabled by default. If you say N it will make suspended USB devices that lose power get reenumerated as if they had been unplugged, causing any mounted filesystems to be lost. The diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 71dc5d768fa..967152a63bd 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -914,10 +914,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - ctrl.bRequestType, ctrl.bRequest, - __le16_to_cpup(&ctrl.wValue), - __le16_to_cpup(&ctrl.wIndex), - __le16_to_cpup(&ctrl.wLength)); + ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, + ctrl.wIndex, ctrl.wLength); if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { @@ -1636,32 +1634,32 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) static int proc_control_compat(struct dev_state *ps, struct usbdevfs_ctrltransfer32 __user *p32) { - struct usbdevfs_ctrltransfer __user *p; - __u32 udata; - p = compat_alloc_user_space(sizeof(*p)); - if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || - get_user(udata, &p32->data) || + struct usbdevfs_ctrltransfer __user *p; + __u32 udata; + p = compat_alloc_user_space(sizeof(*p)); + if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || + get_user(udata, &p32->data) || put_user(compat_ptr(udata), &p->data)) return -EFAULT; - return proc_control(ps, p); + return proc_control(ps, p); } static int proc_bulk_compat(struct dev_state *ps, struct usbdevfs_bulktransfer32 __user *p32) { - struct usbdevfs_bulktransfer __user *p; - compat_uint_t n; - compat_caddr_t addr; + struct usbdevfs_bulktransfer __user *p; + compat_uint_t n; + compat_caddr_t addr; - p = compat_alloc_user_space(sizeof(*p)); + p = compat_alloc_user_space(sizeof(*p)); - if (get_user(n, &p32->ep) || put_user(n, &p->ep) || - get_user(n, &p32->len) || put_user(n, &p->len) || - get_user(n, &p32->timeout) || put_user(n, &p->timeout) || - get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) - return -EFAULT; + if (get_user(n, &p32->ep) || put_user(n, &p->ep) || + get_user(n, &p32->len) || put_user(n, &p->len) || + get_user(n, &p32->timeout) || put_user(n, &p->timeout) || + get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) + return -EFAULT; - return proc_bulk(ps, p); + return proc_bulk(ps, p); } static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg) { diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f7841d44fed..47aade2a5e7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1179,8 +1179,8 @@ static int usb_resume_interface(struct usb_device *udev, "reset_resume", status); } else { intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "reset_resume", driver->name); + dev_dbg(&intf->dev, "no reset_resume for driver %s?\n", + driver->name); } } else { status = driver->resume(intf); @@ -1790,6 +1790,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; + if (enable && !udev->usb2_hw_lpm_allowed) + return 0; + if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 7421888087a..ea337a718cc 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -8,7 +8,7 @@ * (C) Copyright Deti Fliegl 1999 (new USB architecture) * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) + * more docs, etc) * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) * (C) Copyright Greg Kroah-Hartman 2002-2003 @@ -27,29 +27,21 @@ static const struct file_operations *usb_minors[MAX_USB_MINORS]; static DECLARE_RWSEM(minor_rwsem); -static int usb_open(struct inode * inode, struct file * file) +static int usb_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); - const struct file_operations *c; int err = -ENODEV; - const struct file_operations *old_fops, *new_fops = NULL; + const struct file_operations *new_fops; down_read(&minor_rwsem); - c = usb_minors[minor]; + new_fops = fops_get(usb_minors[iminor(inode)]); - if (!c || !(new_fops = fops_get(c))) + if (!new_fops) goto done; - old_fops = file->f_op; - file->f_op = new_fops; + replace_fops(file, new_fops); /* Curiouser and curiouser... NULL ->open() as "no device" ? */ if (file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); + err = file->f_op->open(inode, file); done: up_read(&minor_rwsem); return err; @@ -166,7 +158,7 @@ int usb_register_dev(struct usb_interface *intf, char *temp; #ifdef CONFIG_USB_DYNAMIC_MINORS - /* + /* * We don't care what the device tries to start at, we want to start * at zero to pack the devices into the smallest available space with * no holes in the minor range. diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b9d3c43e385..dfe9d0f2297 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -215,6 +215,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto disable_pci; } + hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) && + driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0; + if (driver->flags & HCD_MEMORY) { /* EHCI, OHCI */ hcd->rsrc_start = pci_resource_start(dev, 0); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d6a8d23f047..6bffb8c87bc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -6,7 +6,7 @@ * (C) Copyright Deti Fliegl 1999 * (C) Copyright Randy Dunlap 2000 * (C) Copyright David Brownell 2000-2002 - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -40,6 +40,7 @@ #include <linux/platform_device.h> #include <linux/workqueue.h> #include <linux/pm_runtime.h> +#include <linux/types.h> #include <linux/usb.h> #include <linux/usb/hcd.h> @@ -92,10 +93,7 @@ EXPORT_SYMBOL_GPL (usb_bus_list); /* used when allocating bus numbers */ #define USB_MAXBUS 64 -struct usb_busmap { - unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; -}; -static struct usb_busmap busmap; +static DECLARE_BITMAP(busmap, USB_MAXBUS); /* used when updating list of hcds */ DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ @@ -171,7 +169,7 @@ static const u8 usb25_rh_dev_descriptor[18] = { }; /* usb 2.0 root hub device descriptor */ -static const u8 usb2_rh_dev_descriptor [18] = { +static const u8 usb2_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x00, 0x02, /* __le16 bcdUSB; v2.0 */ @@ -194,7 +192,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ /* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { +static const u8 usb11_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ 0x10, 0x01, /* __le16 bcdUSB; v1.1 */ @@ -219,7 +217,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { /* Configuration descriptors for our root hubs */ -static const u8 fs_rh_config_descriptor [] = { +static const u8 fs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ @@ -228,13 +226,13 @@ static const u8 fs_rh_config_descriptor [] = { 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0xc0, /* __u8 bmAttributes; + 0xc0, /* __u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -256,17 +254,17 @@ static const u8 fs_rh_config_descriptor [] = { 0x00, /* __u8 if_bInterfaceSubClass; */ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* __u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; -static const u8 hs_rh_config_descriptor [] = { +static const u8 hs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ @@ -275,13 +273,13 @@ static const u8 hs_rh_config_descriptor [] = { 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0xc0, /* __u8 bmAttributes; + 0xc0, /* __u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -303,12 +301,12 @@ static const u8 hs_rh_config_descriptor [] = { 0x00, /* __u8 if_bInterfaceSubClass; */ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* __u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) * see hub.c:hub_configure() for details. */ (USB_MAXCHILDREN + 1 + 7) / 8, 0x00, @@ -428,7 +426,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) char const *s; static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; - // language ids + /* language ids */ switch (id) { case 0: /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ @@ -464,7 +462,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) { struct usb_ctrlrequest *cmd; - u16 typeReq, wValue, wIndex, wLength; + u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; unsigned len = 0; int status; @@ -526,10 +524,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) */ case DeviceRequest | USB_REQ_GET_STATUS: - tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) + tbuf[0] = (device_may_wakeup(&hcd->self.root_hub->dev) << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); - tbuf [1] = 0; + tbuf[1] = 0; len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: @@ -546,7 +544,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) goto error; break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - tbuf [0] = 1; + tbuf[0] = 1; len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: @@ -609,13 +607,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) } break; case DeviceRequest | USB_REQ_GET_INTERFACE: - tbuf [0] = 0; + tbuf[0] = 0; len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_INTERFACE: break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: - // wValue == urb->dev->devaddr + /* wValue == urb->dev->devaddr */ dev_dbg (hcd->self.controller, "root hub device address %d\n", wValue); break; @@ -625,9 +623,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) /* ENDPOINT REQUESTS */ case EndpointRequest | USB_REQ_GET_STATUS: - // ENDPOINT_HALT flag - tbuf [0] = 0; - tbuf [1] = 0; + /* ENDPOINT_HALT flag */ + tbuf[0] = 0; + tbuf[1] = 0; len = 2; /* FALLTHROUGH */ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: @@ -683,7 +681,7 @@ error: if (urb->transfer_buffer_length < len) len = urb->transfer_buffer_length; urb->actual_length = len; - // always USB_DIR_IN, toward host + /* always USB_DIR_IN, toward host */ memcpy (ubuf, bufp, len); /* report whether RH hardware supports remote wakeup */ @@ -877,11 +875,11 @@ static ssize_t authorized_default_store(struct device *dev, usb_hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - usb_hcd->authorized_default = val? 1 : 0; + usb_hcd->authorized_default = val ? 1 : 0; result = size; - } - else + } else { result = -EINVAL; + } return result; } static DEVICE_ATTR_RW(authorized_default); @@ -941,12 +939,12 @@ static int usb_register_bus(struct usb_bus *bus) int busnum; mutex_lock(&usb_bus_list_lock); - busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); + busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1); if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); goto error_find_busnum; } - set_bit (busnum, busmap.busmap); + set_bit(busnum, busmap); bus->busnum = busnum; /* Add it to the local list of buses */ @@ -987,7 +985,7 @@ static void usb_deregister_bus (struct usb_bus *bus) usb_notify_remove_bus(bus); - clear_bit (bus->busnum, busmap.busmap); + clear_bit(bus->busnum, busmap); } /** @@ -1033,6 +1031,7 @@ static int register_root_hub(struct usb_hcd *hcd) dev_name(&usb_dev->dev), retval); return retval; } + usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev); } retval = usb_new_device (usb_dev); @@ -1120,21 +1119,21 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) case USB_SPEED_LOW: /* INTR only */ if (is_input) { tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + return 64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp; } else { tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + return 64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp; } case USB_SPEED_FULL: /* ISOC or INTR */ if (isoc) { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + return ((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp; } else { tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); + return 9107L + BW_HOST_DELAY + tmp; } case USB_SPEED_HIGH: /* ISOC or INTR */ - // FIXME adjust for input vs output + /* FIXME adjust for input vs output */ if (isoc) tmp = HS_NSECS_ISO (bytecount); else @@ -1651,6 +1650,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) static void __usb_hcd_giveback_urb(struct urb *urb) { struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + struct usb_anchor *anchor = urb->anchor; int status = urb->unlinked; unsigned long flags; @@ -1662,6 +1662,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) unmap_urb_for_dma(hcd, urb); usbmon_urb_complete(&hcd->self, urb, status); + usb_anchor_suspend_wakeups(anchor); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ @@ -1681,6 +1682,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) urb->complete(urb); local_irq_restore(flags); + usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); if (unlikely(atomic_read(&urb->reject))) wake_up(&usb_kill_urb_queue); @@ -1703,7 +1705,9 @@ static void usb_giveback_urb_bh(unsigned long param) urb = list_entry(local_list.next, struct urb, urb_list); list_del_init(&urb->urb_list); + bh->completing_ep = urb->ep; __usb_hcd_giveback_urb(urb); + bh->completing_ep = NULL; } /* check if there are new URBs to giveback */ @@ -1812,7 +1816,7 @@ rescan: case USB_ENDPOINT_XFER_INT: s = "-intr"; break; default: - s = "-iso"; break; + s = "-iso"; break; }; s; })); @@ -2073,8 +2077,11 @@ EXPORT_SYMBOL_GPL(usb_alloc_streams); * * Reverts a group of bulk endpoints back to not using stream IDs. * Can fail if we are given bad arguments, or HCD is broken. + * + * Return: On success, the number of allocated streams. On failure, a negative + * error code. */ -void usb_free_streams(struct usb_interface *interface, +int usb_free_streams(struct usb_interface *interface, struct usb_host_endpoint **eps, unsigned int num_eps, gfp_t mem_flags) { @@ -2085,14 +2092,14 @@ void usb_free_streams(struct usb_interface *interface, dev = interface_to_usbdev(interface); hcd = bus_to_hcd(dev->bus); if (dev->speed != USB_SPEED_SUPER) - return; + return -EINVAL; /* Streams only apply to bulk endpoints. */ for (i = 0; i < num_eps; i++) if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc)) - return; + return -EINVAL; - hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); + return hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); } EXPORT_SYMBOL_GPL(usb_free_streams); @@ -2245,7 +2252,7 @@ static void hcd_resume_work(struct work_struct *work) } /** - * usb_hcd_resume_root_hub - called by HCD to resume its root hub + * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub * * The USB host controller calls this function when its root hub is @@ -2324,15 +2331,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; - unsigned long flags; irqreturn_t rc; - /* IRQF_DISABLED doesn't work correctly with shared IRQs - * when the first handler doesn't use it. So let's just - * assume it's never used. - */ - local_irq_save(flags); - if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2340,7 +2340,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) else rc = IRQ_HANDLED; - local_irq_restore(flags); return rc; } EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2547,13 +2546,6 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, if (hcd->driver->irq) { - /* IRQF_DISABLED doesn't work as advertised when used together - * with IRQF_SHARED. As usb_hcd_irq() will always disable - * interrupts we can remove it here. - */ - if (irqflags & IRQF_SHARED) - irqflags &= ~IRQF_DISABLED; - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); retval = request_irq(irqnum, &usb_hcd_irq, irqflags, @@ -2600,7 +2592,7 @@ int usb_add_hcd(struct usb_hcd *hcd, /* Keep old behaviour if authorized_default is not in [0, 1]. */ if (authorized_default < 0 || authorized_default > 1) - hcd->authorized_default = hcd->wireless? 0 : 1; + hcd->authorized_default = hcd->wireless ? 0 : 1; else hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -2743,7 +2735,7 @@ err_allocate_root_hub: err_register_bus: hcd_buffer_destroy(hcd); return retval; -} +} EXPORT_SYMBOL_GPL(usb_add_hcd); /** @@ -2818,7 +2810,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) EXPORT_SYMBOL_GPL(usb_remove_hcd); void -usb_hcd_platform_shutdown(struct platform_device* dev) +usb_hcd_platform_shutdown(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -2840,7 +2832,7 @@ struct usb_mon_operations *mon_ops; * Notice that the code is minimally error-proof. Because usbmon needs * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. */ - + int usb_mon_register (struct usb_mon_operations *ops) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e6b682c6c23..06cec635e70 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -120,7 +120,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus) if (hub_is_superspeed(hub->hdev)) return "5.0 Gb/s"; if (portstatus & USB_PORT_STAT_HIGH_SPEED) - return "480 Mb/s"; + return "480 Mb/s"; else if (portstatus & USB_PORT_STAT_LOW_SPEED) return "1.5 Mb/s"; else @@ -135,7 +135,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) return usb_get_intfdata(hdev->actconfig->interface[0]); } -static int usb_device_supports_lpm(struct usb_device *udev) +int usb_device_supports_lpm(struct usb_device *udev) { /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. @@ -156,6 +156,11 @@ static int usb_device_supports_lpm(struct usb_device *udev) "Power management will be impacted.\n"); return 0; } + + /* udev is root hub */ + if (!udev->parent) + return 1; + if (udev->parent->lpm_capable) return 1; @@ -310,9 +315,9 @@ static void usb_set_lpm_parameters(struct usb_device *udev) return; udev_u1_del = udev->bos->ss_cap->bU1devExitLat; - udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; + udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat); hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; - hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; + hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat); usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del, hub, &udev->parent->u1_params, hub_u1_del); @@ -433,7 +438,7 @@ static void set_port_led( case HUB_LED_OFF: s = "off"; break; case HUB_LED_AUTO: s = "auto"; break; default: s = "??"; break; - }; s; }), + } s; }), status); } @@ -857,7 +862,7 @@ static int hub_hub_status(struct usb_hub *hub, "%s failed (err = %d)\n", __func__, ret); } else { *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); + *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } mutex_unlock(&hub->status_mutex); @@ -956,7 +961,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) */ set_bit(port1, hub->change_bits); - kick_khubd(hub); + kick_khubd(hub); } /** @@ -1107,16 +1112,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* * USB3 protocol ports will automatically transition * to Enabled state when detect an USB3.0 device attach. - * Do not disable USB3 protocol ports. + * Do not disable USB3 protocol ports, just pretend + * power was lost */ - if (!hub_is_superspeed(hdev)) { + portstatus &= ~USB_PORT_STAT_ENABLE; + if (!hub_is_superspeed(hdev)) usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); - portstatus &= ~USB_PORT_STAT_ENABLE; - } else { - /* Pretend that power was lost for USB3 devs */ - portstatus &= ~USB_PORT_STAT_ENABLE; - } } /* Clear status-change flags; we'll debounce later */ @@ -1130,6 +1132,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } + if (portchange & USB_PORT_STAT_C_RESET) { + need_debounce_delay = true; + usb_clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_RESET); + } if ((portchange & USB_PORT_STAT_C_BH_RESET) && hub_is_superspeed(hub->hdev)) { need_debounce_delay = true; @@ -1361,7 +1368,7 @@ static int hub_configure(struct usb_hub *hub, if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && !(hub_is_superspeed(hdev))) { int i; - char portstr [USB_MAXCHILDREN + 1]; + char portstr[USB_MAXCHILDREN + 1]; for (i = 0; i < hdev->maxchild; i++) portstr[i] = hub->descriptor->u.hs.DeviceRemovable @@ -1429,32 +1436,32 @@ static int hub_configure(struct usb_hub *hub, /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ switch (wHubCharacteristics & HUB_CHAR_TTTT) { - case HUB_TTTT_8_BITS: - if (hdev->descriptor.bDeviceProtocol != 0) { - hub->tt.think_time = 666; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 8, hub->tt.think_time); - } - break; - case HUB_TTTT_16_BITS: - hub->tt.think_time = 666 * 2; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 16, hub->tt.think_time); - break; - case HUB_TTTT_24_BITS: - hub->tt.think_time = 666 * 3; + case HUB_TTTT_8_BITS: + if (hdev->descriptor.bDeviceProtocol != 0) { + hub->tt.think_time = 666; dev_dbg(hub_dev, "TT requires at most %d " "FS bit times (%d ns)\n", - 24, hub->tt.think_time); - break; - case HUB_TTTT_32_BITS: - hub->tt.think_time = 666 * 4; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 32, hub->tt.think_time); - break; + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + dev_dbg(hub_dev, "TT requires at most %d " + "FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; } /* probe() zeroes hub->indicator[] */ @@ -1560,7 +1567,7 @@ static int hub_configure(struct usb_hub *hub, /* maybe cycle the hub leds */ if (hub->has_indicators && blinkenlights) - hub->indicator [0] = INDICATOR_CYCLE; + hub->indicator[0] = INDICATOR_CYCLE; for (i = 0; i < hdev->maxchild; i++) { ret = usb_hub_create_port_device(hub, i + 1); @@ -1978,7 +1985,7 @@ static void choose_devnum(struct usb_device *udev) if (devnum >= 128) devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1); } if (devnum < 128) { set_bit(devnum, bus->devmap.devicemap); @@ -2018,8 +2025,8 @@ static void hub_free_dev(struct usb_device *udev) * Something got disconnected. Get rid of it and all of its children. * * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then this routine will acquire the - * usb_bus_list_lock on behalf of the caller. + * If *pdev is a root hub then the caller must hold the usb_bus_list_lock, + * which protects the set of root hubs as well as the list of buses. * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -2232,8 +2239,7 @@ static int usb_enumerate_device(struct usb_device *udev) udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - } - else { + } else { /* read the standard strings and cache them if present */ udev->product = usb_cache_string(udev, udev->descriptor.iProduct); udev->manufacturer = usb_cache_string(udev, @@ -2489,7 +2495,7 @@ error_device_descriptor: usb_autosuspend_device(usb_dev); error_autoresume: out_authorized: - usb_unlock_device(usb_dev); // complements locktree + usb_unlock_device(usb_dev); /* complements locktree */ return result; } @@ -3108,8 +3114,8 @@ static int finish_port_resume(struct usb_device *udev) retry_reset_resume: status = usb_reset_and_verify_device(udev); - /* 10.5.4.5 says be sure devices in the tree are still there. - * For now let's assume the device didn't go crazy on resume, + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, * and device drivers will know about any resume quirks. */ if (status == 0) { @@ -3211,7 +3217,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) if (status == 0 && !port_is_suspended(hub, portstatus)) goto SuspendCleared; - // dev_dbg(hub->intfdev, "resume port %d\n", port1); + /* dev_dbg(hub->intfdev, "resume port %d\n", port1); */ set_bit(port1, hub->busy_bits); @@ -3855,7 +3861,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. - * + * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. @@ -3949,6 +3955,32 @@ static int hub_set_address(struct usb_device *udev, int devnum) return retval; } +/* + * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM + * when they're plugged into a USB 2.0 port, but they don't work when LPM is + * enabled. + * + * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the + * device says it supports the new USB 2.0 Link PM errata by setting the BESL + * support bit in the BOS descriptor. + */ +static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) +{ + int connect_type; + + if (!udev->usb2_hw_lpm_capable) + return; + + connect_type = usb_get_hub_port_connect_type(udev->parent, + udev->portnum); + + if ((udev->bos->ext_cap->bmAttributes & USB_BESL_SUPPORT) || + connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { + udev->usb2_hw_lpm_allowed = 1; + usb_set_usb2_hardware_lpm(udev, 1); + } +} + /* Reset device, (re)assign address, get device descriptor. * Device connection must be stable, no more debouncing needed. * Returns device in USB_STATE_ADDRESS, except on error. @@ -4055,7 +4087,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->tt = &hub->tt; udev->ttport = port1; } - + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. @@ -4130,11 +4162,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, #undef GET_DESCRIPTOR_BUFSIZE } - /* - * If device is WUSB, we already assigned an - * unauthorized address in the Connect Ack sequence; - * authorization will assign the final address. - */ + /* + * If device is WUSB, we already assigned an + * unauthorized address in the Connect Ack sequence; + * authorization will assign the final address. + */ if (udev->wusb == 0) { for (j = 0; j < SET_ADDRESS_TRIES; ++j) { retval = hub_set_address(udev, devnum); @@ -4163,7 +4195,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, msleep(10); if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) break; - } + } retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { @@ -4219,7 +4251,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } - + retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { if (retval != -ENODEV) @@ -4242,6 +4274,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); + hub_set_initial_usb2_lpm_policy(udev); fail: if (retval) { hub_port_disable(hub, port1, 0); @@ -4316,7 +4349,7 @@ hub_power_remaining (struct usb_hub *hub) } if (remaining < 0) { dev_warn(hub->intfdev, "%dmA over power budget!\n", - - remaining); + -remaining); remaining = 0; } return remaining; @@ -4427,7 +4460,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); if (portstatus & USB_PORT_STAT_ENABLE) - goto done; + goto done; return; } if (hub_is_superspeed(hub->hdev)) @@ -4450,7 +4483,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, } usb_set_device_state(udev, USB_STATE_POWERED); - udev->bus_mA = hub->mA_per_port; + udev->bus_mA = hub->mA_per_port; udev->level = hdev->level + 1; udev->wusb = hub_is_wusb(hub); @@ -4504,7 +4537,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, goto loop_disable; } } - + /* check for devices running slower than they could */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL @@ -4564,7 +4597,7 @@ loop: dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); } - + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) @@ -4729,7 +4762,7 @@ static void hub_events(void) * EM interference sometimes causes badly * shielded USB devices to be shutdown by * the hub, this hack enables them again. - * Works at least with mouse driver. + * Works at least with mouse driver. */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change @@ -4841,7 +4874,7 @@ static void hub_events(void) dev_dbg(hub_dev, "over-current change\n"); clear_hub_feature(hdev, C_HUB_OVER_CURRENT); msleep(500); /* Cool down */ - hub_power_on(hub, true); + hub_power_on(hub, true); hub_hub_status(hub, &status, &unused); if (status & HUB_STATUS_OVERCURRENT) dev_err(hub_dev, "over-current " @@ -4861,7 +4894,7 @@ static void hub_events(void) usb_unlock_device(hdev); kref_put(&hub->kref, hub_release); - } /* end while (1) */ + } /* end while (1) */ } static int hub_thread(void *__unused) @@ -4886,7 +4919,7 @@ static int hub_thread(void *__unused) static const struct usb_device_id hub_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_VENDOR - | USB_DEVICE_ID_MATCH_INT_CLASS, + | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = USB_VENDOR_GENESYS_LOGIC, .bInterfaceClass = USB_CLASS_HUB, .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, @@ -5086,6 +5119,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) } parent_hub = usb_hub_to_struct_hub(parent_hdev); + /* Disable USB2 hardware LPM. + * It will be re-enabled by the enumeration process. + */ + if (udev->usb2_hw_lpm_enabled == 1) + usb_set_usb2_hardware_lpm(udev, 0); + bos = udev->bos; udev->bos = NULL; @@ -5120,13 +5159,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (ret < 0) goto re_enumerate; - + /* Device might have changed firmware (DFU or similar) */ if (descriptors_changed(udev, &descriptor, bos)) { dev_info(&udev->dev, "device firmware changed\n"); udev->descriptor = descriptor; /* for disconnect() calls */ goto re_enumerate; - } + } /* Restore the device's previous configuration */ if (!udev->actconfig) @@ -5151,7 +5190,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) udev->actconfig->desc.bConfigurationValue, ret); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; - } + } mutex_unlock(hcd->bandwidth_mutex); usb_set_device_state(udev, USB_STATE_CONFIGURED); @@ -5193,12 +5232,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ + usb_set_usb2_hardware_lpm(udev, 1); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); udev->bos = bos; return 0; - + re_enumerate: /* LPM state doesn't matter when we're about to destroy the device. */ hub_port_logical_disconnect(parent_hub, port1); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 82927e1ed27..bb315970e47 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1182,8 +1182,12 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) put_device(&dev->actconfig->interface[i]->dev); dev->actconfig->interface[i] = NULL; } + + if (dev->usb2_hw_lpm_enabled == 1) + usb_set_usb2_hardware_lpm(dev, 0); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); + dev->actconfig = NULL; if (dev->state == USB_STATE_CONFIGURED) usb_set_device_state(dev, USB_STATE_ADDRESS); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 01fe36273f3..12924dbfdc2 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -13,6 +13,7 @@ #include <linux/usb.h> #include <linux/usb/quirks.h> +#include <linux/usb/hcd.h> #include "usb.h" /* Lists of quirky USB devices, split in device quirks and interface quirks. @@ -161,6 +162,21 @@ static const struct usb_device_id usb_interface_quirk_list[] = { { } /* terminating entry must be last */ }; +static const struct usb_device_id usb_amd_resume_quirk_list[] = { + /* Lenovo Mouse with Pixart controller */ + { USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Pixart Mouse */ + { USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Optical Mouse M90/M100 */ + { USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME }, + + { } /* terminating entry must be last */ +}; + static bool usb_match_any_interface(struct usb_device *udev, const struct usb_device_id *id) { @@ -187,6 +203,18 @@ static bool usb_match_any_interface(struct usb_device *udev, return false; } +static int usb_amd_resume_quirk(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + hcd = bus_to_hcd(udev->bus); + /* The device should be attached directly to root hub */ + if (udev->level == 1 && hcd->amd_resume_bug == 1) + return 1; + + return 0; +} + static u32 __usb_detect_quirks(struct usb_device *udev, const struct usb_device_id *id) { @@ -212,6 +240,15 @@ static u32 __usb_detect_quirks(struct usb_device *udev, void usb_detect_quirks(struct usb_device *udev) { udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); + + /* + * Pixart-based mice would trigger remote wakeup issue on AMD + * Yangtze chipset, so set them as RESET_RESUME flag. + */ + if (usb_amd_resume_quirk(udev)) + udev->quirks |= __usb_detect_quirks(udev, + usb_amd_resume_quirk_list); + if (udev->quirks) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 6d2c8edb1ff..52a97adf02a 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -23,14 +23,16 @@ static ssize_t field##_show(struct device *dev, \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ + ssize_t rc = 0; \ \ udev = to_usb_device(dev); \ + usb_lock_device(udev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf(buf, format_string, \ + rc = sprintf(buf, format_string, \ actconfig->desc.field); \ - else \ - return 0; \ + usb_unlock_device(udev); \ + return rc; \ } \ #define usb_actconfig_attr(field, format_string) \ @@ -45,12 +47,15 @@ static ssize_t bMaxPower_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if (!actconfig) - return 0; - return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + if (actconfig) + rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + usb_unlock_device(udev); + return rc; } static DEVICE_ATTR_RO(bMaxPower); @@ -59,12 +64,15 @@ static ssize_t configuration_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; + ssize_t rc = 0; udev = to_usb_device(dev); + usb_lock_device(udev); actconfig = udev->actconfig; - if ((!actconfig) || (!actconfig->string)) - return 0; - return sprintf(buf, "%s\n", actconfig->string); + if (actconfig && actconfig->string) + rc = sprintf(buf, "%s\n", actconfig->string); + usb_unlock_device(udev); + return rc; } static DEVICE_ATTR_RO(configuration); @@ -390,7 +398,8 @@ static DEVICE_ATTR_RW(autosuspend); static const char on_string[] = "on"; static const char auto_string[] = "auto"; -static void warn_level(void) { +static void warn_level(void) +{ static int level_warned; if (!level_warned) { @@ -449,7 +458,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev, struct usb_device *udev = to_usb_device(dev); const char *p; - if (udev->usb2_hw_lpm_enabled == 1) + if (udev->usb2_hw_lpm_allowed == 1) p = "enabled"; else p = "disabled"; @@ -469,8 +478,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, ret = strtobool(buf, &value); - if (!ret) + if (!ret) { + udev->usb2_hw_lpm_allowed = value; ret = usb_set_usb2_hardware_lpm(udev, value); + } usb_unlock_device(udev); @@ -644,7 +655,7 @@ static ssize_t authorized_store(struct device *dev, result = usb_deauthorize_device(usb_dev); else result = usb_authorize_device(usb_dev); - return result < 0? result : size; + return result < 0 ? result : size; } static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR, authorized_show, authorized_store); @@ -764,6 +775,7 @@ read_descriptors(struct file *filp, struct kobject *kobj, * Following that are the raw descriptor entries for all the * configurations (config plus subsidiary descriptors). */ + usb_lock_device(udev); for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && nleft > 0; ++cfgno) { if (cfgno < 0) { @@ -784,6 +796,7 @@ read_descriptors(struct file *filp, struct kobject *kobj, off -= srclen; } } + usb_unlock_device(udev); return count - nleft; } @@ -870,9 +883,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr, char *string; intf = to_usb_interface(dev); - string = intf->cur_altsetting->string; - barrier(); /* The altsetting might change! */ - + string = ACCESS_ONCE(intf->cur_altsetting->string); if (!string) return 0; return sprintf(buf, "%s\n", string); @@ -888,7 +899,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; + alt = ACCESS_ONCE(intf->cur_altsetting); return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" "ic%02Xisc%02Xip%02Xin%02X\n", @@ -909,23 +920,14 @@ static ssize_t supports_autosuspend_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_interface *intf; - struct usb_device *udev; - int ret; + int s; - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); - - usb_lock_device(udev); + device_lock(dev); /* Devices will be autosuspended even when an interface isn't claimed */ - if (!intf->dev.driver || - to_usb_driver(intf->dev.driver)->supports_autosuspend) - ret = sprintf(buf, "%u\n", 1); - else - ret = sprintf(buf, "%u\n", 0); - usb_unlock_device(udev); + s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); + device_unlock(dev); - return ret; + return sprintf(buf, "%u\n", s); } static DEVICE_ATTR_RO(supports_autosuspend); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c12bc790a6a..e62208356c8 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -138,13 +138,19 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) } EXPORT_SYMBOL_GPL(usb_anchor_urb); +static int usb_anchor_check_wakeup(struct usb_anchor *anchor) +{ + return atomic_read(&anchor->suspend_wakeups) == 0 && + list_empty(&anchor->urb_list); +} + /* Callers must hold anchor->lock */ static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor) { urb->anchor = NULL; list_del(&urb->anchor_list); usb_put_urb(urb); - if (list_empty(&anchor->urb_list)) + if (usb_anchor_check_wakeup(anchor)) wake_up(&anchor->wait); } @@ -846,6 +852,39 @@ void usb_unlink_anchored_urbs(struct usb_anchor *anchor) EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); /** + * usb_anchor_suspend_wakeups + * @anchor: the anchor you want to suspend wakeups on + * + * Call this to stop the last urb being unanchored from waking up any + * usb_wait_anchor_empty_timeout waiters. This is used in the hcd urb give- + * back path to delay waking up until after the completion handler has run. + */ +void usb_anchor_suspend_wakeups(struct usb_anchor *anchor) +{ + if (anchor) + atomic_inc(&anchor->suspend_wakeups); +} +EXPORT_SYMBOL_GPL(usb_anchor_suspend_wakeups); + +/** + * usb_anchor_resume_wakeups + * @anchor: the anchor you want to resume wakeups on + * + * Allow usb_wait_anchor_empty_timeout waiters to be woken up again, and + * wake up any current waiters if the anchor is empty. + */ +void usb_anchor_resume_wakeups(struct usb_anchor *anchor) +{ + if (!anchor) + return; + + atomic_dec(&anchor->suspend_wakeups); + if (usb_anchor_check_wakeup(anchor)) + wake_up(&anchor->wait); +} +EXPORT_SYMBOL_GPL(usb_anchor_resume_wakeups); + +/** * usb_wait_anchor_empty_timeout - wait for an anchor to be unused * @anchor: the anchor you want to become unused * @timeout: how long you are willing to wait in milliseconds @@ -858,7 +897,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout) { - return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list), + return wait_event_timeout(anchor->wait, + usb_anchor_check_wakeup(anchor), msecs_to_jiffies(timeout)); } EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0a6ee2e70b2..4d1144990d4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -497,7 +497,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->authorized = 1; else { dev->authorized = usb_hcd->authorized_default; - dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; } return dev; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 823857767a1..c49383669cd 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -35,6 +35,7 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern int usb_get_bos_descriptor(struct usb_device *dev); extern void usb_release_bos_descriptor(struct usb_device *dev); +extern int usb_device_supports_lpm(struct usb_device *udev); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_choose_configuration(struct usb_device *udev); |