diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/devio.c | 191 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 36 | ||||
-rw-r--r-- | drivers/usb/core/file.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 9 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 37 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 127 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 31 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 5 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 14 |
11 files changed, 242 insertions, 218 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e3beaf229ee..8df4b76465a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -86,13 +86,14 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + unsigned int mem_usage; int status; u32 secid; u8 bulk_addr; u8 bulk_status; }; -static int usbfs_snoop; +static bool usbfs_snoop; module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); @@ -108,8 +109,44 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) -#define MAX_USBFS_BUFFER_SIZE 16384 +/* Limit on the total amount of memory we can allocate for transfers */ +static unsigned usbfs_memory_mb = 16; +module_param(usbfs_memory_mb, uint, 0644); +MODULE_PARM_DESC(usbfs_memory_mb, + "maximum MB allowed for usbfs buffers (0 = no limit)"); +/* Hard limit, necessary to avoid aithmetic overflow */ +#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) + +static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ + +/* Check whether it's okay to allocate more memory for a transfer */ +static int usbfs_increase_memory_usage(unsigned amount) +{ + unsigned lim; + + /* + * Convert usbfs_memory_mb to bytes, avoiding overflows. + * 0 means use the hard limit (effectively unlimited). + */ + lim = ACCESS_ONCE(usbfs_memory_mb); + if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) + lim = USBFS_XFER_MAX; + else + lim <<= 20; + + atomic_add(amount, &usbfs_memory_usage); + if (atomic_read(&usbfs_memory_usage) <= lim) + return 0; + atomic_sub(amount, &usbfs_memory_usage); + return -ENOMEM; +} + +/* Memory for a transfer is being deallocated */ +static void usbfs_decrease_memory_usage(unsigned amount) +{ + atomic_sub(amount, &usbfs_memory_usage); +} static int connected(struct dev_state *ps) { @@ -249,10 +286,12 @@ static struct async *alloc_async(unsigned int numisoframes) static void free_async(struct async *as) { put_pid(as->pid); - put_cred(as->cred); + if (as->cred) + put_cred(as->cred); kfree(as->urb->transfer_buffer); kfree(as->urb->setup_packet); usb_free_urb(as->urb); + usbfs_decrease_memory_usage(as->mem_usage); kfree(as); } @@ -792,9 +831,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ if (wLength > PAGE_SIZE) return -EINVAL; + ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + + sizeof(struct usb_ctrlrequest)); + if (ret) + return ret; tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); - if (!tbuf) - return -ENOMEM; + if (!tbuf) { + ret = -ENOMEM; + goto done; + } tmo = ctrl.timeout; snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " @@ -806,8 +851,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } pipe = usb_rcvctrlpipe(dev, 0); snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); @@ -821,15 +866,15 @@ static int proc_control(struct dev_state *ps, void __user *arg) tbuf, max(i, 0)); if ((i > 0) && ctrl.wLength) { if (copy_to_user(ctrl.data, tbuf, i)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (ctrl.wLength) { if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } pipe = usb_sndctrlpipe(dev, 0); @@ -843,14 +888,18 @@ static int proc_control(struct dev_state *ps, void __user *arg) usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); } - free_page((unsigned long)tbuf); if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); } - return i; + ret = i; + done: + free_page((unsigned long) tbuf); + usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) + + sizeof(struct usb_ctrlrequest)); + return ret; } static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -877,15 +926,20 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 > MAX_USBFS_BUFFER_SIZE) + if (len1 >= USBFS_XFER_MAX) return -EINVAL; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) - return -ENOMEM; + ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); + if (ret) + return ret; + if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } tmo = bulk.timeout; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { - kfree(tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); @@ -896,15 +950,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); @@ -914,10 +968,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) usb_lock_device(dev); snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0); } + ret = (i < 0 ? i : len2); + done: kfree(tbuf); - if (i < 0) - return i; - return len2; + usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); + return ret; } static int proc_resetep(struct dev_state *ps, void __user *arg) @@ -1062,7 +1117,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; - struct async *as; + struct async *as = NULL; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; @@ -1095,32 +1150,30 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, } if (!ep) return -ENOENT; + + u = 0; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; - /* min 8 byte setup packet, - * max 8 byte setup plus an arbitrary data stage */ - if (uurb->buffer_length < 8 || - uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) + /* min 8 byte setup packet */ + if (uurb->buffer_length < 8) return -EINVAL; dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { - kfree(dr); - return -EINVAL; + ret = -EINVAL; + goto error; } ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, le16_to_cpup(&dr->wIndex)); - if (ret) { - kfree(dr); - return ret; - } + if (ret) + goto error; uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; @@ -1138,6 +1191,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, __le16_to_cpup(&dr->wValue), __le16_to_cpup(&dr->wIndex), __le16_to_cpup(&dr->wLength)); + u = sizeof(struct usb_ctrlrequest); break; case USBDEVFS_URB_TYPE_BULK: @@ -1151,8 +1205,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, goto interrupt_urb; } uurb->number_of_packets = 0; - if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) - return -EINVAL; break; case USBDEVFS_URB_TYPE_INTERRUPT: @@ -1160,8 +1212,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; interrupt_urb: uurb->number_of_packets = 0; - if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) - return -EINVAL; break; case USBDEVFS_URB_TYPE_ISO: @@ -1176,50 +1226,53 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { - kfree(isopkt); - return -EFAULT; + ret = -EFAULT; + goto error; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { /* arbitrary limit, * sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { - kfree(isopkt); - return -EINVAL; + ret = -EINVAL; + goto error; } totlen += isopkt[u].length; } - /* 3072 * 64 microframes */ - if (totlen > 196608) { - kfree(isopkt); - return -EINVAL; - } + u *= sizeof(struct usb_iso_packet_descriptor); uurb->buffer_length = totlen; break; default: return -EINVAL; } + + if (uurb->buffer_length >= USBFS_XFER_MAX) { + ret = -EINVAL; + goto error; + } if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { - kfree(isopkt); - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } as = alloc_async(uurb->number_of_packets); if (!as) { - kfree(isopkt); - kfree(dr); - return -ENOMEM; + ret = -ENOMEM; + goto error; } + u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length; + ret = usbfs_increase_memory_usage(u); + if (ret) + goto error; + as->mem_usage = u; + if (uurb->buffer_length > 0) { as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); if (!as->urb->transfer_buffer) { - kfree(isopkt); - kfree(dr); - free_async(as); - return -ENOMEM; + ret = -ENOMEM; + goto error; } /* Isochronous input data may end up being discontiguous * if some of the packets are short. Clear the buffer so @@ -1253,6 +1306,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; + dr = NULL; as->urb->start_frame = uurb->start_frame; as->urb->number_of_packets = uurb->number_of_packets; if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1268,6 +1322,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, totlen += isopkt[u].length; } kfree(isopkt); + isopkt = NULL; as->ps = ps; as->userurb = arg; if (is_in && uurb->buffer_length > 0) @@ -1282,8 +1337,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if (!is_in && uurb->buffer_length > 0) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, uurb->buffer_length)) { - free_async(as); - return -EFAULT; + ret = -EFAULT; + goto error; } } snoop_urb(ps->dev, as->userurb, as->urb->pipe, @@ -1329,10 +1384,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, snoop_urb(ps->dev, as->userurb, as->urb->pipe, 0, ret, COMPLETE, NULL, 0); async_removepending(as); - free_async(as); - return ret; + goto error; } return 0; + + error: + kfree(isopkt); + kfree(dr); + if (as) + free_async(as); + return ret; } static int proc_submiturb(struct dev_state *ps, void __user *arg) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 45887a0ff87..d40ff956881 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -45,10 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, struct usb_dynid *dynid; u32 idVendor = 0; u32 idProduct = 0; + unsigned int bInterfaceClass = 0; int fields = 0; int retval = 0; - fields = sscanf(buf, "%x %x", &idVendor, &idProduct); + fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, + &bInterfaceClass); if (fields < 2) return -EINVAL; @@ -60,6 +62,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, dynid->id.idVendor = idVendor; dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; + if (fields == 3) { + dynid->id.bInterfaceClass = (u8)bInterfaceClass; + dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; + } spin_lock(&dynids->lock); list_add_tail(&dynid->node, &dynids->list); @@ -1073,17 +1079,10 @@ static int usb_suspend_interface(struct usb_device *udev, goto done; driver = to_usb_driver(intf->dev.driver); - if (driver->suspend) { - status = driver->suspend(intf, msg); - if (status && !PMSG_IS_AUTO(msg)) - dev_err(&intf->dev, "%s error %d\n", - "suspend", status); - } else { - /* Later we will unbind the driver and reprobe */ - intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "suspend", driver->name); - } + /* at this time we know the driver supports suspend */ + status = driver->suspend(intf, msg); + if (status && !PMSG_IS_AUTO(msg)) + dev_err(&intf->dev, "suspend error %d\n", status); done: dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); @@ -1132,16 +1131,9 @@ static int usb_resume_interface(struct usb_device *udev, "reset_resume", driver->name); } } else { - if (driver->resume) { - status = driver->resume(intf); - if (status) - dev_err(&intf->dev, "%s error %d\n", - "resume", status); - } else { - intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "resume", driver->name); - } + status = driver->resume(intf); + if (status) + dev_err(&intf->dev, "resume error %d\n", status); } done: diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 99458c843d6..d95760de9e8 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -66,7 +66,7 @@ static struct usb_class { struct class *class; } *usb_class; -static char *usb_devnode(struct device *dev, mode_t *mode) +static char *usb_devnode(struct device *dev, umode_t *mode) { struct usb_class_driver *drv; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index a004db35f6d..81e2c0d9c17 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -187,7 +187,10 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; dev->current_state = PCI_D0; - if (!dev->irq) { + /* The xHCI driver supports MSI and MSI-X, + * so don't fail if the BIOS doesn't provide a legacy IRQ. + */ + if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); @@ -453,10 +456,6 @@ static int resume_common(struct device *dev, int event) pci_set_master(pci_dev); - clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - if (hcd->shared_hcd) - clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); - if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { if (event != PM_EVENT_AUTO_RESUME) wait_for_companions(pci_dev, hcd); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 13222d352a6..e1282328fc2 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -658,7 +658,7 @@ error: len > offsetof(struct usb_device_descriptor, bDeviceProtocol)) ((struct usb_device_descriptor *) ubuf)-> - bDeviceProtocol = 1; + bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT; } /* any errors get returned through the urb completion */ @@ -1168,20 +1168,6 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, if (urb->unlinked) return -EBUSY; urb->unlinked = status; - - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) { - dev_warn(hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - if (hcd->shared_hcd) - set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); - } - return 0; } EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); @@ -1412,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_SG; - if (n != urb->num_sgs) { - urb->num_sgs = n; + urb->num_mapped_sgs = n; + if (n != urb->num_sgs) urb->transfer_flags |= URB_DMA_SG_COMBINED; - } } else if (urb->sg) { struct scatterlist *sg = urb->sg; urb->transfer_dma = dma_map_page( @@ -2148,16 +2133,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) */ local_irq_save(flags); - if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) { + if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; - } else if (hcd->driver->irq(hcd) == IRQ_NONE) { + else if (hcd->driver->irq(hcd) == IRQ_NONE) rc = IRQ_NONE; - } else { - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - if (hcd->shared_hcd) - set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); + else rc = IRQ_HANDLED; - } local_irq_restore(flags); return rc; @@ -2466,8 +2447,10 @@ int usb_add_hcd(struct usb_hcd *hcd, && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - /* enable irqs just before we start the controller */ - if (usb_hcd_is_primary_hcd(hcd)) { + /* enable irqs just before we start the controller, + * if the BIOS provides legacy PCI irqs. + */ + if (usb_hcd_is_primary_hcd(hcd) && irqnum) { retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); if (retval) goto err_request_irq; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 79781461eec..265c2f675d0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -84,7 +84,7 @@ struct usb_hub { static inline int hub_is_superspeed(struct usb_device *hdev) { - return (hdev->descriptor.bDeviceProtocol == 3); + return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); } /* Protect struct usb_device->state and ->children members @@ -102,7 +102,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ -static int blinkenlights = 0; +static bool blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); @@ -131,12 +131,12 @@ MODULE_PARM_DESC(initial_descriptor_timeout, * otherwise the new scheme is used. If that fails and "use_both_schemes" * is set, then the driver will make another attempt, using the other scheme. */ -static int old_scheme_first = 0; +static bool old_scheme_first = 0; module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -static int use_both_schemes = 1; +static bool use_both_schemes = 1; module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " @@ -705,10 +705,26 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (type == HUB_INIT3) goto init3; - /* After a resume, port power should still be on. + /* The superspeed hub except for root hub has to use Hub Depth + * value as an offset into the route string to locate the bits + * it uses to determine the downstream port number. So hub driver + * should send a set hub depth request to superspeed hub after + * the superspeed hub is set configuration in initialization or + * reset procedure. + * + * After a resume, port power should still be on. * For any other type of activation, turn it on. */ if (type != HUB_RESUME) { + if (hdev->parent && hub_is_superspeed(hdev)) { + ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + HUB_SET_DEPTH, USB_RT_HUB, + hdev->level - 1, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(hub->intfdev, + "set hub depth failed\n"); + } /* Speed up system boot by using a delayed_work for the * hub's initial power-up delays. This is pretty awkward @@ -987,18 +1003,6 @@ static int hub_configure(struct usb_hub *hub, goto fail; } - if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) { - ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_SET_DEPTH, USB_RT_HUB, - hdev->level - 1, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - - if (ret < 0) { - message = "can't set hub depth"; - goto fail; - } - } - /* Request the entire hub descriptor. * hub->descriptor can handle USB_MAXCHILDREN ports, * but the hub can/will return fewer bytes here. @@ -1041,58 +1045,58 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "standalone hub\n"); switch (wHubCharacteristics & HUB_CHAR_LPSM) { - case 0x00: - dev_dbg(hub_dev, "ganged power switching\n"); - break; - case 0x01: - dev_dbg(hub_dev, "individual port power switching\n"); - break; - case 0x02: - case 0x03: - dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); - break; + case HUB_CHAR_COMMON_LPSM: + dev_dbg(hub_dev, "ganged power switching\n"); + break; + case HUB_CHAR_INDV_PORT_LPSM: + dev_dbg(hub_dev, "individual port power switching\n"); + break; + case HUB_CHAR_NO_LPSM: + case HUB_CHAR_LPSM: + dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); + break; } switch (wHubCharacteristics & HUB_CHAR_OCPM) { - case 0x00: - dev_dbg(hub_dev, "global over-current protection\n"); - break; - case 0x08: - dev_dbg(hub_dev, "individual port over-current protection\n"); - break; - case 0x10: - case 0x18: - dev_dbg(hub_dev, "no over-current protection\n"); - break; + case HUB_CHAR_COMMON_OCPM: + dev_dbg(hub_dev, "global over-current protection\n"); + break; + case HUB_CHAR_INDV_PORT_OCPM: + dev_dbg(hub_dev, "individual port over-current protection\n"); + break; + case HUB_CHAR_NO_OCPM: + case HUB_CHAR_OCPM: + dev_dbg(hub_dev, "no over-current protection\n"); + break; } spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { - case 0: - break; - case 1: - dev_dbg(hub_dev, "Single TT\n"); - hub->tt.hub = hdev; - break; - case 2: - ret = usb_set_interface(hdev, 0, 1); - if (ret == 0) { - dev_dbg(hub_dev, "TT per port\n"); - hub->tt.multi = 1; - } else - dev_err(hub_dev, "Using single TT (err %d)\n", - ret); - hub->tt.hub = hdev; - break; - case 3: - /* USB 3.0 hubs don't have a TT */ - break; - default: - dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", - hdev->descriptor.bDeviceProtocol); - break; + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + dev_dbg(hub_dev, "Single TT\n"); + hub->tt.hub = hdev; + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(hdev, 0, 1); + if (ret == 0) { + dev_dbg(hub_dev, "TT per port\n"); + hub->tt.multi = 1; + } else + dev_err(hub_dev, "Using single TT (err %d)\n", + ret); + hub->tt.hub = hdev; + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", + hdev->descriptor.bDeviceProtocol); + break; } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ @@ -1360,7 +1364,6 @@ descriptor_error: return -ENODEV; } -/* No BKL needed */ static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { @@ -2027,7 +2030,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_ADDRESS_TRIES 2 #define GET_DESCRIPTOR_TRIES 2 #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) -#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first) +#define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first) #define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 2278dad886e..9e186f3da83 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -65,7 +65,7 @@ static umode_t devmode = USBFS_DEFAULT_DEVMODE; static umode_t busmode = USBFS_DEFAULT_BUSMODE; static umode_t listmode = USBFS_DEFAULT_LISTMODE; -static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int usbfs_show_options(struct seq_file *seq, struct dentry *root) { if (devuid != 0) seq_printf(seq, ",devuid=%u", devuid); @@ -264,21 +264,19 @@ static int remount(struct super_block *sb, int *flags, char *data) return -EINVAL; } - if (usbfs_mount && usbfs_mount->mnt_sb) + if (usbfs_mount) update_sb(usbfs_mount->mnt_sb); return 0; } -static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev) +static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev) { struct inode *inode = new_inode(sb); if (inode) { inode->i_ino = get_next_ino(); - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); + inode_init_owner(inode, NULL, mode); inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: @@ -300,7 +298,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de } /* SMP-safe */ -static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, +static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); @@ -317,7 +315,7 @@ static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, return error; } -static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) +static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode) { int res; @@ -328,7 +326,7 @@ static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) return res; } -static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode) +static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode) { mode = (mode & S_IALLUGO) | S_IFREG; return usbfs_mknod (dir, dentry, mode, 0); @@ -489,7 +487,7 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) * * This function handles both regular files and directories. */ -static int fs_create_by_name (const char *name, mode_t mode, +static int fs_create_by_name (const char *name, umode_t mode, struct dentry *parent, struct dentry **dentry) { int error = 0; @@ -500,9 +498,8 @@ static int fs_create_by_name (const char *name, mode_t mode, * have around. */ if (!parent ) { - if (usbfs_mount && usbfs_mount->mnt_sb) { - parent = usbfs_mount->mnt_sb->s_root; - } + if (usbfs_mount) + parent = usbfs_mount->mnt_root; } if (!parent) { @@ -514,7 +511,7 @@ static int fs_create_by_name (const char *name, mode_t mode, mutex_lock(&parent->d_inode->i_mutex); *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(*dentry)) { - if ((mode & S_IFMT) == S_IFDIR) + if (S_ISDIR(mode)) error = usbfs_mkdir (parent->d_inode, *dentry, mode); else error = usbfs_create (parent->d_inode, *dentry, mode); @@ -525,7 +522,7 @@ static int fs_create_by_name (const char *name, mode_t mode, return error; } -static struct dentry *fs_create_file (const char *name, mode_t mode, +static struct dentry *fs_create_file (const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops, uid_t uid, gid_t gid) @@ -608,7 +605,7 @@ static int create_special_files (void) ignore_mount = 0; - parent = usbfs_mount->mnt_sb->s_root; + parent = usbfs_mount->mnt_root; devices_usbfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent, NULL, &usbfs_devices_fops, @@ -662,7 +659,7 @@ static void usbfs_add_bus(struct usb_bus *bus) sprintf (name, "%03d", bus->busnum); - parent = usbfs_mount->mnt_sb->s_root; + parent = usbfs_mount->mnt_root; bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, bus, NULL, busuid, busgid); if (bus->usbfs_dentry == NULL) { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ecf12e15a7e..4c65eb6a867 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -117,9 +117,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*/ + /* 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/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 662c0cf3a3e..9e491ca2e5c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -642,7 +642,7 @@ static struct attribute *dev_string_attrs[] = { NULL }; -static mode_t dev_string_attrs_are_visible(struct kobject *kobj, +static umode_t dev_string_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); @@ -877,7 +877,7 @@ static struct attribute *intf_assoc_attrs[] = { NULL, }; -static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj, +static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 73cd90012ec..8ca9f994a28 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -47,7 +47,7 @@ const char *usbcore_name = "usbcore"; -static int nousb; /* Disable USB when built into kernel image */ +static bool nousb; /* Disable USB when built into kernel image */ #ifdef CONFIG_USB_SUSPEND static int usb_autosuspend_delay = 2; /* Default delay value, @@ -326,7 +326,7 @@ static const struct dev_pm_ops usb_device_pm_ops = { #endif /* CONFIG_PM */ -static char *usb_devnode(struct device *dev, mode_t *mode) +static char *usb_devnode(struct device *dev, umode_t *mode) { struct usb_device *usb_dev; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3888778582c..45e8479c377 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -132,20 +132,6 @@ static inline int is_usb_device_driver(struct device_driver *drv) for_devices; } -/* translate USB error codes to codes user space understands */ -static inline int usb_translate_errors(int error_code) |