diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/buffer.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/config.c | 34 | ||||
-rw-r--r-- | drivers/usb/core/devices.c | 19 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 61 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 26 | ||||
-rw-r--r-- | drivers/usb/core/endpoint.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/file.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 25 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 79 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 10 | ||||
-rw-r--r-- | drivers/usb/core/ledtrig-usbport.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 103 | ||||
-rw-r--r-- | drivers/usb/core/notify.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/of.c | 108 | ||||
-rw-r--r-- | drivers/usb/core/otg_whitelist.h | 6 | ||||
-rw-r--r-- | drivers/usb/core/port.c | 11 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 28 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 9 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 36 | ||||
-rw-r--r-- | drivers/usb/core/usb-acpi.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 5 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 4 |
24 files changed, 396 insertions, 214 deletions
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b64568cf572c..77eef8acff94 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * DMA memory management for framework level HCD code (hc_driver) * @@ -5,7 +6,6 @@ * and should work with all USB controllers, regardless of bus type. * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/module.h> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 883549ee946c..c821b4b9647e 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/usb.h> @@ -555,6 +555,9 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, unsigned iad_num = 0; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); + nintf = nintf_orig = config->desc.bNumInterfaces; + config->desc.bNumInterfaces = 0; // Adjusted later + if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE || config->desc.bLength > size) { @@ -568,7 +571,6 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, buffer += config->desc.bLength; size -= config->desc.bLength; - nintf = nintf_orig = config->desc.bNumInterfaces; if (nintf > USB_MAXINTERFACES) { dev_warn(ddev, "config %d has too many interfaces: %d, " "using maximum allowed: %d\n", @@ -905,14 +907,25 @@ void usb_release_bos_descriptor(struct usb_device *dev) } } +static const __u8 bos_desc_len[256] = { + [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE, + [USB_CAP_TYPE_EXT] = USB_DT_USB_EXT_CAP_SIZE, + [USB_SS_CAP_TYPE] = USB_DT_USB_SS_CAP_SIZE, + [USB_SSP_CAP_TYPE] = USB_DT_USB_SSP_CAP_SIZE(1), + [CONTAINER_ID_TYPE] = USB_DT_USB_SS_CONTN_ID_SIZE, + [USB_PTM_CAP_TYPE] = USB_DT_USB_PTM_ID_SIZE, +}; + /* Get BOS descriptor set */ int usb_get_bos_descriptor(struct usb_device *dev) { struct device *ddev = &dev->dev; struct usb_bos_descriptor *bos; struct usb_dev_cap_header *cap; + struct usb_ssp_cap_descriptor *ssp_cap; unsigned char *buffer; - int length, total_len, num, i; + int length, total_len, num, i, ssac; + __u8 cap_type; int ret; bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); @@ -965,7 +978,13 @@ int usb_get_bos_descriptor(struct usb_device *dev) dev->bos->desc->bNumDeviceCaps = i; break; } + cap_type = cap->bDevCapabilityType; length = cap->bLength; + if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) { + dev->bos->desc->bNumDeviceCaps = i; + break; + } + total_len -= length; if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { @@ -973,7 +992,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) continue; } - switch (cap->bDevCapabilityType) { + switch (cap_type) { case USB_CAP_TYPE_WIRELESS_USB: /* Wireless USB cap descriptor is handled by wusb */ break; @@ -986,8 +1005,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) (struct usb_ss_cap_descriptor *)buffer; break; case USB_SSP_CAP_TYPE: - dev->bos->ssp_cap = - (struct usb_ssp_cap_descriptor *)buffer; + ssp_cap = (struct usb_ssp_cap_descriptor *)buffer; + ssac = (le32_to_cpu(ssp_cap->bmAttributes) & + USB_SSP_SUBLINK_SPEED_ATTRIBS); + if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac)) + dev->bos->ssp_cap = ssp_cap; break; case CONTAINER_ID_TYPE: dev->bos->ss_id = diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 55dea2e7828f..3de3c750b5f6 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * devices.c * (C) Copyright 1999 Randy Dunlap. @@ -5,20 +6,6 @@ * (proc file per device) * (C) Copyright 1999 Deti Fliegl (new USB architecture) * - * 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 option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * ************************************************************* * * <mountpoint>/devices contains USB topology, device, config, class, @@ -635,7 +622,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, } /* Kernel lock for "lastev" protection */ -static unsigned int usb_device_poll(struct file *file, +static __poll_t usb_device_poll(struct file *file, struct poll_table_struct *wait) { unsigned int event_count; @@ -645,7 +632,7 @@ static unsigned int usb_device_poll(struct file *file, event_count = atomic_read(&device_event.count); if (file->f_version != event_count) { file->f_version = event_count; - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; } return 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e9326f31db8d..d526595bc959 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /*****************************************************************************/ /* @@ -5,20 +6,6 @@ * * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) * - * 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 option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * * This file implements the usbfs/x/y files, where * x is the bus number and y the device number. * @@ -150,7 +137,7 @@ static int usbfs_increase_memory_usage(u64 amount) { u64 lim; - lim = ACCESS_ONCE(usbfs_memory_mb); + lim = READ_ONCE(usbfs_memory_mb); lim <<= 20; atomic64_add(amount, &usbfs_memory_usage); @@ -608,7 +595,7 @@ static void async_completed(struct urb *urb) as->status = urb->status; signr = as->signr; if (signr) { - memset(&sinfo, 0, sizeof(sinfo)); + clear_siginfo(&sinfo); sinfo.si_signo = as->signr; sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; @@ -1455,14 +1442,18 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb int number_of_packets = 0; unsigned int stream_id = 0; void *buf; - - if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | - USBDEVFS_URB_SHORT_NOT_OK | + unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | USBDEVFS_URB_BULK_CONTINUATION | USBDEVFS_URB_NO_FSBR | USBDEVFS_URB_ZERO_PACKET | - USBDEVFS_URB_NO_INTERRUPT)) - return -EINVAL; + USBDEVFS_URB_NO_INTERRUPT; + /* USBDEVFS_URB_ISO_ASAP is a special case */ + if (uurb->type == USBDEVFS_URB_TYPE_ISO) + mask |= USBDEVFS_URB_ISO_ASAP; + + if (uurb->flags & ~mask) + return -EINVAL; + if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX) return -EINVAL; if (uurb->buffer_length > 0 && !uurb->buffer) @@ -1690,8 +1681,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u |= URB_ISO_ASAP; if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) u |= URB_SHORT_NOT_OK; - if (uurb->flags & USBDEVFS_URB_NO_FSBR) - u |= URB_NO_FSBR; if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) u |= URB_ZERO_PACKET; if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) @@ -1833,6 +1822,18 @@ static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) return 0; } +static void compute_isochronous_actual_length(struct urb *urb) +{ + unsigned int i; + + if (urb->number_of_packets > 0) { + urb->actual_length = 0; + for (i = 0; i < urb->number_of_packets; i++) + urb->actual_length += + urb->iso_frame_desc[i].actual_length; + } +} + static int processcompl(struct async *as, void __user * __user *arg) { struct urb *urb = as->urb; @@ -1840,6 +1841,7 @@ static int processcompl(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; + compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) goto err_out; @@ -2008,6 +2010,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; + compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) return -EFAULT; @@ -2567,19 +2570,19 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd, #endif /* No kernel lock - fine */ -static unsigned int usbdev_poll(struct file *file, +static __poll_t usbdev_poll(struct file *file, struct poll_table_struct *wait) { struct usb_dev_state *ps = file->private_data; - unsigned int mask = 0; + __poll_t mask = 0; poll_wait(file, &ps->wait, wait); if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; if (!connected(ps)) - mask |= POLLHUP; + mask |= EPOLLHUP; if (list_empty(&ps->list)) - mask |= POLLERR; + mask |= EPOLLERR; return mask; } @@ -2608,7 +2611,7 @@ static void usbdev_remove(struct usb_device *udev) wake_up_all(&ps->wait); list_del_init(&ps->list); if (ps->discsignr) { - memset(&sinfo, 0, sizeof(sinfo)); + clear_siginfo(&sinfo); sinfo.si_signo = ps->discsignr; sinfo.si_errno = EPIPE; sinfo.si_code = SI_ASYNCIO; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index eb87a259d55c..9792cedfc351 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/driver.c - most of the driver model stuff for usb * @@ -16,7 +17,6 @@ * (C) Copyright Greg Kroah-Hartman 2002-2003 * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -342,8 +342,8 @@ static int usb_probe_interface(struct device *dev) if (driver->disable_hub_initiated_lpm) { lpm_disable_error = usb_unlocked_disable_lpm(udev); if (lpm_disable_error) { - dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n", + __func__, driver->name); error = lpm_disable_error; goto err; } @@ -537,8 +537,8 @@ int usb_driver_claim_interface(struct usb_driver *driver, 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); + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n", + __func__, driver->name); return -ENOMEM; } } @@ -1070,7 +1070,7 @@ static void usb_rebind_intf(struct usb_interface *intf) if (!intf->dev.power.is_prepared) { intf->needs_binding = 0; rc = device_attach(&intf->dev); - if (rc < 0) + if (rc < 0 && rc != -EPROBE_DEFER) dev_warn(&intf->dev, "rebind failed: %d\n", rc); } } @@ -1340,8 +1340,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) int err; u16 devstat; - err = usb_get_status(udev, USB_RECIP_DEVICE, 0, - &devstat); + err = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, + &devstat); if (err) { dev_err(&udev->dev, "Failed to suspend device, error %d\n", @@ -1461,6 +1461,7 @@ static void choose_wakeup(struct usb_device *udev, pm_message_t msg) int usb_suspend(struct device *dev, pm_message_t msg) { struct usb_device *udev = to_usb_device(dev); + int r; unbind_no_pm_drivers_interfaces(udev); @@ -1469,7 +1470,14 @@ int usb_suspend(struct device *dev, pm_message_t msg) * so we may still need to unbind and rebind upon resume */ choose_wakeup(udev, msg); - return usb_suspend_both(udev, msg); + r = usb_suspend_both(udev, msg); + if (r) + return r; + + if (udev->quirks & USB_QUIRK_DISCONNECT_SUSPEND) + usb_port_disable(udev); + + return 0; } /* The device lock is held by the PM core */ diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index a60bc830a056..1c2c04079676 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/endpoint.c * @@ -6,7 +7,6 @@ * (C) Copyright 2006 Novell Inc. * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 * * Endpoint sysfs stuff */ diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 87ad6b6bfee8..65de6f73b672 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/file.c * @@ -14,7 +15,6 @@ * (C) Copyright Greg Kroah-Hartman 2002-2003 * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/module.h> diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index bd3e0c5a6db2..83c14dda6300 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/generic.c - generic driver for USB devices (not interfaces) * @@ -16,7 +17,6 @@ * (C) Copyright Greg Kroah-Hartman 2002-2003 * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/usb.h> diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ea829ad798c0..66fe1b78d952 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -1,19 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (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 - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 75ad6718858c..fc32391a34d5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright Linus Torvalds 1999 * (C) Copyright Johannes Erdfelt 1999-2001 @@ -6,20 +7,6 @@ * (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 - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/bcd.h> @@ -801,9 +788,11 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); /* timer callback */ -static void rh_timer_func (unsigned long _hcd) +static void rh_timer_func (struct timer_list *t) { - usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); + struct usb_hcd *_hcd = from_timer(_hcd, t, rh_timer); + + usb_hcd_poll_rh_status(_hcd); } /*-------------------------------------------------------------------------*/ @@ -2558,9 +2547,7 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, hcd->self.bus_name = bus_name; hcd->self.uses_dma = (sysdev->dma_mask != NULL); - init_timer(&hcd->rh_timer); - hcd->rh_timer.function = rh_timer_func; - hcd->rh_timer.data = (unsigned long) hcd; + timer_setup(&hcd->rh_timer, rh_timer_func, 0); #ifdef CONFIG_PM INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e9ce6bb0b22d..c5c1f6cf3228 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * USB hub driver. * @@ -7,7 +8,6 @@ * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au) * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/kernel.h> @@ -38,6 +38,9 @@ #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 +#define USB_TP_TRANSMISSION_DELAY 40 /* ns */ +#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -1049,12 +1052,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ret = hcd->driver->update_hub_device(hcd, hdev, &hub->tt, GFP_NOIO); if (ret < 0) { - dev_err(hub->intfdev, "Host not " - "accepting hub info " - "update.\n"); - dev_err(hub->intfdev, "LS/FS devices " - "and hubs may not work " - "under this hub\n."); + dev_err(hub->intfdev, + "Host not accepting hub info update\n"); + dev_err(hub->intfdev, + "LS/FS devices and hubs may not work under this hub\n"); } } hub_power_on(hub, true); @@ -1352,6 +1353,20 @@ static int hub_configure(struct usb_hub *hub, goto fail; } + /* + * Accumulate wHubDelay + 40ns for every hub in the tree of devices. + * The resulting value will be used for SetIsochDelay() request. + */ + if (hub_is_superspeed(hdev) || hub_is_superspeedplus(hdev)) { + u32 delay = __le16_to_cpu(hub->descriptor->u.ss.wHubDelay); + + if (hdev->parent) + delay += hdev->parent->hub_delay; + + delay += USB_TP_TRANSMISSION_DELAY; + hdev->hub_delay = min_t(u32, delay, USB_TP_TRANSMISSION_DELAY_MAX); + } + maxchild = hub->descriptor->bNbrPorts; dev_info(hub_dev, "%d port%s detected\n", maxchild, (maxchild == 1) ? "" : "s"); @@ -1482,7 +1497,7 @@ static int hub_configure(struct usb_hub *hub, /* power budgeting mostly matters with bus-powered hubs, * and battery-powered root hubs (may provide just 8 mA). */ - ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus); + ret = usb_get_std_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus); if (ret) { message = "can't get hub status"; goto fail; @@ -3157,7 +3172,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_usb2_hardware_lpm(udev, 0); if (usb_disable_ltm(udev)) { - dev_err(&udev->dev, "Failed to disable LTM before suspend\n."); + dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); status = -ENOMEM; if (PMSG_IS_AUTO(msg)) goto err_ltm; @@ -3279,7 +3294,7 @@ static int finish_port_resume(struct usb_device *udev) */ if (status == 0) { devstatus = 0; - status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, &devstatus); /* If a normal resume failed, try doing a reset-resume */ if (status && !udev->reset_resume && udev->persist_enabled) { @@ -3303,7 +3318,7 @@ static int finish_port_resume(struct usb_device *udev) if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) status = usb_disable_remote_wakeup(udev); } else { - status = usb_get_status(udev, USB_RECIP_INTERFACE, 0, + status = usb_get_std_status(udev, USB_RECIP_INTERFACE, 0, &devstatus); if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW)) @@ -4183,6 +4198,19 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) return ret; } +/* + * usb_port_disable - disable a usb device's upstream port + * @udev: device to disable + * Context: @udev locked, must be able to sleep. + * + * Disables a USB device that isn't in active use. + */ +int usb_port_disable(struct usb_device *udev) +{ + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + + return hub_port_disable(hub, udev->portnum, 0); +} /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * @@ -4586,7 +4614,20 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (retval >= 0) retval = -EMSGSIZE; } else { + u32 delay; + retval = 0; + + delay = udev->parent->hub_delay; + udev->hub_delay = min_t(u32, delay, + USB_TP_TRANSMISSION_DELAY_MAX); + retval = usb_set_isoch_delay(udev); + if (retval) { + dev_dbg(&udev->dev, + "Failed set isoch delay, error %d\n", + retval); + retval = 0; + } break; } } @@ -4853,7 +4894,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, && udev->bus_mA <= unit_load) { u16 devstat; - status = usb_get_status(udev, USB_RECIP_DEVICE, 0, + status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, &devstat); if (status) { dev_dbg(&udev->dev, "get status %d ?\n", status); @@ -4935,6 +4976,15 @@ loop: usb_put_dev(udev); if ((status == -ENOTCONN) || (status == -ENOTSUPP)) break; + + /* When halfway through our retry count, power-cycle the port */ + if (i == (SET_CONFIG_TRIES / 2) - 1) { + dev_info(&port_dev->dev, "attempt power cycle\n"); + usb_hub_set_port_power(hdev, hub, port1, false); + msleep(2 * hub_power_on_good_delay(hub)); + usb_hub_set_port_power(hdev, hub, port1, true); + msleep(hub_power_on_good_delay(hub)); + } } if (hub->hdev->parent || !hcd->driver->port_handed_over || @@ -5462,13 +5512,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ ret = usb_unlocked_disable_lpm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__); goto re_enumerate_no_bos; } ret = usb_disable_ltm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LTM\n.", - __func__); + dev_err(&udev->dev, "%s Failed to disable LTM\n", __func__); goto re_enumerate_no_bos; } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 34c1a7e22aae..2a700ccc868c 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * usb hub driver head file * @@ -8,15 +9,6 @@ * Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com) * * move struct usb_hub to this file. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. */ #include <linux/usb.h> diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index 1af877942110..d775ffea20c3 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * USB port LED trigger * * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> @@ -140,11 +137,17 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data, if (!led_np) return false; - /* Get node of port being added */ - port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1); + /* + * Get node of port being added + * + * FIXME: This is really the device node of the connected device + */ + port_np = usb_of_get_device_node(usb_dev, port1); if (!port_np) return false; + of_node_put(port_np); + /* Amount of trigger sources for this LED */ count = of_count_phandle_with_args(led_np, "trigger-sources", "#trigger-source-cells"); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 371a07d874a3..c64cf6c4a83d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * message.c - synchronous message handling * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/pci.h> /* for scatterlist macros */ @@ -18,6 +18,7 @@ #include <linux/usb/cdc.h> #include <linux/usb/quirks.h> #include <linux/usb/hcd.h> /* for usbcore internals */ +#include <linux/usb/of.h> #include <asm/byteorder.h> #include "usb.h" @@ -776,7 +777,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) * deal with strings at all. Set string_langid to -1 in order to * prevent any string to be retrieved from the device */ if (err < 0) { - dev_err(&dev->dev, "string descriptor 0 read error: %d\n", + dev_info(&dev->dev, "string descriptor 0 read error: %d\n", err); dev->string_langid = -1; return -EPIPE; @@ -915,10 +916,35 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) return ret; } +/* + * usb_set_isoch_delay - informs the device of the packet transmit delay + * @dev: the device whose delay is to be informed + * Context: !in_interrupt() + * + * Since this is an optional request, we don't bother if it fails. + */ +int usb_set_isoch_delay(struct usb_device *dev) +{ + /* skip hub devices */ + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) + return 0; + + /* skip non-SS/non-SSP devices */ + if (dev->speed < USB_SPEED_SUPER) + return 0; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_ISOCH_DELAY, + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, + cpu_to_le16(dev->hub_delay), 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); +} + /** * usb_get_status - issues a GET_STATUS call * @dev: the device whose status is being checked - * @type: USB_RECIP_*; for device, interface, or endpoint + * @recip: USB_RECIP_*; for device, interface, or endpoint + * @type: USB_STATUS_TYPE_*; for standard or PTM status types * @target: zero (for device), else interface or endpoint number * @data: pointer to two bytes of bitmap data * Context: !in_interrupt () @@ -937,24 +963,58 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) * Returns 0 and the status value in *@data (in host byte order) on success, * or else the status code from the underlying usb_control_msg() call. */ -int usb_get_status(struct usb_device *dev, int type, int target, void *data) +int usb_get_status(struct usb_device *dev, int recip, int type, int target, + void *data) { int ret; - __le16 *status = kmalloc(sizeof(*status), GFP_KERNEL); + void *status; + int length; + switch (type) { + case USB_STATUS_TYPE_STANDARD: + length = 2; + break; + case USB_STATUS_TYPE_PTM: + if (recip != USB_RECIP_DEVICE) + return -EINVAL; + + length = 4; + break; + default: + return -EINVAL; + } + + status = kmalloc(length, GFP_KERNEL); if (!status) return -ENOMEM; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status, - sizeof(*status), USB_CTRL_GET_TIMEOUT); + USB_REQ_GET_STATUS, USB_DIR_IN | recip, USB_STATUS_TYPE_STANDARD, + target, status, length, USB_CTRL_GET_TIMEOUT); + + switch (ret) { + case 4: + if (type != USB_STATUS_TYPE_PTM) { + ret = -EIO; + break; + } + + *(u32 *) data = le32_to_cpu(*(__le32 *) status); + ret = 0; + break; + case 2: + if (type != USB_STATUS_TYPE_STANDARD) { + ret = -EIO; + break; + } - if (ret == 2) { - *(u16 *) data = le16_to_cpu(*status); + *(u16 *) data = le16_to_cpu(*(__le16 *) status); ret = 0; - } else if (ret >= 0) { + break; + default: ret = -EIO; } + kfree(status); return ret; } @@ -1320,7 +1380,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * so that the xHCI driver can recalculate the U1/U2 timeouts. */ if (usb_disable_lpm(dev)) { - dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&iface->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); return -ENOMEM; } @@ -1464,7 +1524,7 @@ int usb_reset_configuration(struct usb_device *dev) * that the xHCI driver can recalculate the U1/U2 timeouts. */ if (usb_disable_lpm(dev)) { - dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); return -ENOMEM; } @@ -1548,6 +1608,7 @@ static void usb_release_interface(struct device *dev) kref_put(&intfc->ref, usb_release_interface_cache); usb_put_dev(interface_to_usbdev(intf)); + of_node_put(dev->of_node); kfree(intf); } @@ -1811,7 +1872,7 @@ free_interfaces: * timeouts. */ if (dev->actconfig && usb_disable_lpm(dev)) { - dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); ret = -ENOMEM; goto free_interfaces; @@ -1833,6 +1894,7 @@ free_interfaces: struct usb_interface_cache *intfc; struct usb_interface *intf; struct usb_host_interface *alt; + u8 ifnum; cp->interface[i] = intf = new_interfaces[i]; intfc = cp->intf_cache[i]; @@ -1851,11 +1913,17 @@ free_interfaces: if (!alt) alt = &intf->altsetting[0]; - intf->intf_assoc = - find_iad(dev, cp, alt->desc.bInterfaceNumber); + ifnum = alt->desc.bInterfaceNumber; + intf->intf_assoc = find_iad(dev, cp, ifnum); intf->cur_altsetting = alt; usb_enable_interface(dev, intf, true); intf->dev.parent = &dev->dev; + if (usb_of_has_combined_node(dev)) { + device_set_of_node_from_dev(&intf->dev, &dev->dev); + } else { + intf->dev.of_node = usb_of_get_interface_node(dev, + configuration, ifnum); + } intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; @@ -1870,9 +1938,8 @@ free_interfaces: intf->minor = -1; device_initialize(&intf->dev); pm_runtime_no_callbacks(&intf->dev); - dev_set_name(&intf->dev, "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, alt->desc.bInterfaceNumber); + dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum, + dev->devpath, configuration, ifnum); usb_get_dev(dev); } kfree(new_interfaces); diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index b12a463a3e22..ab474b11523e 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * All the USB notify logic * @@ -7,7 +8,6 @@ * but fixed up to not be so broken. * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 3863bb1ce8c5..fd77442c2d12 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * of.c The helpers for hcd device tree support * * Copyright (C) 2016 Freescale Semiconductor, Inc. - * Author: Peter Chen <peter.chen@freescale.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * Author: Peter Chen <peter.chen@freescale.com> + * Copyright (C) 2017 Johan Hovold <johan@kernel.org> */ #include <linux/of.h> @@ -22,31 +12,99 @@ #include <linux/usb/of.h> /** - * usb_of_get_child_node - Find the device node match port number - * @parent: the parent device node - * @portnum: the port number which device is connecting + * usb_of_get_device_node() - get a USB device node + * @hub: hub to which device is connected + * @port1: one-based index of port * - * Find the node from device tree according to its port number. + * Look up the node of a USB device given its parent hub device and one-based + * port number. * * Return: A pointer to the node with incremented refcount if found, or * %NULL otherwise. */ -struct device_node *usb_of_get_child_node(struct device_node *parent, - int portnum) +struct device_node *usb_of_get_device_node(struct usb_device *hub, int port1) { struct device_node *node; - u32 port; + u32 reg; + + for_each_child_of_node(hub->dev.of_node, node) { + if (of_property_read_u32(node, "reg", ®)) + continue; + + if (reg == port1) + return node; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(usb_of_get_device_node); + +/** + * usb_of_has_combined_node() - determine whether a device has a combined node + * @udev: USB device + * + * Determine whether a USB device has a so called combined node which is + * shared with its sole interface. This is the case if and only if the device + * has a node and its decriptors report the following: + * + * 1) bDeviceClass is 0 or 9, and + * 2) bNumConfigurations is 1, and + * 3) bNumInterfaces is 1. + * + * Return: True iff the device has a device node and its descriptors match the + * criteria for a combined node. + */ +bool usb_of_has_combined_node(struct usb_device *udev) +{ + struct usb_device_descriptor *ddesc = &udev->descriptor; + struct usb_config_descriptor *cdesc; - for_each_child_of_node(parent, node) { - if (!of_property_read_u32(node, "reg", &port)) { - if (port == portnum) - return node; + if (!udev->dev.of_node) + return false; + + switch (ddesc->bDeviceClass) { + case USB_CLASS_PER_INTERFACE: + case USB_CLASS_HUB: + if (ddesc->bNumConfigurations == 1) { + cdesc = &udev->config->desc; + if (cdesc->bNumInterfaces == 1) + return true; } } + return false; +} +EXPORT_SYMBOL_GPL(usb_of_has_combined_node); + +/** + * usb_of_get_interface_node() - get a USB interface node + * @udev: USB device of interface + * @config: configuration value + * @ifnum: interface number + * + * Look up the node of a USB interface given its USB device, configuration + * value and interface number. + * + * Return: A pointer to the node with incremented refcount if found, or + * %NULL otherwise. + */ +struct device_node * +usb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum) +{ + struct device_node *node; + u32 reg[2]; + + for_each_child_of_node(udev->dev.of_node, node) { + if (of_property_read_u32_array(node, "reg", reg, 2)) + continue; + + if (reg[0] == ifnum && reg[1] == config) + return node; + } + return NULL; } -EXPORT_SYMBOL_GPL(usb_of_get_child_node); +EXPORT_SYMBOL_GPL(usb_of_get_interface_node); /** * usb_of_get_companion_dev - Find the companion device diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 085049d37d7a..2ae90158ded7 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * drivers/usb/core/otg_whitelist.h * * Copyright (C) 2004 Texas Instruments - * - * 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 option) any later version. */ /* diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 460c855be0d0..1a01e9ad3804 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * usb port device code * * Copyright (C) 2012 Intel Corp * * Author: Lan Tianyu <tianyu.lan@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * */ #include <linux/slab.h> diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index a6aaf2f193a4..f4a548471f0f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -1,14 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * USB device quirk handling logic and table * * Copyright (c) 2007 Oliver Neukum * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> - * - * 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, version 2. - * - * */ #include <linux/usb.h> @@ -57,10 +52,11 @@ static const struct usb_device_id usb_quirk_list[] = { /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Logitech HD Pro Webcams C920, C920-C and C930e */ + /* Logitech HD Pro Webcams C920, C920-C, C925e and C930e */ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x085b), .driver_info = USB_QUIRK_DELAY_INIT }, /* Logitech ConferenceCam CC3000e */ { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -151,6 +147,12 @@ static const struct usb_device_id usb_quirk_list[] = { /* appletouch */ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Genesys Logic hub, internally used by KY-688 USB 3.1 Type-C Hub */ + { USB_DEVICE(0x05e3, 0x0612), .driver_info = USB_QUIRK_NO_LPM }, + + /* ELSA MicroLink 56K */ + { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */ { USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM }, @@ -203,6 +205,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + /* Huawei 4G LTE module */ + { USB_DEVICE(0x12d1, 0x15bb), .driver_info = + USB_QUIRK_DISCONNECT_SUSPEND }, + { USB_DEVICE(0x12d1, 0x15c3), .driver_info = + USB_QUIRK_DISCONNECT_SUSPEND }, + /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -218,9 +226,15 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Corsair K70 RGB */ + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair Strafe RGB */ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair K70 LUX */ + { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, + /* MIDI keyboard WORLDE MINI */ { USB_DEVICE(0x1c75, 0x0204), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d930bfda4010..27bb34043053 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/sysfs.c * @@ -8,7 +9,6 @@ * All of the sysfs file attributes for usb devices and interfaces. * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ @@ -654,7 +654,8 @@ static int add_power_attributes(struct device *dev) if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); - if (udev->speed == USB_SPEED_SUPER && + if ((udev->speed == USB_SPEED_SUPER || + udev->speed == USB_SPEED_SUPER_PLUS) && udev->lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb3_hardware_lpm_attr_group); @@ -973,7 +974,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr, char *string; intf = to_usb_interface(dev); - string = ACCESS_ONCE(intf->cur_altsetting->string); + string = READ_ONCE(intf->cur_altsetting->string); if (!string) return 0; return sprintf(buf, "%s\n", string); @@ -989,7 +990,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); - alt = ACCESS_ONCE(intf->cur_altsetting); + alt = READ_ONCE(intf->cur_altsetting); return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" "ic%02Xisc%02Xip%02Xin%02X\n", diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 47903d510955..796c9b149728 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/module.h> @@ -187,6 +187,31 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); /*-------------------------------------------------------------------*/ +static const int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + +/** + * usb_urb_ep_type_check - sanity check of endpoint in the given urb + * @urb: urb to be checked + * + * This performs a light-weight sanity check for the endpoint in the + * given urb. It returns 0 if the urb contains a valid endpoint, otherwise + * a negative error code. + */ +int usb_urb_ep_type_check(const struct urb *urb) +{ + const struct usb_host_endpoint *ep; + + ep = usb_pipe_endpoint(urb->dev, urb->pipe); + if (!ep) + return -EINVAL; + if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(usb_urb_ep_type_check); + /** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request @@ -326,9 +351,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; @@ -444,7 +466,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) */ /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + if (usb_urb_ep_type_check(urb)) dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); @@ -457,9 +479,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case USB_ENDPOINT_XFER_CONTROL: - allowed |= URB_NO_FSBR; /* only affects UHCI */ - /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; @@ -492,6 +511,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if ((urb->interval < 6) && (xfertype == USB_ENDPOINT_XFER_INT)) return -EINVAL; + /* fall through */ default: if (urb->interval <= 0) return -EINVAL; diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index ef9cf4a21afe..84da17460568 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * USB-ACPI glue code * * Copyright 2012 Red Hat <mjg@redhat.com> - * - * 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, version 2. - * */ #include <linux/module.h> #include <linux/usb.h> diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 17681d5638ac..2f5fbc56a9dd 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/usb.c * @@ -13,7 +14,6 @@ * (C) Copyright Greg Kroah-Hartman 2002-2003 * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -645,8 +645,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, raw_port = usb_hcd_find_raw_port_number(usb_hcd, port1); } - dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node, - raw_port); + dev->dev.of_node = usb_of_get_device_node(parent, raw_port); /* hub driver sets up TT records */ } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index dc6949248823..149cc7480971 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/pm.h> @@ -40,6 +40,7 @@ extern int usb_remove_device(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern int usb_set_isoch_delay(struct usb_device *dev); extern int usb_get_bos_descriptor(struct usb_device *dev); extern void usb_release_bos_descriptor(struct usb_device *dev); extern char *usb_cache_string(struct usb_device *udev, int index); @@ -73,6 +74,7 @@ extern void usb_hub_cleanup(void); extern int usb_major_init(void); extern void usb_major_cleanup(void); extern int usb_device_supports_lpm(struct usb_device *udev); +extern int usb_port_disable(struct usb_device *udev); #ifdef CONFIG_PM |