diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/config.c | 105 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 155 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 5 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 35 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 61 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 209 | ||||
-rw-r--r-- | drivers/usb/core/phy.c | 21 | ||||
-rw-r--r-- | drivers/usb/core/phy.h | 1 | ||||
-rw-r--r-- | drivers/usb/core/port.c | 9 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 222 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 3 |
13 files changed, 403 insertions, 426 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 9d6cb709ca7b..26bc05e48d8a 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -203,9 +203,58 @@ static const unsigned short super_speed_maxpacket_maxes[4] = { [USB_ENDPOINT_XFER_INT] = 1024, }; -static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, - int asnum, struct usb_host_interface *ifp, int num_ep, - unsigned char *buffer, int size) +static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, + struct usb_endpoint_descriptor *e2) +{ + if (e1->bEndpointAddress == e2->bEndpointAddress) + return true; + + if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { + if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) + return true; + } + + return false; +} + +/* + * Check for duplicate endpoint addresses in other interfaces and in the + * altsetting currently being parsed. + */ +static bool config_endpoint_is_duplicate(struct usb_host_config *config, + int inum, int asnum, struct usb_endpoint_descriptor *d) +{ + struct usb_endpoint_descriptor *epd; + struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int i, j, k; + + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intfc = config->intf_cache[i]; + + for (j = 0; j < intfc->num_altsetting; ++j) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceNumber == inum && + alt->desc.bAlternateSetting != asnum) + continue; + + for (k = 0; k < alt->desc.bNumEndpoints; ++k) { + epd = &alt->endpoint[k].desc; + + if (endpoint_is_duplicate(epd, d)) + return true; + } + } + } + + return false; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, + struct usb_host_config *config, int inum, int asnum, + struct usb_host_interface *ifp, int num_ep, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; @@ -242,13 +291,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, goto skip_to_next_endpoint_or_interface_descriptor; /* Check for duplicate endpoint addresses */ - for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { - if (ifp->endpoint[i].desc.bEndpointAddress == - d->bEndpointAddress) { - dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; - } + if (config_endpoint_is_duplicate(config, inum, asnum, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; } endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; @@ -346,8 +392,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, endpoint->desc.wMaxPacketSize = cpu_to_le16(8); } - /* Validate the wMaxPacketSize field */ + /* + * Validate the wMaxPacketSize field. + * Some devices have isochronous endpoints in altsetting 0; + * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0 + * (see the end of section 5.6.3), so don't warn about them. + */ maxp = usb_endpoint_maxp(&endpoint->desc); + if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n", + cfgno, inum, asnum, d->bEndpointAddress); + } /* Find the highest legal maxpacket size for this endpoint */ i = 0; /* additional transactions per microframe */ @@ -517,8 +572,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, if (((struct usb_descriptor_header *) buffer)->bDescriptorType == USB_DT_INTERFACE) break; - retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, - num_ep, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, + alt, num_ep, buffer, size); if (retval < 0) return retval; ++n; @@ -800,10 +855,10 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + int result; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " @@ -819,16 +874,16 @@ int usb_get_configuration(struct usb_device *dev) length = ncfg * sizeof(struct usb_host_config); dev->config = kzalloc(length, GFP_KERNEL); if (!dev->config) - goto err2; + return -ENOMEM; length = ncfg * sizeof(char *); dev->rawdescriptors = kzalloc(length, GFP_KERNEL); if (!dev->rawdescriptors) - goto err2; + return -ENOMEM; desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); if (!desc) - goto err2; + return -ENOMEM; for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long @@ -890,9 +945,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(desc); dev->descriptor.bNumConfigurations = cfgno; -err2: - if (result == -ENOMEM) - dev_err(ddev, "out of memory\n"); + return result; } @@ -921,7 +974,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) struct usb_bos_descriptor *bos; struct usb_dev_cap_header *cap; struct usb_ssp_cap_descriptor *ssp_cap; - unsigned char *buffer; + unsigned char *buffer, *buffer0; int length, total_len, num, i, ssac; __u8 cap_type; int ret; @@ -966,10 +1019,12 @@ int usb_get_bos_descriptor(struct usb_device *dev) ret = -ENOMSG; goto err; } + + buffer0 = buffer; total_len -= length; + buffer += length; for (i = 0; i < num; i++) { - buffer += length; cap = (struct usb_dev_cap_header *)buffer; if (total_len < sizeof(*cap) || total_len < cap->bLength) { @@ -983,8 +1038,6 @@ int usb_get_bos_descriptor(struct usb_device *dev) break; } - total_len -= length; - if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { dev_warn(ddev, "descriptor type invalid, skip\n"); continue; @@ -1019,7 +1072,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) default: break; } + + total_len -= length; + buffer += length; } + dev->bos->desc->wTotalLength = cpu_to_le16(buffer - buffer0); return 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 9063ede411ae..6833c918abce 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -44,10 +44,19 @@ #include "usb.h" +#ifdef CONFIG_PM +#define MAYBE_CAP_SUSPEND USBDEVFS_CAP_SUSPEND +#else +#define MAYBE_CAP_SUSPEND 0 +#endif + #define USB_MAXBUS 64 #define USB_DEVICE_MAX (USB_MAXBUS * 128) #define USB_SG_SIZE 16384 /* split-size for large txs */ +/* Mutual exclusion for ps->list in resume vs. release and remove */ +static DEFINE_MUTEX(usbfs_mutex); + struct usb_dev_state { struct list_head list; /* state list */ struct usb_device *dev; @@ -57,14 +66,17 @@ struct usb_dev_state { struct list_head async_completed; struct list_head memory_list; wait_queue_head_t wait; /* wake up if a request completed */ + wait_queue_head_t wait_for_resume; /* wake up upon runtime resume */ unsigned int discsignr; struct pid *disc_pid; const struct cred *cred; sigval_t disccontext; unsigned long ifclaimed; u32 disabled_bulk_eps; - bool privileges_dropped; unsigned long interface_allowed_mask; + int not_yet_resumed; + bool suspend_allowed; + bool privileges_dropped; }; struct usb_memory { @@ -562,7 +574,7 @@ __acquires(ps->lock) /* Now carefully unlink all the marked pending URBs */ rescan: - list_for_each_entry(as, &ps->async_pending, asynclist) { + list_for_each_entry_reverse(as, &ps->async_pending, asynclist) { if (as->bulk_status == AS_UNLINK) { as->bulk_status = 0; /* Only once */ urb = as->urb; @@ -624,7 +636,7 @@ static void destroy_async(struct usb_dev_state *ps, struct list_head *list) spin_lock_irqsave(&ps->lock, flags); while (!list_empty(list)) { - as = list_entry(list->next, struct async, asynclist); + as = list_last_entry(list, struct async, asynclist); list_del_init(&as->asynclist); urb = as->urb; usb_get_urb(urb); @@ -694,9 +706,7 @@ static void driver_disconnect(struct usb_interface *intf) destroy_async_on_interface(ps, ifnum); } -/* The following routines are merely placeholders. There is no way - * to inform a user task about suspend or resumes. - */ +/* We don't care about suspend/resume of claimed interfaces */ static int driver_suspend(struct usb_interface *intf, pm_message_t msg) { return 0; @@ -707,12 +717,32 @@ static int driver_resume(struct usb_interface *intf) return 0; } +/* The following routines apply to the entire device, not interfaces */ +void usbfs_notify_suspend(struct usb_device *udev) +{ + /* We don't need to handle this */ +} + +void usbfs_notify_resume(struct usb_device *udev) +{ + struct usb_dev_state *ps; + + /* Protect against simultaneous remove or release */ + mutex_lock(&usbfs_mutex); + list_for_each_entry(ps, &udev->filelist, list) { + WRITE_ONCE(ps->not_yet_resumed, 0); + wake_up_all(&ps->wait_for_resume); + } + mutex_unlock(&usbfs_mutex); +} + struct usb_driver usbfs_driver = { .name = "usbfs", .probe = driver_probe, .disconnect = driver_disconnect, .suspend = driver_suspend, .resume = driver_resume, + .supports_autosuspend = 1, }; static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) @@ -734,8 +764,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) intf = usb_ifnum_to_if(dev, ifnum); if (!intf) err = -ENOENT; - else + else { + unsigned int old_suppress; + + /* suppress uevents while claiming interface */ + old_suppress = dev_get_uevent_suppress(&intf->dev); + dev_set_uevent_suppress(&intf->dev, 1); err = usb_driver_claim_interface(&usbfs_driver, intf, ps); + dev_set_uevent_suppress(&intf->dev, old_suppress); + } if (err == 0) set_bit(ifnum, &ps->ifclaimed); return err; @@ -755,7 +792,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum) if (!intf) err = -ENOENT; else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { + unsigned int old_suppress; + + /* suppress uevents while releasing interface */ + old_suppress = dev_get_uevent_suppress(&intf->dev); + dev_set_uevent_suppress(&intf->dev, 1); usb_driver_release_interface(&usbfs_driver, intf); + dev_set_uevent_suppress(&intf->dev, old_suppress); err = 0; } return err; @@ -942,17 +985,11 @@ error: return ret; } -static int match_devt(struct device *dev, const void *data) -{ - return dev->devt == (dev_t)(unsigned long)(void *)data; -} - static struct usb_device *usbdev_lookup_by_devt(dev_t devt) { struct device *dev; - dev = bus_find_device(&usb_bus_type, NULL, - (void *) (unsigned long) devt, match_devt); + dev = bus_find_device_by_devt(&usb_bus_type, devt); if (!dev) return NULL; return to_usb_device(dev); @@ -997,9 +1034,12 @@ static int usbdev_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&ps->async_completed); INIT_LIST_HEAD(&ps->memory_list); init_waitqueue_head(&ps->wait); + init_waitqueue_head(&ps->wait_for_resume); ps->disc_pid = get_pid(task_pid(current)); ps->cred = get_current_cred(); smp_wmb(); + + /* Can't race with resume; the device is already active */ list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; usb_unlock_device(dev); @@ -1025,7 +1065,10 @@ static int usbdev_release(struct inode *inode, struct file *file) usb_lock_device(dev); usb_hub_release_all_ports(dev, ps); + /* Protect against simultaneous resume */ + mutex_lock(&usbfs_mutex); list_del_init(&ps->list); + mutex_unlock(&usbfs_mutex); for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); ifnum++) { @@ -1033,7 +1076,8 @@ static int usbdev_release(struct inode *inode, struct file *file) releaseintf(ps, ifnum); } destroy_all_async(ps); - usb_autosuspend_device(dev); + if (!ps->suspend_allowed) + usb_autosuspend_device(dev); usb_unlock_device(dev); usb_put_dev(dev); put_pid(ps->disc_pid); @@ -1519,10 +1563,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb uurb->buffer_length = le16_to_cpu(dr->wLength); uurb->buffer += 8; if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { - is_in = 1; + is_in = true; uurb->endpoint |= USB_DIR_IN; } else { - is_in = 0; + is_in = false; uurb->endpoint &= ~USB_DIR_IN; } if (is_in) @@ -1627,7 +1671,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb if (as->usbm) num_sgs = 0; - u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length + + u += sizeof(struct async) + sizeof(struct urb) + + (as->usbm ? 0 : uurb->buffer_length) + num_sgs * sizeof(struct scatterlist); ret = usbfs_increase_memory_usage(u); if (ret) @@ -2279,7 +2324,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg) caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM | USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP | - USBDEVFS_CAP_DROP_PRIVILEGES | USBDEVFS_CAP_CONNINFO_EX; + USBDEVFS_CAP_DROP_PRIVILEGES | + USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND; if (!ps->dev->bus->no_stop_on_short) caps |= USBDEVFS_CAP_BULK_CONTINUATION; if (ps->dev->bus->sg_tablesize) @@ -2382,6 +2428,47 @@ static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg) return 0; } +static int proc_forbid_suspend(struct usb_dev_state *ps) +{ + int ret = 0; + + if (ps->suspend_allowed) { + ret = usb_autoresume_device(ps->dev); + if (ret == 0) + ps->suspend_allowed = false; + else if (ret != -ENODEV) + ret = -EIO; + } + return ret; +} + +static int proc_allow_suspend(struct usb_dev_state *ps) +{ + if (!connected(ps)) + return -ENODEV; + + WRITE_ONCE(ps->not_yet_resumed, 1); + if (!ps->suspend_allowed) { + usb_autosuspend_device(ps->dev); + ps->suspend_allowed = true; + } + return 0; +} + +static int proc_wait_for_resume(struct usb_dev_state *ps) +{ + int ret; + + usb_unlock_device(ps->dev); + ret = wait_event_interruptible(ps->wait_for_resume, + READ_ONCE(ps->not_yet_resumed) == 0); + usb_lock_device(ps->dev); + + if (ret != 0) + return -EINTR; + return proc_forbid_suspend(ps); +} + /* * NOTE: All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from @@ -2576,6 +2663,15 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, case USBDEVFS_GET_SPEED: ret = ps->dev->speed; break; + case USBDEVFS_FORBID_SUSPEND: + ret = proc_forbid_suspend(ps); + break; + case USBDEVFS_ALLOW_SUSPEND: + ret = proc_allow_suspend(ps); + break; + case USBDEVFS_WAIT_FOR_RESUME: + ret = proc_wait_for_resume(ps); + break; } /* Handle variable-length commands */ @@ -2602,18 +2698,6 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd, return ret; } -#ifdef CONFIG_COMPAT -static long usbdev_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret; - - ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg)); - - return ret; -} -#endif - /* No kernel lock - fine */ static __poll_t usbdev_poll(struct file *file, struct poll_table_struct *wait) @@ -2637,9 +2721,7 @@ const struct file_operations usbdev_file_operations = { .read = usbdev_read, .poll = usbdev_poll, .unlocked_ioctl = usbdev_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = usbdev_compat_ioctl, -#endif + .compat_ioctl = compat_ptr_ioctl, .mmap = usbdev_mmap, .open = usbdev_open, .release = usbdev_release, @@ -2649,15 +2731,20 @@ static void usbdev_remove(struct usb_device *udev) { struct usb_dev_state *ps; + /* Protect against simultaneous resume */ + mutex_lock(&usbfs_mutex); while (!list_empty(&udev->filelist)) { ps = list_entry(udev->filelist.next, struct usb_dev_state, list); destroy_all_async(ps); wake_up_all(&ps->wait); + WRITE_ONCE(ps->not_yet_resumed, 0); + wake_up_all(&ps->wait_for_resume); list_del_init(&ps->list); if (ps->discsignr) kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext, ps->disc_pid, ps->cred); } + mutex_unlock(&usbfs_mutex); } static int usbdev_notify(struct notifier_block *self, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ebcadaad89d1..2b27d232d7a7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -892,6 +892,7 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, new_udriver->drvwrap.driver.probe = usb_probe_device; new_udriver->drvwrap.driver.remove = usb_unbind_device; new_udriver->drvwrap.driver.owner = owner; + new_udriver->drvwrap.driver.dev_groups = new_udriver->dev_groups; retval = driver_register(&new_udriver->drvwrap.driver); @@ -954,6 +955,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; new_driver->drvwrap.driver.mod_name = mod_name; + new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 1ac9c1e5f773..38f8b3e31762 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -257,6 +257,8 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) else rc = usb_port_suspend(udev, msg); + if (rc == 0) + usbfs_notify_suspend(udev); return rc; } @@ -273,6 +275,9 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg) rc = hcd_bus_resume(udev, msg); else rc = usb_port_resume(udev, msg); + + if (rc == 0) + usbfs_notify_resume(udev); return rc; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 03432467b05f..f0a259937da8 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -216,32 +216,33 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* EHCI, OHCI */ hcd->rsrc_start = pci_resource_start(dev, 0); hcd->rsrc_len = pci_resource_len(dev, 0); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { + if (!devm_request_mem_region(&dev->dev, hcd->rsrc_start, + hcd->rsrc_len, driver->description)) { dev_dbg(&dev->dev, "controller already in use\n"); retval = -EBUSY; goto put_hcd; } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_ioremap(&dev->dev, hcd->rsrc_start, + hcd->rsrc_len); if (hcd->regs == NULL) { dev_dbg(&dev->dev, "error mapping memory\n"); retval = -EFAULT; - goto release_mem_region; + goto put_hcd; } } else { /* UHCI */ int region; - for (region = 0; region < PCI_ROM_RESOURCE; region++) { + for (region = 0; region < PCI_STD_NUM_BARS; region++) { if (!(pci_resource_flags(dev, region) & IORESOURCE_IO)) continue; hcd->rsrc_start = pci_resource_start(dev, region); hcd->rsrc_len = pci_resource_len(dev, region); - if (request_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) + if (devm_request_region(&dev->dev, hcd->rsrc_start, + hcd->rsrc_len, driver->description)) break; } if (region == PCI_ROM_RESOURCE) { @@ -275,20 +276,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } if (retval != 0) - goto unmap_registers; + goto put_hcd; device_wakeup_enable(hcd->self.controller); if (pci_dev_run_wake(dev)) pm_runtime_put_noidle(&dev->dev); return retval; -unmap_registers: - if (driver->flags & HCD_MEMORY) { - iounmap(hcd->regs); -release_mem_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - } else - release_region(hcd->rsrc_start, hcd->rsrc_len); put_hcd: usb_put_hcd(hcd); disable_pci: @@ -347,14 +341,6 @@ void usb_hcd_pci_remove(struct pci_dev *dev) dev_set_drvdata(&dev->dev, NULL); up_read(&companions_rwsem); } - - if (hcd->driver->flags & HCD_MEMORY) { - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - } else { - release_region(hcd->rsrc_start, hcd->rsrc_len); - } - usb_put_hcd(hcd); pci_disable_device(dev); } @@ -407,8 +393,7 @@ static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable) static int check_root_hub_suspended(struct device *dev) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); if (HCD_RH_RUNNING(hcd)) { dev_warn(dev, "Root hub is not suspended\n"); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8592c0344fe8..aa45840d8273 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1249,9 +1249,6 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); * To support host controllers with limited dma capabilities we provide dma * bounce buffers. This feature can be enabled by initializing * hcd->localmem_pool using usb_hcd_setup_local_mem(). - * For this to work properly the host controller code must first use the - * function dma_declare_coherent_memory() to point out which memory area - * that should be used for dma allocations. * * The initialized hcd->localmem_pool then tells the usb code to allocate all * data for dma using the genalloc API. @@ -1412,11 +1409,18 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, if (usb_endpoint_xfer_control(&urb->ep->desc)) { if (hcd->self.uses_pio_for_control) return ret; - if (hcd_uses_dma(hcd)) { - if (is_vmalloc_addr(urb->setup_packet)) { - WARN_ONCE(1, "setup packet is not dma capable\n"); - return -EAGAIN; - } else if (object_is_on_stack(urb->setup_packet)) { + if (hcd->localmem_pool) { + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (ret) + return ret; + urb->transfer_flags |= URB_SETUP_MAP_LOCAL; + } else if (hcd_uses_dma(hcd)) { + if (object_is_on_stack(urb->setup_packet)) { WARN_ONCE(1, "setup packet is on stack\n"); return -EAGAIN; } @@ -1430,23 +1434,22 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, urb->setup_dma)) return -EAGAIN; urb->transfer_flags |= URB_SETUP_MAP_SINGLE; - } else if (hcd->localmem_pool) { - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->setup_dma, - (void **)&urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (ret) - return ret; - urb->transfer_flags |= URB_SETUP_MAP_LOCAL; } } dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; if (urb->transfer_buffer_length != 0 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { - if (hcd_uses_dma(hcd)) { + if (hcd->localmem_pool) { + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); + if (ret == 0) + urb->transfer_flags |= URB_MAP_LOCAL; + } else if (hcd_uses_dma(hcd)) { if (urb->num_sgs) { int n; @@ -1482,9 +1485,6 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_PAGE; - } else if (is_vmalloc_addr(urb->transfer_buffer)) { - WARN_ONCE(1, "transfer buffer not dma capable\n"); - ret = -EAGAIN; } else if (object_is_on_stack(urb->transfer_buffer)) { WARN_ONCE(1, "transfer buffer is on stack\n"); ret = -EAGAIN; @@ -1500,15 +1500,6 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, else urb->transfer_flags |= URB_DMA_MAP_SINGLE; } - } else if (hcd->localmem_pool) { - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->transfer_dma, - &urb->transfer_buffer, - urb->transfer_buffer_length, - dir); - if (ret == 0) - urb->transfer_flags |= URB_MAP_LOCAL; } if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL))) @@ -2191,6 +2182,9 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = HC_STATE_RESUMING; status = hcd->driver->bus_resume(hcd); clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); + if (status == 0) + status = usb_phy_roothub_calibrate(hcd->phy_roothub); + if (status == 0) { struct usb_device *udev; int port1; @@ -2454,7 +2448,6 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, hcd->self.controller = dev; hcd->self.sysdev = sysdev; hcd->self.bus_name = bus_name; - hcd->self.uses_dma = (sysdev->dma_mask != NULL); timer_setup(&hcd->rh_timer, rh_timer_func, 0); #ifdef CONFIG_PM @@ -2764,6 +2757,10 @@ int usb_add_hcd(struct usb_hcd *hcd, } hcd->rh_pollable = 1; + retval = usb_phy_roothub_calibrate(hcd->phy_roothub); + if (retval) + goto err_hcd_driver_setup; + /* NOTE: root hub and controller capabilities may not be the same */ if (device_can_wakeup(hcd->self.controller) && device_can_wakeup(&hcd->self.root_hub->dev)) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 236313f41f4a..3405b146edc9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -18,6 +18,7 @@ #include <linux/sched/mm.h> #include <linux/list.h> #include <linux/slab.h> +#include <linux/kcov.h> #include <linux/ioctl.h> #include <linux/usb.h> #include <linux/usbdevice_fs.h> @@ -1191,6 +1192,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); @@ -2691,7 +2693,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, scheme) ((i) / 2 == (int)scheme) +#define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme)) #define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 @@ -4930,6 +4932,91 @@ hub_power_remaining(struct usb_hub *hub) return remaining; } + +static int descriptors_changed(struct usb_device *udev, + struct usb_device_descriptor *old_device_descriptor, + struct usb_host_bos *old_bos) +{ + int changed = 0; + unsigned index; + unsigned serial_len = 0; + unsigned len; + unsigned old_length; + int length; + char *buf; + + if (memcmp(&udev->descriptor, old_device_descriptor, + sizeof(*old_device_descriptor)) != 0) + return 1; + + if ((old_bos && !udev->bos) || (!old_bos && udev->bos)) + return 1; + if (udev->bos) { + len = le16_to_cpu(udev->bos->desc->wTotalLength); + if (len != le16_to_cpu(old_bos->desc->wTotalLength)) + return 1; + if (memcmp(udev->bos->desc, old_bos->desc, len)) + return 1; + } + + /* Since the idVendor, idProduct, and bcdDevice values in the + * device descriptor haven't changed, we will assume the + * Manufacturer and Product strings haven't changed either. + * But the SerialNumber string could be different (e.g., a + * different flash card of the same brand). + */ + if (udev->serial) + serial_len = strlen(udev->serial) + 1; + + len = serial_len; + for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); + len = max(len, old_length); + } + + buf = kmalloc(len, GFP_NOIO); + if (!buf) + /* assume the worst */ + return 1; + + for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); + length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, + old_length); + if (length != old_length) { + dev_dbg(&udev->dev, "config index %d, error %d\n", + index, length); + changed = 1; + break; + } + if (memcmp(buf, udev->rawdescriptors[index], old_length) + != 0) { + dev_dbg(&udev->dev, "config index %d changed (#%d)\n", + index, + ((struct usb_config_descriptor *) buf)-> + bConfigurationValue); + changed = 1; + break; + } + } + + if (!changed && serial_len) { + length = usb_string(udev, udev->descriptor.iSerialNumber, + buf, serial_len); + if (length + 1 != serial_len) { + dev_dbg(&udev->dev, "serial string error %d\n", + length); + changed = 1; + } else if (memcmp(buf, udev->serial, length) != 0) { + dev_dbg(&udev->dev, "serial string changed\n"); + changed = 1; + } + } + + kfree(buf); + return changed; +} + static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { @@ -5167,7 +5254,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *udev = port_dev->child; + struct usb_device_descriptor descriptor; int status = -ENODEV; + int retval; dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, portchange, portspeed(hub, portstatus)); @@ -5188,7 +5277,30 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && udev->state != USB_STATE_NOTATTACHED) { if (portstatus & USB_PORT_STAT_ENABLE) { - status = 0; /* Nothing to do */ + /* + * USB-3 connections are initialized automatically by + * the hostcontroller hardware. Therefore check for + * changed device descriptors before resuscitating the + * device. + */ + descriptor = udev->descriptor; + retval = usb_get_device_descriptor(udev, + sizeof(udev->descriptor)); + if (retval < 0) { + dev_dbg(&udev->dev, + "can't read device descriptor %d\n", + retval); + } else { + if (descriptors_changed(udev, &descriptor, + udev->bos)) { + dev_dbg(&udev->dev, + "device descriptor has changed\n"); + /* for disconnect() calls */ + udev->descriptor = descriptor; + } else { + status = 0; /* Nothing to do */ + } + } #ifdef CONFIG_PM } else if (udev->state == USB_STATE_SUSPENDED && udev->persist_enabled) { @@ -5374,6 +5486,8 @@ static void hub_event(struct work_struct *work) hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); + kcov_remote_start_usb((u64)hdev->bus->busnum); + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", hdev->state, hdev->maxchild, /* NOTE: expects max 15 ports... */ @@ -5480,6 +5594,8 @@ out_hdev_lock: /* Balance the stuff in kick_hub_wq() and allow autosuspend */ usb_autopm_put_interface(intf); kref_put(&hub->kref, hub_release); + + kcov_remote_stop(); } static const struct usb_device_id hub_id_table[] = { @@ -5550,90 +5666,6 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ -static int descriptors_changed(struct usb_device *udev, - struct usb_device_descriptor *old_device_descriptor, - struct usb_host_bos *old_bos) -{ - int changed = 0; - unsigned index; - unsigned serial_len = 0; - unsigned len; - unsigned old_length; - int length; - char *buf; - - if (memcmp(&udev->descriptor, old_device_descriptor, - sizeof(*old_device_descriptor)) != 0) - return 1; - - if ((old_bos && !udev->bos) || (!old_bos && udev->bos)) - return 1; - if (udev->bos) { - len = le16_to_cpu(udev->bos->desc->wTotalLength); - if (len != le16_to_cpu(old_bos->desc->wTotalLength)) - return 1; - if (memcmp(udev->bos->desc, old_bos->desc, len)) - return 1; - } - - /* Since the idVendor, idProduct, and bcdDevice values in the - * device descriptor haven't changed, we will assume the - * Manufacturer and Product strings haven't changed either. - * But the SerialNumber string could be different (e.g., a - * different flash card of the same brand). - */ - if (udev->serial) - serial_len = strlen(udev->serial) + 1; - - len = serial_len; - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - len = max(len, old_length); - } - - buf = kmalloc(len, GFP_NOIO); - if (!buf) - /* assume the worst */ - return 1; - - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, - old_length); - if (length != old_length) { - dev_dbg(&udev->dev, "config index %d, error %d\n", - index, length); - changed = 1; - break; - } - if (memcmp(buf, udev->rawdescriptors[index], old_length) - != 0) { - dev_dbg(&udev->dev, "config index %d changed (#%d)\n", - index, - ((struct usb_config_descriptor *) buf)-> - bConfigurationValue); - changed = 1; - break; - } - } - - if (!changed && serial_len) { - length = usb_string(udev, udev->descriptor.iSerialNumber, - buf, serial_len); - if (length + 1 != serial_len) { - dev_dbg(&udev->dev, "serial string error %d\n", - length); - changed = 1; - } else if (memcmp(buf, udev->serial, length) != 0) { - dev_dbg(&udev->dev, "serial string changed\n"); - changed = 1; - } - } - - kfree(buf); - return changed; -} - /** * usb_reset_and_verify_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) @@ -5814,7 +5846,7 @@ re_enumerate_no_bos: /** * usb_reset_device - warn interface drivers and perform a USB port reset - * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) + * @udev: device to reset (not in NOTATTACHED state) * * Warns all drivers bound to registered interfaces (using their pre_reset * method), performs the port reset, and then lets the drivers know that @@ -5842,8 +5874,7 @@ int usb_reset_device(struct usb_device *udev) struct usb_host_config *config = udev->actconfig; struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { + if (udev->state == USB_STATE_NOTATTACHED) { dev_dbg(&udev->dev, "device reset not allowed in state %d\n", udev->state); return -EINVAL; diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 7580493b867a..fb1588e7c282 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -151,6 +151,27 @@ err_out: } EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode); +int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_calibrate(roothub_entry->phy); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate); + int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) { struct usb_phy_roothub *roothub_entry; diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index dad564e2d2d4..20a267cd986b 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -18,6 +18,7 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, enum phy_mode mode); +int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 1a06a4b5fbb1..bbbb35fa639f 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -285,6 +285,14 @@ static int usb_port_runtime_suspend(struct device *dev) } #endif +static void usb_port_shutdown(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + + if (port_dev->child) + usb_disable_usb2_hardware_lpm(port_dev->child); +} + static const struct dev_pm_ops usb_port_pm_ops = { #ifdef CONFIG_PM .runtime_suspend = usb_port_runtime_suspend, @@ -301,6 +309,7 @@ struct device_type usb_port_device_type = { static struct device_driver usb_port_driver = { .name = "usb", .owner = THIS_MODULE, + .shutdown = usb_port_shutdown, }; static int link_peers(struct usb_port *left, struct usb_port *right) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 0eab79f82ce4..da923ec17612 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -45,6 +45,7 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); + INIT_LIST_HEAD(&urb->urb_list); INIT_LIST_HEAD(&urb->anchor_list); } } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0ab8738047da..f16c26dc079d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -933,228 +933,6 @@ void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, } EXPORT_SYMBOL_GPL(usb_free_coherent); -/** - * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer/setup_packet will be mapped - * - * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation - * succeeds. If the device is connected to this system through a non-DMA - * controller, this operation always succeeds. - * - * This call would normally be used for an urb which is reused, perhaps - * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. - * - * Reverse the effect of this call with usb_buffer_unmap(). - * - * Return: Either %NULL (indicating no buffer could be mapped), or @urb. - * - */ -#if 0 -struct urb *usb_buffer_map(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) - return NULL; - - if (controller->dma_mask) { - urb->transfer_dma = dma_map_single(controller, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - /* FIXME generic api broken like pci, can't report errors */ - /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */ - } else - urb->transfer_dma = ~0; - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - return urb; -} -EXPORT_SYMBOL_GPL(usb_buffer_map); -#endif /* 0 */ - -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 - -/** - * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer/setup_packet will be synchronized - */ -void usb_buffer_dmasync(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) - return; - - if (controller->dma_mask) { - dma_sync_single_for_cpu(controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol(urb->pipe)) - dma_sync_single_for_cpu(controller, - urb->setup_dma, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - } -} -EXPORT_SYMBOL_GPL(usb_buffer_dmasync); -#endif - -/** - * usb_buffer_unmap - free DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be unmapped - * - * Reverses the effect of usb_buffer_map(). - */ -#if 0 -void usb_buffer_unmap(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->sysdev)) - return; - - if (controller->dma_mask) { - dma_unmap_single(controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP; -} -EXPORT_SYMBOL_GPL(usb_buffer_unmap); -#endif /* 0 */ - -#if 0 -/** - * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to map - * @nents: the number of entries in the scatterlist - * - * Return: Either < 0 (indicating no buffers could be mapped), or the - * number of DMA mapping array entries in the scatterlist. - * - * Note: - * The caller is responsible for placing the resulting DMA addresses from - * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. - * - * Top I/O rates come from queuing URBs, instead of waiting for each one - * to complete before starting the next I/O. This is particularly easy - * to do with scatterlists. Just allocate and submit one URB for each DMA - * mapping entry returned, stopping on the first error or when all succeed. - * Better yet, use the usb_sg_*() calls, which do that (and more) for you. - * - * This call would normally be used when translating scatterlist requests, - * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it - * may be able to coalesce mappings for improved I/O efficiency. - * - * Reverse the effect of this call with usb_buffer_unmap_sg(). - */ -int usb_buffer_map_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int nents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return -EINVAL; - - /* FIXME generic api broken like pci, can't report errors */ - return dma_map_sg(controller, sg, nents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM; -} -EXPORT_SYMBOL_GPL(usb_buffer_map_sg); -#endif - -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 - -/** - * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to synchronize - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Use this when you are re-using a scatterlist's data buffers for - * another USB request. - */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return; - - dma_sync_sg_for_cpu(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} -EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); -#endif - -#if 0 -/** - * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to unmap - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Reverses the effect of usb_buffer_map_sg(). - */ -void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->sysdev) - || !controller->dma_mask) - return; - - dma_unmap_sg(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} -EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); -#endif - /* * Notifications of device and interface registration */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 0c9fde5ad052..cf4783cf661a 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -95,6 +95,9 @@ extern int usb_runtime_idle(struct device *dev); extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); +extern void usbfs_notify_suspend(struct usb_device *udev); +extern void usbfs_notify_resume(struct usb_device *udev); + #else static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg) |