diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/buffer.c | 8 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 28 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 31 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 27 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 14 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 42 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 11 | ||||
-rw-r--r-- | drivers/usb/core/of.c | 26 | ||||
-rw-r--r-- | drivers/usb/core/phy.c | 7 | ||||
-rw-r--r-- | drivers/usb/core/port.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 2 |
13 files changed, 143 insertions, 75 deletions
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 77eef8acff94..f641342cdec0 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -101,12 +101,8 @@ void hcd_buffer_destroy(struct usb_hcd *hcd) return; for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool[i]; - - if (pool) { - dma_pool_destroy(pool); - hcd->pool[i] = NULL; - } + dma_pool_destroy(hcd->pool[i]); + hcd->pool[i] = NULL; } } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6ce77b33da61..a75bc0b8a50f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -582,7 +582,7 @@ static void async_completed(struct urb *urb) { struct async *as = urb->context; struct usb_dev_state *ps = as->ps; - struct siginfo sinfo; + struct kernel_siginfo sinfo; struct pid *pid = NULL; const struct cred *cred = NULL; unsigned long flags; @@ -1434,10 +1434,13 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb struct async *as = NULL; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; - int i, ret, is_in, num_sgs = 0, ifnum = -1; + int i, ret, num_sgs = 0, ifnum = -1; int number_of_packets = 0; unsigned int stream_id = 0; void *buf; + bool is_in; + bool allow_short = false; + bool allow_zero = false; unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | USBDEVFS_URB_BULK_CONTINUATION | USBDEVFS_URB_NO_FSBR | @@ -1500,6 +1503,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb is_in = 0; uurb->endpoint &= ~USB_DIR_IN; } + if (is_in) + allow_short = true; snoop(&ps->dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", @@ -1511,6 +1516,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb break; case USBDEVFS_URB_TYPE_BULK: + if (!is_in) + allow_zero = true; + else + allow_short = true; switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: @@ -1531,6 +1540,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; interrupt_urb: + if (!is_in) + allow_zero = true; + else + allow_short = true; break; case USBDEVFS_URB_TYPE_ISO: @@ -1676,14 +1689,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u = (is_in ? URB_DIR_IN : URB_DIR_OUT); if (uurb->flags & USBDEVFS_URB_ISO_ASAP) u |= URB_ISO_ASAP; - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) + if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) u |= URB_SHORT_NOT_OK; - if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) + if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET) u |= URB_ZERO_PACKET; if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) u |= URB_NO_INTERRUPT; as->urb->transfer_flags = u; + if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n"); + if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET) + dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n"); + as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; dr = NULL; @@ -2599,7 +2617,7 @@ const struct file_operations usbdev_file_operations = { static void usbdev_remove(struct usb_device *udev) { struct usb_dev_state *ps; - struct siginfo sinfo; + struct kernel_siginfo sinfo; while (!list_empty(&udev->filelist)) { ps = list_entry(udev->filelist.next, struct usb_dev_state, list); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index e76e95f62f76..53564386ed57 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -510,9 +510,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { struct device *dev; - struct usb_device *udev; int retval = 0; - int lpm_disable_error = -ENODEV; if (!iface) return -ENODEV; @@ -525,24 +523,12 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (!iface->authorized) return -ENODEV; - udev = interface_to_usbdev(iface); - dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); iface->needs_binding = 0; iface->condition = USB_INTERFACE_BOUND; - /* See the comment about disabling LPM in usb_probe_interface(). */ - if (driver->disable_hub_initiated_lpm) { - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error) { - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n", - __func__, driver->name); - return -ENOMEM; - } - } - /* Claimed interfaces are initially inactive (suspended) and * runtime-PM-enabled, but only if the driver has autosuspend * support. Otherwise they are marked active, to prevent the @@ -561,9 +547,20 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (device_is_registered(dev)) retval = device_bind_driver(dev); - /* Attempt to re-enable USB3 LPM, if the disable was successful. */ - if (!lpm_disable_error) - usb_unlocked_enable_lpm(udev); + if (retval) { + dev->driver = NULL; + usb_set_intfdata(iface, NULL); + iface->needs_remote_wakeup = 0; + iface->condition = USB_INTERFACE_UNBOUND; + + /* + * Unbound interfaces are always runtime-PM-disabled + * and runtime-PM-suspended + */ + if (driver->supports_autosuspend) + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + } return retval; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index bc8242bc4564..356b05c82dbc 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -21,6 +21,7 @@ #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <uapi/linux/usb/audio.h> #include "usb.h" static inline const char *plural(int n) @@ -42,6 +43,16 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } +static bool is_audio(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_AUDIO; +} + +static bool is_uac3_config(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceProtocol == UAC_VERSION_3; +} + int usb_choose_configuration(struct usb_device *udev) { int i; @@ -121,6 +132,22 @@ int usb_choose_configuration(struct usb_device *udev) #endif } + /* + * Select first configuration as default for audio so that + * devices that don't comply with UAC3 protocol are supported. + * But, still iterate through other configurations and + * select UAC3 compliant config if present. + */ + if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { + best = c; + continue; + } + + if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { + best = c; + break; + } + /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 66fe1b78d952..03432467b05f 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -515,8 +515,6 @@ static int resume_common(struct device *dev, int event) event == PM_EVENT_RESTORE); if (retval) { dev_err(dev, "PCI post-resume error %d!\n", retval); - if (hcd->shared_hcd) - usb_hc_died(hcd->shared_hcd); usb_hc_died(hcd); } } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c21955fe7c0..487025d31d44 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1738,7 +1738,6 @@ 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; urb->hcpriv = NULL; if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && @@ -1755,20 +1754,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) /* pass ownership to the completion handler */ urb->status = status; - - /* - * We disable local IRQs here avoid possible deadlock because - * drivers may call spin_lock() to hold lock which might be - * acquired in one hard interrupt handler. - * - * The local_irq_save()/local_irq_restore() around complete() - * will be removed if current USB drivers have been cleaned up - * and no one may trigger the above deadlock situation when - * running complete() in tasklet. - */ - local_irq_save(flags); urb->complete(urb); - local_irq_restore(flags); usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 462ce49f683a..c6077d582d29 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -28,6 +28,7 @@ #include <linux/mutex.h> #include <linux/random.h> #include <linux/pm_qos.h> +#include <linux/kobject.h> #include <linux/uaccess.h> #include <asm/byteorder.h> @@ -2660,11 +2661,13 @@ static bool use_new_scheme(struct usb_device *udev, int retry, { int old_scheme_first_port = port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME; + int quick_enumeration = (udev->speed == USB_SPEED_HIGH); if (udev->speed >= USB_SPEED_SUPER) return false; - return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first); + return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first + || quick_enumeration); } /* Is a USB 3.0 port in the Inactive or Compliance Mode state? @@ -5147,6 +5150,42 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, usb_lock_port(port_dev); } +/* Handle notifying userspace about hub over-current events */ +static void port_over_current_notify(struct usb_port *port_dev) +{ + static char *envp[] = { NULL, NULL, NULL }; + struct device *hub_dev; + char *port_dev_path; + + sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count"); + + hub_dev = port_dev->dev.parent; + + if (!hub_dev) + return; + + port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL); + if (!port_dev_path) + return; + + envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path); + if (!envp[0]) + goto exit_path; + + envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u", + port_dev->over_current_count); + if (!envp[1]) + goto exit; + + kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp); + + kfree(envp[1]); +exit: + kfree(envp[0]); +exit_path: + kfree(port_dev_path); +} + static void port_event(struct usb_hub *hub, int port1) __must_hold(&port_dev->status_lock) { @@ -5189,6 +5228,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; port_dev->over_current_count++; + port_over_current_notify(port_dev); dev_dbg(&port_dev->dev, "over-current change #%u\n", port_dev->over_current_count); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 228672f2c4a1..bfa5eda0cc26 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1341,6 +1341,11 @@ void usb_enable_interface(struct usb_device *dev, * is submitted that needs that bandwidth. Some other operating systems * allocate bandwidth early, when a configuration is chosen. * + * xHCI reserves bandwidth and configures the alternate setting in + * usb_hcd_alloc_bandwidth(). If it fails the original interface altsetting + * may be disabled. Drivers cannot rely on any particular alternate + * setting being in effect after a failure. + * * This call is synchronous, and may not be used in an interrupt context. * Also, drivers must not change altsettings while urbs are scheduled for * endpoints in that interface; all such urbs must first be completed @@ -1376,6 +1381,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) alternate); return -EINVAL; } + /* + * usb3 hosts configure the interface in usb_hcd_alloc_bandwidth, + * including freeing dropped endpoint ring buffers. + * Make sure the interface endpoints are flushed before that + */ + usb_disable_interface(dev, iface, false); /* Make sure we have enough bandwidth for this alternate interface. * Remove the current alt setting and add the new alt setting. diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index fd77442c2d12..651708d8c908 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -105,29 +105,3 @@ usb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum) return NULL; } EXPORT_SYMBOL_GPL(usb_of_get_interface_node); - -/** - * usb_of_get_companion_dev - Find the companion device - * @dev: the device pointer to find a companion - * - * Find the companion device from platform bus. - * - * Takes a reference to the returned struct device which needs to be dropped - * after use. - * - * Return: On success, a pointer to the companion device, %NULL on failure. - */ -struct device *usb_of_get_companion_dev(struct device *dev) -{ - struct device_node *node; - struct platform_device *pdev = NULL; - - node = of_parse_phandle(dev->of_node, "companion", 0); - if (node) - pdev = of_find_device_by_node(node); - - of_node_put(node); - - return pdev ? &pdev->dev : NULL; -} -EXPORT_SYMBOL_GPL(usb_of_get_companion_dev); diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 9879767452a2..38b2c776c4b4 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -23,10 +23,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index, struct list_head *list) { struct usb_phy_roothub *roothub_entry; - struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + struct phy *phy; - if (IS_ERR_OR_NULL(phy)) { - if (!phy || PTR_ERR(phy) == -ENODEV) + phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + if (IS_ERR(phy)) { + if (PTR_ERR(phy) == -ENODEV) return 0; else return PTR_ERR(phy); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 4a2143195395..1a06a4b5fbb1 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -16,6 +16,15 @@ static int usb_port_block_power_off; static const struct attribute_group *port_dev_group[]; +static ssize_t location_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *port_dev = to_usb_port(dev); + + return sprintf(buf, "0x%08x\n", port_dev->location); +} +static DEVICE_ATTR_RO(location); + static ssize_t connect_type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -140,6 +149,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit); static struct attribute *port_dev_attrs[] = { &dev_attr_connect_type.attr, + &dev_attr_location.attr, &dev_attr_quirks.attr, &dev_attr_over_current_count.attr, NULL, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 097057d2eacf..178d6c6063c0 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -58,6 +58,7 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp) quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry), GFP_KERNEL); if (!quirk_list) { + quirk_count = 0; mutex_unlock(&quirk_mutex); return -ENOMEM; } @@ -154,7 +155,7 @@ static struct kparam_string quirks_param_string = { .string = quirks_param, }; -module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644); +device_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644); MODULE_PARM_DESC(quirks, "Add/modify USB quirks by specifying quirks=vendorID:productID:quirks"); /* Lists of quirky USB devices, split in device quirks and interface quirks. @@ -178,6 +179,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, + /* WORLDE Controller KS49 or Prodipe MIDI 49C USB controller */ + { USB_DEVICE(0x0218, 0x0201), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* WORLDE easy key (easykey.25) MIDI controller */ { USB_DEVICE(0x0218, 0x0401), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -406,6 +411,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* DJI CineSSD */ + { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 623be3174fb3..79d8bd7a612e 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -228,6 +228,8 @@ struct usb_host_interface *usb_find_alt_setting( struct usb_interface_cache *intf_cache = NULL; int i; + if (!config) + return NULL; for (i = 0; i < config->desc.bNumInterfaces; i++) { if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber == iface_num) { |