summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:02:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 01:02:30 +0000
commit76cb841cb886eef6b3bee341a2266c76578724ad (patch)
treef5892e5ba6cc11949952a6ce4ecbe6d516d6ce58 /drivers/usb/core
parentInitial commit. (diff)
downloadlinux-76cb841cb886eef6b3bee341a2266c76578724ad.tar.xz
linux-76cb841cb886eef6b3bee341a2266c76578724ad.zip
Adding upstream version 4.19.249.upstream/4.19.249
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/Kconfig92
-rw-r--r--drivers/usb/core/Makefile17
-rw-r--r--drivers/usb/core/buffer.c173
-rw-r--r--drivers/usb/core/config.c1103
-rw-r--r--drivers/usb/core/devices.c645
-rw-r--r--drivers/usb/core/devio.c2705
-rw-r--r--drivers/usb/core/driver.c1928
-rw-r--r--drivers/usb/core/endpoint.c218
-rw-r--r--drivers/usb/core/file.c247
-rw-r--r--drivers/usb/core/generic.c254
-rw-r--r--drivers/usb/core/hcd-pci.c621
-rw-r--r--drivers/usb/core/hcd.c3087
-rw-r--r--drivers/usb/core/hub.c6079
-rw-r--r--drivers/usb/core/hub.h165
-rw-r--r--drivers/usb/core/ledtrig-usbport.c368
-rw-r--r--drivers/usb/core/message.c2269
-rw-r--r--drivers/usb/core/notify.c71
-rw-r--r--drivers/usb/core/of.c107
-rw-r--r--drivers/usb/core/otg_whitelist.h106
-rw-r--r--drivers/usb/core/phy.c197
-rw-r--r--drivers/usb/core/phy.h27
-rw-r--r--drivers/usb/core/port.c604
-rw-r--r--drivers/usb/core/quirks.c713
-rw-r--r--drivers/usb/core/sysfs.c1161
-rw-r--r--drivers/usb/core/urb.c1029
-rw-r--r--drivers/usb/core/usb-acpi.c244
-rw-r--r--drivers/usb/core/usb.c1263
-rw-r--r--drivers/usb/core/usb.h206
28 files changed, 25699 insertions, 0 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
new file mode 100644
index 000000000..4d75d9a80
--- /dev/null
+++ b/drivers/usb/core/Kconfig
@@ -0,0 +1,92 @@
+#
+# USB Core configuration
+#
+config USB_ANNOUNCE_NEW_DEVICES
+ bool "USB announce new devices"
+ help
+ Say Y here if you want the USB core to always announce the
+ idVendor, idProduct, Manufacturer, Product, and SerialNumber
+ strings for every new USB device to the syslog. This option is
+ usually used by distro vendors to help with debugging and to
+ let users know what specific device was added to the machine
+ in what location.
+
+ If you do not want this kind of information sent to the system
+ log, or have any doubts about this, say N here.
+
+comment "Miscellaneous USB options"
+
+config USB_DEFAULT_PERSIST
+ bool "Enable USB persist by default"
+ default y
+ help
+ Say N here if you don't want USB power session persistence
+ enabled by default. If you say N it will make suspended USB
+ devices that lose power get reenumerated as if they had been
+ unplugged, causing any mounted filesystems to be lost. The
+ persist feature can still be enabled for individual devices
+ through the power/persist sysfs node. See
+ Documentation/driver-api/usb/persist.rst for more info.
+
+ If you have any questions about this, say Y here, only say N
+ if you know exactly what you are doing.
+
+config USB_DYNAMIC_MINORS
+ bool "Dynamic USB minor allocation"
+ help
+ If you say Y here, the USB subsystem will use dynamic minor
+ allocation for any device that uses the USB major number.
+ This means that you can have more than 16 of a single type
+ of device (like USB printers).
+
+ If you are unsure about this, say N here.
+
+config USB_OTG
+ bool "OTG support"
+ depends on PM
+ default n
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role is decided by the type of
+ plug inserted and can be changed later when two dual
+ role devices talk to each other.
+
+ Select this only if your board has Mini-AB/Micro-AB
+ connector.
+
+config USB_OTG_WHITELIST
+ bool "Rely on OTG and EH Targeted Peripherals List"
+ depends on USB
+ help
+ If you say Y here, the "otg_whitelist.h" file will be used as a
+ product whitelist, so USB peripherals not listed there will be
+ rejected during enumeration. This behavior is required by the
+ USB OTG and EH specification for all devices not on your product's
+ "Targeted Peripherals List". "Embedded Hosts" are likewise
+ allowed to support only a limited number of peripherals.
+
+config USB_OTG_BLACKLIST_HUB
+ bool "Disable external hubs"
+ depends on USB_OTG || EXPERT
+ help
+ If you say Y here, then Linux will refuse to enumerate
+ external hubs. OTG hosts are allowed to reduce hardware
+ and software costs by not supporting external hubs. So
+ are "Embedded Hosts" that don't offer OTG support.
+
+config USB_OTG_FSM
+ tristate "USB 2.0 OTG FSM implementation"
+ depends on USB && USB_OTG
+ select USB_PHY
+ help
+ Implements OTG Finite State Machine as specified in On-The-Go
+ and Embedded Host Supplement to the USB Revision 2.0 Specification.
+
+config USB_LEDS_TRIGGER_USBPORT
+ tristate "USB port LED trigger"
+ depends on USB && LEDS_TRIGGERS
+ help
+ This driver allows LEDs to be controlled by USB events. Enabling this
+ trigger allows specifying list of USB ports that should turn on LED
+ when some USB device gets connected.
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
new file mode 100644
index 000000000..18e874b04
--- /dev/null
+++ b/drivers/usb/core/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for USB Core files and filesystem
+#
+
+usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
+usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
+usbcore-y += devio.o notify.o generic.o quirks.o devices.o
+usbcore-y += phy.o port.o
+
+usbcore-$(CONFIG_OF) += of.o
+usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
+usbcore-$(CONFIG_ACPI) += usb-acpi.o
+
+obj-$(CONFIG_USB) += usbcore.o
+
+obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT) += ledtrig-usbport.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
new file mode 100644
index 000000000..77eef8acf
--- /dev/null
+++ b/drivers/usb/core/buffer.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DMA memory management for framework level HCD code (hc_driver)
+ *
+ * This implementation plugs in through generic "usb_bus" level methods,
+ * and should work with all USB controllers, regardless of bus type.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+
+/*
+ * DMA-Coherent Buffers
+ */
+
+/* FIXME tune these based on pool statistics ... */
+static size_t pool_max[HCD_BUFFER_POOLS] = {
+ 32, 128, 512, 2048,
+};
+
+void __init usb_init_pool_max(void)
+{
+ /*
+ * The pool_max values must never be smaller than
+ * ARCH_KMALLOC_MINALIGN.
+ */
+ if (ARCH_KMALLOC_MINALIGN <= 32)
+ ; /* Original value is okay */
+ else if (ARCH_KMALLOC_MINALIGN <= 64)
+ pool_max[0] = 64;
+ else if (ARCH_KMALLOC_MINALIGN <= 128)
+ pool_max[0] = 0; /* Don't use this pool */
+ else
+ BUILD_BUG(); /* We don't allow this */
+}
+
+/* SETUP primitives */
+
+/**
+ * hcd_buffer_create - initialize buffer pools
+ * @hcd: the bus whose buffer pools are to be initialized
+ * Context: !in_interrupt()
+ *
+ * Call this as part of initializing a host controller that uses the dma
+ * memory allocators. It initializes some pools of dma-coherent memory that
+ * will be shared by all drivers using that controller.
+ *
+ * Call hcd_buffer_destroy() to clean up after using those pools.
+ *
+ * Return: 0 if successful. A negative errno value otherwise.
+ */
+int hcd_buffer_create(struct usb_hcd *hcd)
+{
+ char name[16];
+ int i, size;
+
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!is_device_dma_capable(hcd->self.sysdev) &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM)))
+ return 0;
+
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ size = pool_max[i];
+ if (!size)
+ continue;
+ snprintf(name, sizeof(name), "buffer-%d", size);
+ hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
+ size, size, 0);
+ if (!hcd->pool[i]) {
+ hcd_buffer_destroy(hcd);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * hcd_buffer_destroy - deallocate buffer pools
+ * @hcd: the bus whose buffer pools are to be destroyed
+ * Context: !in_interrupt()
+ *
+ * This frees the buffer pools created by hcd_buffer_create().
+ */
+void hcd_buffer_destroy(struct usb_hcd *hcd)
+{
+ int i;
+
+ if (!IS_ENABLED(CONFIG_HAS_DMA))
+ 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;
+ }
+ }
+}
+
+
+/* sometimes alloc/free could use kmalloc with GFP_DMA, for
+ * better sharing and to leverage mm/slab.c intelligence.
+ */
+
+void *hcd_buffer_alloc(
+ struct usb_bus *bus,
+ size_t size,
+ gfp_t mem_flags,
+ dma_addr_t *dma
+)
+{
+ struct usb_hcd *hcd = bus_to_hcd(bus);
+ int i;
+
+ if (size == 0)
+ return NULL;
+
+ /* some USB hosts just use PIO */
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!is_device_dma_capable(bus->sysdev) &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+ *dma = ~(dma_addr_t) 0;
+ return kmalloc(size, mem_flags);
+ }
+
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ if (size <= pool_max[i])
+ return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
+ }
+ return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
+}
+
+void hcd_buffer_free(
+ struct usb_bus *bus,
+ size_t size,
+ void *addr,
+ dma_addr_t dma
+)
+{
+ struct usb_hcd *hcd = bus_to_hcd(bus);
+ int i;
+
+ if (!addr)
+ return;
+
+ if (!IS_ENABLED(CONFIG_HAS_DMA) ||
+ (!is_device_dma_capable(bus->sysdev) &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+ kfree(addr);
+ return;
+ }
+
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ if (size <= pool_max[i]) {
+ dma_pool_free(hcd->pool[i], addr, dma);
+ return;
+ }
+ }
+ dma_free_coherent(hcd->self.sysdev, size, addr, dma);
+}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
new file mode 100644
index 000000000..0410f05cc
--- /dev/null
+++ b/drivers/usb/core/config.c
@@ -0,0 +1,1103 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/quirks.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <asm/byteorder.h>
+#include "usb.h"
+
+
+#define USB_MAXALTSETTING 128 /* Hard limit */
+
+#define USB_MAXCONFIG 8 /* Arbitrary limit */
+
+
+static inline const char *plural(int n)
+{
+ return (n == 1 ? "" : "s");
+}
+
+static int find_next_descriptor(unsigned char *buffer, int size,
+ int dt1, int dt2, int *num_skipped)
+{
+ struct usb_descriptor_header *h;
+ int n = 0;
+ unsigned char *buffer0 = buffer;
+
+ /* Find the next descriptor of type dt1 or dt2 */
+ while (size > 0) {
+ h = (struct usb_descriptor_header *) buffer;
+ if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)
+ break;
+ buffer += h->bLength;
+ size -= h->bLength;
+ ++n;
+ }
+
+ /* Store the number of descriptors skipped and return the
+ * number of bytes skipped */
+ if (num_skipped)
+ *num_skipped = n;
+ return buffer - buffer0;
+}
+
+static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
+ int cfgno, int inum, int asnum, struct usb_host_endpoint *ep,
+ unsigned char *buffer, int size)
+{
+ struct usb_ssp_isoc_ep_comp_descriptor *desc;
+
+ /*
+ * The SuperSpeedPlus Isoc endpoint companion descriptor immediately
+ * follows the SuperSpeed Endpoint Companion descriptor
+ */
+ desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
+ if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
+ size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
+ dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
+ "for config %d interface %d altsetting %d ep %d.\n",
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ return;
+ }
+ memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE);
+}
+
+static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
+ int inum, int asnum, struct usb_host_endpoint *ep,
+ unsigned char *buffer, int size)
+{
+ struct usb_ss_ep_comp_descriptor *desc;
+ int max_tx;
+
+ /* The SuperSpeed endpoint companion descriptor is supposed to
+ * be the first thing immediately following the endpoint descriptor.
+ */
+ desc = (struct usb_ss_ep_comp_descriptor *) buffer;
+
+ if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
+ size < USB_DT_SS_EP_COMP_SIZE) {
+ dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
+ " interface %d altsetting %d ep %d: "
+ "using minimum values\n",
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+
+ /* Fill in some default values.
+ * Leave bmAttributes as zero, which will mean no streams for
+ * bulk, and isoc won't support multiple bursts of packets.
+ * With bursts of only one packet, and a Mult of 1, the max
+ * amount of data moved per endpoint service interval is one
+ * packet.
+ */
+ ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE;
+ ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
+ if (usb_endpoint_xfer_isoc(&ep->desc) ||
+ usb_endpoint_xfer_int(&ep->desc))
+ ep->ss_ep_comp.wBytesPerInterval =
+ ep->desc.wMaxPacketSize;
+ return;
+ }
+ buffer += desc->bLength;
+ size -= desc->bLength;
+ memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
+
+ /* Check the various values */
+ if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
+ dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to zero\n", desc->bMaxBurst,
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bMaxBurst = 0;
+ } else if (desc->bMaxBurst > 15) {
+ dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to 15\n", desc->bMaxBurst,
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bMaxBurst = 15;
+ }
+
+ if ((usb_endpoint_xfer_control(&ep->desc) ||
+ usb_endpoint_xfer_int(&ep->desc)) &&
+ desc->bmAttributes != 0) {
+ dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to zero\n",
+ usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
+ desc->bmAttributes,
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bmAttributes = 0;
+ } else if (usb_endpoint_xfer_bulk(&ep->desc) &&
+ desc->bmAttributes > 16) {
+ dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to max\n",
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bmAttributes = 16;
+ } else if (usb_endpoint_xfer_isoc(&ep->desc) &&
+ !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
+ USB_SS_MULT(desc->bmAttributes) > 3) {
+ dev_warn(ddev, "Isoc endpoint has Mult of %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to 3\n",
+ USB_SS_MULT(desc->bmAttributes),
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bmAttributes = 2;
+ }
+
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ max_tx = (desc->bMaxBurst + 1) *
+ (USB_SS_MULT(desc->bmAttributes)) *
+ usb_endpoint_maxp(&ep->desc);
+ else if (usb_endpoint_xfer_int(&ep->desc))
+ max_tx = usb_endpoint_maxp(&ep->desc) *
+ (desc->bMaxBurst + 1);
+ else
+ max_tx = 999999;
+ if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
+ dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to %d\n",
+ usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
+ le16_to_cpu(desc->wBytesPerInterval),
+ cfgno, inum, asnum, ep->desc.bEndpointAddress,
+ max_tx);
+ ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
+ }
+ /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */
+ if (usb_endpoint_xfer_isoc(&ep->desc) &&
+ USB_SS_SSP_ISOC_COMP(desc->bmAttributes))
+ usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
+ ep, buffer, size);
+}
+
+static const unsigned short low_speed_maxpacket_maxes[4] = {
+ [USB_ENDPOINT_XFER_CONTROL] = 8,
+ [USB_ENDPOINT_XFER_ISOC] = 0,
+ [USB_ENDPOINT_XFER_BULK] = 0,
+ [USB_ENDPOINT_XFER_INT] = 8,
+};
+static const unsigned short full_speed_maxpacket_maxes[4] = {
+ [USB_ENDPOINT_XFER_CONTROL] = 64,
+ [USB_ENDPOINT_XFER_ISOC] = 1023,
+ [USB_ENDPOINT_XFER_BULK] = 64,
+ [USB_ENDPOINT_XFER_INT] = 64,
+};
+static const unsigned short high_speed_maxpacket_maxes[4] = {
+ [USB_ENDPOINT_XFER_CONTROL] = 64,
+ [USB_ENDPOINT_XFER_ISOC] = 1024,
+
+ /* Bulk should be 512, but some devices use 1024: we will warn below */
+ [USB_ENDPOINT_XFER_BULK] = 1024,
+ [USB_ENDPOINT_XFER_INT] = 1024,
+};
+static const unsigned short super_speed_maxpacket_maxes[4] = {
+ [USB_ENDPOINT_XFER_CONTROL] = 512,
+ [USB_ENDPOINT_XFER_ISOC] = 1024,
+ [USB_ENDPOINT_XFER_BULK] = 1024,
+ [USB_ENDPOINT_XFER_INT] = 1024,
+};
+
+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)
+{
+ struct usb_device *udev = to_usb_device(ddev);
+ unsigned char *buffer0 = buffer;
+ struct usb_endpoint_descriptor *d;
+ struct usb_host_endpoint *endpoint;
+ int n, i, j, retval;
+ unsigned int maxp;
+ const unsigned short *maxpacket_maxes;
+
+ d = (struct usb_endpoint_descriptor *) buffer;
+ buffer += d->bLength;
+ size -= d->bLength;
+
+ if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)
+ n = USB_DT_ENDPOINT_AUDIO_SIZE;
+ else if (d->bLength >= USB_DT_ENDPOINT_SIZE)
+ n = USB_DT_ENDPOINT_SIZE;
+ else {
+ dev_warn(ddev, "config %d interface %d altsetting %d has an "
+ "invalid endpoint descriptor of length %d, skipping\n",
+ cfgno, inum, asnum, d->bLength);
+ goto skip_to_next_endpoint_or_interface_descriptor;
+ }
+
+ i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
+ if (i >= 16 || i == 0) {
+ dev_warn(ddev, "config %d interface %d altsetting %d has an "
+ "invalid endpoint with address 0x%X, skipping\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
+ goto skip_to_next_endpoint_or_interface_descriptor;
+ }
+
+ /* Only store as many endpoints as we have room for */
+ if (ifp->desc.bNumEndpoints >= num_ep)
+ goto skip_to_next_endpoint_or_interface_descriptor;
+
+ /* Check for duplicate endpoint addresses */
+ 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;
+ }
+
+ /* Ignore blacklisted endpoints */
+ if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) {
+ if (usb_endpoint_is_blacklisted(udev, ifp, d)) {
+ dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted 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];
+ ++ifp->desc.bNumEndpoints;
+
+ memcpy(&endpoint->desc, d, n);
+ INIT_LIST_HEAD(&endpoint->urb_list);
+
+ /*
+ * Fix up bInterval values outside the legal range.
+ * Use 10 or 8 ms if no proper value can be guessed.
+ */
+ i = 0; /* i = min, j = max, n = default */
+ j = 255;
+ if (usb_endpoint_xfer_int(d)) {
+ i = 1;
+ switch (to_usb_device(ddev)->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER:
+ case USB_SPEED_HIGH:
+ /*
+ * Many device manufacturers are using full-speed
+ * bInterval values in high-speed interrupt endpoint
+ * descriptors. Try to fix those and fall back to an
+ * 8-ms default value otherwise.
+ */
+ n = fls(d->bInterval*8);
+ if (n == 0)
+ n = 7; /* 8 ms = 2^(7-1) uframes */
+ j = 16;
+
+ /*
+ * Adjust bInterval for quirked devices.
+ */
+ /*
+ * This quirk fixes bIntervals reported in ms.
+ */
+ if (to_usb_device(ddev)->quirks &
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
+ n = clamp(fls(d->bInterval) + 3, i, j);
+ i = j = n;
+ }
+ /*
+ * This quirk fixes bIntervals reported in
+ * linear microframes.
+ */
+ if (to_usb_device(ddev)->quirks &
+ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {
+ n = clamp(fls(d->bInterval), i, j);
+ i = j = n;
+ }
+ break;
+ default: /* USB_SPEED_FULL or _LOW */
+ /*
+ * For low-speed, 10 ms is the official minimum.
+ * But some "overclocked" devices might want faster
+ * polling so we'll allow it.
+ */
+ n = 10;
+ break;
+ }
+ } else if (usb_endpoint_xfer_isoc(d)) {
+ i = 1;
+ j = 16;
+ switch (to_usb_device(ddev)->speed) {
+ case USB_SPEED_HIGH:
+ n = 7; /* 8 ms = 2^(7-1) uframes */
+ break;
+ default: /* USB_SPEED_FULL */
+ n = 4; /* 8 ms = 2^(4-1) frames */
+ break;
+ }
+ }
+ if (d->bInterval < i || d->bInterval > j) {
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "endpoint 0x%X has an invalid bInterval %d, "
+ "changing to %d\n",
+ cfgno, inum, asnum,
+ d->bEndpointAddress, d->bInterval, n);
+ endpoint->desc.bInterval = n;
+ }
+
+ /* Some buggy low-speed devices have Bulk endpoints, which is
+ * explicitly forbidden by the USB spec. In an attempt to make
+ * them usable, we will try treating them as Interrupt endpoints.
+ */
+ if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
+ usb_endpoint_xfer_bulk(d)) {
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "endpoint 0x%X is Bulk; changing to Interrupt\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
+ endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
+ endpoint->desc.bInterval = 1;
+ if (usb_endpoint_maxp(&endpoint->desc) > 8)
+ endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
+ }
+
+ /*
+ * 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 = le16_to_cpu(endpoint->desc.wMaxPacketSize);
+ 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 */
+ switch (to_usb_device(ddev)->speed) {
+ case USB_SPEED_LOW:
+ maxpacket_maxes = low_speed_maxpacket_maxes;
+ break;
+ case USB_SPEED_FULL:
+ maxpacket_maxes = full_speed_maxpacket_maxes;
+ break;
+ case USB_SPEED_HIGH:
+ /* Multiple-transactions bits are allowed only for HS periodic endpoints */
+ if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
+ i = maxp & USB_EP_MAXP_MULT_MASK;
+ maxp &= ~i;
+ }
+ /* fallthrough */
+ default:
+ maxpacket_maxes = high_speed_maxpacket_maxes;
+ break;
+ case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
+ maxpacket_maxes = super_speed_maxpacket_maxes;
+ break;
+ }
+ j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
+
+ if (maxp > j) {
+ dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
+ cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
+ maxp = j;
+ endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
+ }
+
+ /*
+ * Some buggy high speed devices have bulk endpoints using
+ * maxpacket sizes other than 512. High speed HCDs may not
+ * be able to handle that particular bug, so let's warn...
+ */
+ if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
+ && usb_endpoint_xfer_bulk(d)) {
+ if (maxp != 512)
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "bulk endpoint 0x%X has invalid maxpacket %d\n",
+ cfgno, inum, asnum, d->bEndpointAddress,
+ maxp);
+ }
+
+ /* Parse a possible SuperSpeed endpoint companion descriptor */
+ if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
+ usb_parse_ss_endpoint_companion(ddev, cfgno,
+ inum, asnum, endpoint, buffer, size);
+
+ /* Skip over any Class Specific or Vendor Specific descriptors;
+ * find the next endpoint or interface descriptor */
+ endpoint->extra = buffer;
+ i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+ USB_DT_INTERFACE, &n);
+ endpoint->extralen = i;
+ retval = buffer - buffer0 + i;
+ if (n > 0)
+ dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
+ n, plural(n), "endpoint");
+ return retval;
+
+skip_to_next_endpoint_or_interface_descriptor:
+ i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+ USB_DT_INTERFACE, NULL);
+ return buffer - buffer0 + i;
+}
+
+void usb_release_interface_cache(struct kref *ref)
+{
+ struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
+ int j;
+
+ for (j = 0; j < intfc->num_altsetting; j++) {
+ struct usb_host_interface *alt = &intfc->altsetting[j];
+
+ kfree(alt->endpoint);
+ kfree(alt->string);
+ }
+ kfree(intfc);
+}
+
+static int usb_parse_interface(struct device *ddev, int cfgno,
+ struct usb_host_config *config, unsigned char *buffer, int size,
+ u8 inums[], u8 nalts[])
+{
+ unsigned char *buffer0 = buffer;
+ struct usb_interface_descriptor *d;
+ int inum, asnum;
+ struct usb_interface_cache *intfc;
+ struct usb_host_interface *alt;
+ int i, n;
+ int len, retval;
+ int num_ep, num_ep_orig;
+
+ d = (struct usb_interface_descriptor *) buffer;
+ buffer += d->bLength;
+ size -= d->bLength;
+
+ if (d->bLength < USB_DT_INTERFACE_SIZE)
+ goto skip_to_next_interface_descriptor;
+
+ /* Which interface entry is this? */
+ intfc = NULL;
+ inum = d->bInterfaceNumber;
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ if (inums[i] == inum) {
+ intfc = config->intf_cache[i];
+ break;
+ }
+ }
+ if (!intfc || intfc->num_altsetting >= nalts[i])
+ goto skip_to_next_interface_descriptor;
+
+ /* Check for duplicate altsetting entries */
+ asnum = d->bAlternateSetting;
+ for ((i = 0, alt = &intfc->altsetting[0]);
+ i < intfc->num_altsetting;
+ (++i, ++alt)) {
+ if (alt->desc.bAlternateSetting == asnum) {
+ dev_warn(ddev, "Duplicate descriptor for config %d "
+ "interface %d altsetting %d, skipping\n",
+ cfgno, inum, asnum);
+ goto skip_to_next_interface_descriptor;
+ }
+ }
+
+ ++intfc->num_altsetting;
+ memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);
+
+ /* Skip over any Class Specific or Vendor Specific descriptors;
+ * find the first endpoint or interface descriptor */
+ alt->extra = buffer;
+ i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+ USB_DT_INTERFACE, &n);
+ alt->extralen = i;
+ if (n > 0)
+ dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
+ n, plural(n), "interface");
+ buffer += i;
+ size -= i;
+
+ /* Allocate space for the right(?) number of endpoints */
+ num_ep = num_ep_orig = alt->desc.bNumEndpoints;
+ alt->desc.bNumEndpoints = 0; /* Use as a counter */
+ if (num_ep > USB_MAXENDPOINTS) {
+ dev_warn(ddev, "too many endpoints for config %d interface %d "
+ "altsetting %d: %d, using maximum allowed: %d\n",
+ cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
+ num_ep = USB_MAXENDPOINTS;
+ }
+
+ if (num_ep > 0) {
+ /* Can't allocate 0 bytes */
+ len = sizeof(struct usb_host_endpoint) * num_ep;
+ alt->endpoint = kzalloc(len, GFP_KERNEL);
+ if (!alt->endpoint)
+ return -ENOMEM;
+ }
+
+ /* Parse all the endpoint descriptors */
+ n = 0;
+ while (size > 0) {
+ if (((struct usb_descriptor_header *) buffer)->bDescriptorType
+ == USB_DT_INTERFACE)
+ break;
+ retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum,
+ alt, num_ep, buffer, size);
+ if (retval < 0)
+ return retval;
+ ++n;
+
+ buffer += retval;
+ size -= retval;
+ }
+
+ if (n != num_ep_orig)
+ dev_warn(ddev, "config %d interface %d altsetting %d has %d "
+ "endpoint descriptor%s, different from the interface "
+ "descriptor's value: %d\n",
+ cfgno, inum, asnum, n, plural(n), num_ep_orig);
+ return buffer - buffer0;
+
+skip_to_next_interface_descriptor:
+ i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
+ USB_DT_INTERFACE, NULL);
+ return buffer - buffer0 + i;
+}
+
+static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
+ struct usb_host_config *config, unsigned char *buffer, int size)
+{
+ struct device *ddev = &dev->dev;
+ unsigned char *buffer0 = buffer;
+ int cfgno;
+ int nintf, nintf_orig;
+ int i, j, n;
+ struct usb_interface_cache *intfc;
+ unsigned char *buffer2;
+ int size2;
+ struct usb_descriptor_header *header;
+ int len, retval;
+ u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
+ 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) {
+ dev_err(ddev, "invalid descriptor for config index %d: "
+ "type = 0x%X, length = %d\n", cfgidx,
+ config->desc.bDescriptorType, config->desc.bLength);
+ return -EINVAL;
+ }
+ cfgno = config->desc.bConfigurationValue;
+
+ buffer += config->desc.bLength;
+ size -= config->desc.bLength;
+
+ if (nintf > USB_MAXINTERFACES) {
+ dev_warn(ddev, "config %d has too many interfaces: %d, "
+ "using maximum allowed: %d\n",
+ cfgno, nintf, USB_MAXINTERFACES);
+ nintf = USB_MAXINTERFACES;
+ }
+
+ /* Go through the descriptors, checking their length and counting the
+ * number of altsettings for each interface */
+ n = 0;
+ for ((buffer2 = buffer, size2 = size);
+ size2 > 0;
+ (buffer2 += header->bLength, size2 -= header->bLength)) {
+
+ if (size2 < sizeof(struct usb_descriptor_header)) {
+ dev_warn(ddev, "config %d descriptor has %d excess "
+ "byte%s, ignoring\n",
+ cfgno, size2, plural(size2));
+ break;
+ }
+
+ header = (struct usb_descriptor_header *) buffer2;
+ if ((header->bLength > size2) || (header->bLength < 2)) {
+ dev_warn(ddev, "config %d has an invalid descriptor "
+ "of length %d, skipping remainder of the config\n",
+ cfgno, header->bLength);
+ break;
+ }
+
+ if (header->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *d;
+ int inum;
+
+ d = (struct usb_interface_descriptor *) header;
+ if (d->bLength < USB_DT_INTERFACE_SIZE) {
+ dev_warn(ddev, "config %d has an invalid "
+ "interface descriptor of length %d, "
+ "skipping\n", cfgno, d->bLength);
+ continue;
+ }
+
+ inum = d->bInterfaceNumber;
+
+ if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
+ n >= nintf_orig) {
+ dev_warn(ddev, "config %d has more interface "
+ "descriptors, than it declares in "
+ "bNumInterfaces, ignoring interface "
+ "number: %d\n", cfgno, inum);
+ continue;
+ }
+
+ if (inum >= nintf_orig)
+ dev_warn(ddev, "config %d has an invalid "
+ "interface number: %d but max is %d\n",
+ cfgno, inum, nintf_orig - 1);
+
+ /* Have we already encountered this interface?
+ * Count its altsettings */
+ for (i = 0; i < n; ++i) {
+ if (inums[i] == inum)
+ break;
+ }
+ if (i < n) {
+ if (nalts[i] < 255)
+ ++nalts[i];
+ } else if (n < USB_MAXINTERFACES) {
+ inums[n] = inum;
+ nalts[n] = 1;
+ ++n;
+ }
+
+ } else if (header->bDescriptorType ==
+ USB_DT_INTERFACE_ASSOCIATION) {
+ struct usb_interface_assoc_descriptor *d;
+
+ d = (struct usb_interface_assoc_descriptor *)header;
+ if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
+ dev_warn(ddev,
+ "config %d has an invalid interface association descriptor of length %d, skipping\n",
+ cfgno, d->bLength);
+ continue;
+ }
+
+ if (iad_num == USB_MAXIADS) {
+ dev_warn(ddev, "found more Interface "
+ "Association Descriptors "
+ "than allocated for in "
+ "configuration %d\n", cfgno);
+ } else {
+ config->intf_assoc[iad_num] = d;
+ iad_num++;
+ }
+
+ } else if (header->bDescriptorType == USB_DT_DEVICE ||
+ header->bDescriptorType == USB_DT_CONFIG)
+ dev_warn(ddev, "config %d contains an unexpected "
+ "descriptor of type 0x%X, skipping\n",
+ cfgno, header->bDescriptorType);
+
+ } /* for ((buffer2 = buffer, size2 = size); ...) */
+ size = buffer2 - buffer;
+ config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
+
+ if (n != nintf)
+ dev_warn(ddev, "config %d has %d interface%s, different from "
+ "the descriptor's value: %d\n",
+ cfgno, n, plural(n), nintf_orig);
+ else if (n == 0)
+ dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
+ config->desc.bNumInterfaces = nintf = n;
+
+ /* Check for missing interface numbers */
+ for (i = 0; i < nintf; ++i) {
+ for (j = 0; j < nintf; ++j) {
+ if (inums[j] == i)
+ break;
+ }
+ if (j >= nintf)
+ dev_warn(ddev, "config %d has no interface number "
+ "%d\n", cfgno, i);
+ }
+
+ /* Allocate the usb_interface_caches and altsetting arrays */
+ for (i = 0; i < nintf; ++i) {
+ j = nalts[i];
+ if (j > USB_MAXALTSETTING) {
+ dev_warn(ddev, "too many alternate settings for "
+ "config %d interface %d: %d, "
+ "using maximum allowed: %d\n",
+ cfgno, inums[i], j, USB_MAXALTSETTING);
+ nalts[i] = j = USB_MAXALTSETTING;
+ }
+
+ len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
+ config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
+ if (!intfc)
+ return -ENOMEM;
+ kref_init(&intfc->ref);
+ }
+
+ /* FIXME: parse the BOS descriptor */
+
+ /* Skip over any Class Specific or Vendor Specific descriptors;
+ * find the first interface descriptor */
+ config->extra = buffer;
+ i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
+ USB_DT_INTERFACE, &n);
+ config->extralen = i;
+ if (n > 0)
+ dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
+ n, plural(n), "configuration");
+ buffer += i;
+ size -= i;
+
+ /* Parse all the interface/altsetting descriptors */
+ while (size > 0) {
+ retval = usb_parse_interface(ddev, cfgno, config,
+ buffer, size, inums, nalts);
+ if (retval < 0)
+ return retval;
+
+ buffer += retval;
+ size -= retval;
+ }
+
+ /* Check for missing altsettings */
+ for (i = 0; i < nintf; ++i) {
+ intfc = config->intf_cache[i];
+ for (j = 0; j < intfc->num_altsetting; ++j) {
+ for (n = 0; n < intfc->num_altsetting; ++n) {
+ if (intfc->altsetting[n].desc.
+ bAlternateSetting == j)
+ break;
+ }
+ if (n >= intfc->num_altsetting)
+ dev_warn(ddev, "config %d interface %d has no "
+ "altsetting %d\n", cfgno, inums[i], j);
+ }
+ }
+
+ return 0;
+}
+
+/* hub-only!! ... and only exported for reset/reinit path.
+ * otherwise used internally on disconnect/destroy path
+ */
+void usb_destroy_configuration(struct usb_device *dev)
+{
+ int c, i;
+
+ if (!dev->config)
+ return;
+
+ if (dev->rawdescriptors) {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+ kfree(dev->rawdescriptors[i]);
+
+ kfree(dev->rawdescriptors);
+ dev->rawdescriptors = NULL;
+ }
+
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+ struct usb_host_config *cf = &dev->config[c];
+
+ kfree(cf->string);
+ for (i = 0; i < cf->desc.bNumInterfaces; i++) {
+ if (cf->intf_cache[i])
+ kref_put(&cf->intf_cache[i]->ref,
+ usb_release_interface_cache);
+ }
+ }
+ kfree(dev->config);
+ dev->config = NULL;
+}
+
+
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ */
+int usb_get_configuration(struct usb_device *dev)
+{
+ struct device *ddev = &dev->dev;
+ int ncfg = dev->descriptor.bNumConfigurations;
+ int result = 0;
+ unsigned int cfgno, length;
+ unsigned char *bigbuffer;
+ struct usb_config_descriptor *desc;
+
+ cfgno = 0;
+ result = -ENOMEM;
+ if (ncfg > USB_MAXCONFIG) {
+ dev_warn(ddev, "too many configurations: %d, "
+ "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
+ dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
+ }
+
+ if (ncfg < 1) {
+ dev_err(ddev, "no configurations\n");
+ return -EINVAL;
+ }
+
+ length = ncfg * sizeof(struct usb_host_config);
+ dev->config = kzalloc(length, GFP_KERNEL);
+ if (!dev->config)
+ goto err2;
+
+ length = ncfg * sizeof(char *);
+ dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
+ if (!dev->rawdescriptors)
+ goto err2;
+
+ desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+ if (!desc)
+ goto err2;
+
+ result = 0;
+ for (; cfgno < ncfg; cfgno++) {
+ /* We grab just the first descriptor so we know how long
+ * the whole configuration is */
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
+ desc, USB_DT_CONFIG_SIZE);
+ if (result < 0) {
+ dev_err(ddev, "unable to read config index %d "
+ "descriptor/%s: %d\n", cfgno, "start", result);
+ if (result != -EPIPE)
+ goto err;
+ dev_err(ddev, "chopping to %d config(s)\n", cfgno);
+ dev->descriptor.bNumConfigurations = cfgno;
+ break;
+ } else if (result < 4) {
+ dev_err(ddev, "config index %d descriptor too short "
+ "(expected %i, got %i)\n", cfgno,
+ USB_DT_CONFIG_SIZE, result);
+ result = -EINVAL;
+ goto err;
+ }
+ length = max((int) le16_to_cpu(desc->wTotalLength),
+ USB_DT_CONFIG_SIZE);
+
+ /* Now that we know the length, get the whole thing */
+ bigbuffer = kmalloc(length, GFP_KERNEL);
+ if (!bigbuffer) {
+ result = -ENOMEM;
+ goto err;
+ }
+
+ if (dev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(200);
+
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
+ bigbuffer, length);
+ if (result < 0) {
+ dev_err(ddev, "unable to read config index %d "
+ "descriptor/%s\n", cfgno, "all");
+ kfree(bigbuffer);
+ goto err;
+ }
+ if (result < length) {
+ dev_warn(ddev, "config index %d descriptor too short "
+ "(expected %i, got %i)\n", cfgno, length, result);
+ length = result;
+ }
+
+ dev->rawdescriptors[cfgno] = bigbuffer;
+
+ result = usb_parse_configuration(dev, cfgno,
+ &dev->config[cfgno], bigbuffer, length);
+ if (result < 0) {
+ ++cfgno;
+ goto err;
+ }
+ }
+ result = 0;
+
+err:
+ kfree(desc);
+ dev->descriptor.bNumConfigurations = cfgno;
+err2:
+ if (result == -ENOMEM)
+ dev_err(ddev, "out of memory\n");
+ return result;
+}
+
+void usb_release_bos_descriptor(struct usb_device *dev)
+{
+ if (dev->bos) {
+ kfree(dev->bos->desc);
+ kfree(dev->bos);
+ dev->bos = NULL;
+ }
+}
+
+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, *buffer0;
+ int length, total_len, num, i, ssac;
+ __u8 cap_type;
+ int ret;
+
+ bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
+ if (!bos)
+ return -ENOMEM;
+
+ /* Get BOS descriptor */
+ ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
+ if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
+ dev_err(ddev, "unable to get BOS descriptor or descriptor too short\n");
+ if (ret >= 0)
+ ret = -ENOMSG;
+ kfree(bos);
+ return ret;
+ }
+
+ length = bos->bLength;
+ total_len = le16_to_cpu(bos->wTotalLength);
+ num = bos->bNumDeviceCaps;
+ kfree(bos);
+ if (total_len < length)
+ return -EINVAL;
+
+ dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
+ if (!dev->bos)
+ return -ENOMEM;
+
+ /* Now let's get the whole BOS descriptor set */
+ buffer = kzalloc(total_len, GFP_KERNEL);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev->bos->desc = (struct usb_bos_descriptor *)buffer;
+
+ ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
+ if (ret < total_len) {
+ dev_err(ddev, "unable to get BOS descriptor set\n");
+ if (ret >= 0)
+ ret = -ENOMSG;
+ goto err;
+ }
+
+ buffer0 = buffer;
+ total_len -= length;
+ buffer += length;
+
+ for (i = 0; i < num; i++) {
+ cap = (struct usb_dev_cap_header *)buffer;
+
+ if (total_len < sizeof(*cap) || total_len < cap->bLength) {
+ 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;
+ }
+
+ if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+ dev_warn(ddev, "descriptor type invalid, skip\n");
+ continue;
+ }
+
+ switch (cap_type) {
+ case USB_CAP_TYPE_WIRELESS_USB:
+ /* Wireless USB cap descriptor is handled by wusb */
+ break;
+ case USB_CAP_TYPE_EXT:
+ dev->bos->ext_cap =
+ (struct usb_ext_cap_descriptor *)buffer;
+ break;
+ case USB_SS_CAP_TYPE:
+ dev->bos->ss_cap =
+ (struct usb_ss_cap_descriptor *)buffer;
+ break;
+ case USB_SSP_CAP_TYPE:
+ 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 =
+ (struct usb_ss_container_id_descriptor *)buffer;
+ break;
+ case USB_PTM_CAP_TYPE:
+ dev->bos->ptm_cap =
+ (struct usb_ptm_cap_descriptor *)buffer;
+ default:
+ break;
+ }
+
+ total_len -= length;
+ buffer += length;
+ }
+ dev->bos->desc->wTotalLength = cpu_to_le16(buffer - buffer0);
+
+ return 0;
+
+err:
+ usb_release_bos_descriptor(dev);
+ return ret;
+}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
new file mode 100644
index 000000000..3de3c750b
--- /dev/null
+++ b/drivers/usb/core/devices.c
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * devices.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>.
+ * (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ *************************************************************
+ *
+ * <mountpoint>/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /dev/bus/usb/device# for each device
+ * as it is attached or detached, but I didn't like this for some
+ * reason -- maybe it's just too deep of a directory structure.
+ * I also don't like looking in multiple places to gather and view
+ * the data. Having only one file for ./devices also prevents race
+ * conditions that could arise if a program was reading device info
+ * for devices that are being removed (unplugged). (That is, the
+ * program may find a directory for devnum_12 then try to open it,
+ * but it was just unplugged, so the directory is now deleted.
+ * But programs would just have to be prepared for situations like
+ * this in any plug-and-play environment.)
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Converted the whole proc stuff to real
+ * read methods. Now not the whole device list needs to fit
+ * into one page, only the device list for one bus.
+ * Added a poll method to /sys/kernel/debug/usb/devices, to wake
+ * up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Turned into its own filesystem
+ * 2000-07-05: Ashley Montanaro <ashley@compsoc.man.ac.uk>
+ * Converted file reading routine to dump to buffer once
+ * per device, not per bus
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "usb.h"
+
+/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
+#define ALLOW_SERIAL_NUMBER
+
+static const char format_topo[] =
+/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */
+"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n";
+
+static const char format_string_manufacturer[] =
+/* S: Manufacturer=xxxx */
+ "S: Manufacturer=%.100s\n";
+
+static const char format_string_product[] =
+/* S: Product=xxxx */
+ "S: Product=%.100s\n";
+
+#ifdef ALLOW_SERIAL_NUMBER
+static const char format_string_serialnumber[] =
+/* S: SerialNumber=xxxx */
+ "S: SerialNumber=%.100s\n";
+#endif
+
+static const char format_bandwidth[] =
+/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
+ "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
+
+static const char format_device1[] =
+/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+ "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+
+static const char format_device2[] =
+/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
+ "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
+
+static const char format_config[] =
+/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+ "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+
+static const char format_iad[] =
+/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
+ "A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+
+static const char format_iface[] =
+/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
+ "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+
+static const char format_endpt[] =
+/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
+ "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
+
+/*
+ * Wait for an connect/disconnect event to happen. We initialize
+ * the event counter with an odd number, and each event will increment
+ * the event counter by two, so it will always _stay_ odd. That means
+ * that it will never be zero, so "event 0" will never match a current
+ * event, and thus 'poll' will always trigger as readable for the first
+ * time it gets called.
+ */
+static struct device_connect_event {
+ atomic_t count;
+ wait_queue_head_t wait;
+} device_event = {
+ .count = ATOMIC_INIT(1),
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER(device_event.wait)
+};
+
+struct class_info {
+ int class;
+ char *class_name;
+};
+
+static const struct class_info clas_info[] = {
+ /* max. 5 chars. per name string */
+ {USB_CLASS_PER_INTERFACE, ">ifc"},
+ {USB_CLASS_AUDIO, "audio"},
+ {USB_CLASS_COMM, "comm."},
+ {USB_CLASS_HID, "HID"},
+ {USB_CLASS_PHYSICAL, "PID"},
+ {USB_CLASS_STILL_IMAGE, "still"},
+ {USB_CLASS_PRINTER, "print"},
+ {USB_CLASS_MASS_STORAGE, "stor."},
+ {USB_CLASS_HUB, "hub"},
+ {USB_CLASS_CDC_DATA, "data"},
+ {USB_CLASS_CSCID, "scard"},
+ {USB_CLASS_CONTENT_SEC, "c-sec"},
+ {USB_CLASS_VIDEO, "video"},
+ {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"},
+ {USB_CLASS_MISC, "misc"},
+ {USB_CLASS_APP_SPEC, "app."},
+ {USB_CLASS_VENDOR_SPEC, "vend."},
+ {-1, "unk."} /* leave as last */
+};
+
+/*****************************************************************/
+
+void usbfs_conn_disc_event(void)
+{
+ atomic_add(2, &device_event.count);
+ wake_up(&device_event.wait);
+}
+
+static const char *class_decode(const int class)
+{
+ int ix;
+
+ for (ix = 0; clas_info[ix].class != -1; ix++)
+ if (clas_info[ix].class == class)
+ break;
+ return clas_info[ix].class_name;
+}
+
+static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
+ const struct usb_endpoint_descriptor *desc)
+{
+ char dir, unit, *type;
+ unsigned interval, bandwidth = 1;
+
+ if (start > end)
+ return start;
+
+ dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
+
+ if (speed == USB_SPEED_HIGH)
+ bandwidth = usb_endpoint_maxp_mult(desc);
+
+ /* this isn't checking for illegal values */
+ switch (usb_endpoint_type(desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "Ctrl";
+ if (speed == USB_SPEED_HIGH) /* uframes per NAK */
+ interval = desc->bInterval;
+ else
+ interval = 0;
+ dir = 'B'; /* ctrl is bidirectional */
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ type = "Isoc";
+ interval = 1 << (desc->bInterval - 1);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = "Bulk";
+ if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */
+ interval = desc->bInterval;
+ else
+ interval = 0;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = "Int.";
+ if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
+ interval = 1 << (desc->bInterval - 1);
+ else
+ interval = desc->bInterval;
+ break;
+ default: /* "can't happen" */
+ return start;
+ }
+ interval *= (speed == USB_SPEED_HIGH ||
+ speed >= USB_SPEED_SUPER) ? 125 : 1000;
+ if (interval % 1000)
+ unit = 'u';
+ else {
+ unit = 'm';
+ interval /= 1000;
+ }
+
+ start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
+ desc->bmAttributes, type,
+ usb_endpoint_maxp(desc) *
+ bandwidth,
+ interval, unit);
+ return start;
+}
+
+static char *usb_dump_interface_descriptor(char *start, char *end,
+ const struct usb_interface_cache *intfc,
+ const struct usb_interface *iface,
+ int setno)
+{
+ const struct usb_interface_descriptor *desc;
+ const char *driver_name = "";
+ int active = 0;
+
+ if (start > end)
+ return start;
+ desc = &intfc->altsetting[setno].desc;
+ if (iface) {
+ driver_name = (iface->dev.driver
+ ? iface->dev.driver->name
+ : "(none)");
+ active = (desc == &iface->cur_altsetting->desc);
+ }
+ start += sprintf(start, format_iface,
+ active ? '*' : ' ', /* mark active altsetting */
+ desc->bInterfaceNumber,
+ desc->bAlternateSetting,
+ desc->bNumEndpoints,
+ desc->bInterfaceClass,
+ class_decode(desc->bInterfaceClass),
+ desc->bInterfaceSubClass,
+ desc->bInterfaceProtocol,
+ driver_name);
+ return start;
+}
+
+static char *usb_dump_interface(int speed, char *start, char *end,
+ const struct usb_interface_cache *intfc,
+ const struct usb_interface *iface, int setno)
+{
+ const struct usb_host_interface *desc = &intfc->altsetting[setno];
+ int i;
+
+ start = usb_dump_interface_descriptor(start, end, intfc, iface, setno);
+ for (i = 0; i < desc->desc.bNumEndpoints; i++) {
+ if (start > end)
+ return start;
+ start = usb_dump_endpoint_descriptor(speed,
+ start, end, &desc->endpoint[i].desc);
+ }
+ return start;
+}
+
+static char *usb_dump_iad_descriptor(char *start, char *end,
+ const struct usb_interface_assoc_descriptor *iad)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, format_iad,
+ iad->bFirstInterface,
+ iad->bInterfaceCount,
+ iad->bFunctionClass,
+ class_decode(iad->bFunctionClass),
+ iad->bFunctionSubClass,
+ iad->bFunctionProtocol);
+ return start;
+}
+
+/* TBD:
+ * 0. TBDs
+ * 1. marking active interface altsettings (code lists all, but should mark
+ * which ones are active, if any)
+ */
+static char *usb_dump_config_descriptor(char *start, char *end,
+ const struct usb_config_descriptor *desc,
+ int active, int speed)
+{
+ int mul;
+
+ if (start > end)
+ return start;
+ if (speed >= USB_SPEED_SUPER)
+ mul = 8;
+ else
+ mul = 2;
+ start += sprintf(start, format_config,
+ /* mark active/actual/current cfg. */
+ active ? '*' : ' ',
+ desc->bNumInterfaces,
+ desc->bConfigurationValue,
+ desc->bmAttributes,
+ desc->bMaxPower * mul);
+ return start;
+}
+
+static char *usb_dump_config(int speed, char *start, char *end,
+ const struct usb_host_config *config, int active)
+{
+ int i, j;
+ struct usb_interface_cache *intfc;
+ struct usb_interface *interface;
+
+ if (start > end)
+ return start;
+ if (!config)
+ /* getting these some in 2.3.7; none in 2.3.6 */
+ return start + sprintf(start, "(null Cfg. desc.)\n");
+ start = usb_dump_config_descriptor(start, end, &config->desc, active,
+ speed);
+ for (i = 0; i < USB_MAXIADS; i++) {
+ if (config->intf_assoc[i] == NULL)
+ break;
+ start = usb_dump_iad_descriptor(start, end,
+ config->intf_assoc[i]);
+ }
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ intfc = config->intf_cache[i];
+ interface = config->interface[i];
+ for (j = 0; j < intfc->num_altsetting; j++) {
+ if (start > end)
+ return start;
+ start = usb_dump_interface(speed,
+ start, end, intfc, interface, j);
+ }
+ }
+ return start;
+}
+
+/*
+ * Dump the different USB descriptors.
+ */
+static char *usb_dump_device_descriptor(char *start, char *end,
+ const struct usb_device_descriptor *desc)
+{
+ u16 bcdUSB = le16_to_cpu(desc->bcdUSB);
+ u16 bcdDevice = le16_to_cpu(desc->bcdDevice);
+
+ if (start > end)
+ return start;
+ start += sprintf(start, format_device1,
+ bcdUSB >> 8, bcdUSB & 0xff,
+ desc->bDeviceClass,
+ class_decode(desc->bDeviceClass),
+ desc->bDeviceSubClass,
+ desc->bDeviceProtocol,
+ desc->bMaxPacketSize0,
+ desc->bNumConfigurations);
+ if (start > end)
+ return start;
+ start += sprintf(start, format_device2,
+ le16_to_cpu(desc->idVendor),
+ le16_to_cpu(desc->idProduct),
+ bcdDevice >> 8, bcdDevice & 0xff);
+ return start;
+}
+
+/*
+ * Dump the different strings that this device holds.
+ */
+static char *usb_dump_device_strings(char *start, char *end,
+ struct usb_device *dev)
+{
+ if (start > end)
+ return start;
+ if (dev->manufacturer)
+ start += sprintf(start, format_string_manufacturer,
+ dev->manufacturer);
+ if (start > end)
+ goto out;
+ if (dev->product)
+ start += sprintf(start, format_string_product, dev->product);
+ if (start > end)
+ goto out;
+#ifdef ALLOW_SERIAL_NUMBER
+ if (dev->serial)
+ start += sprintf(start, format_string_serialnumber,
+ dev->serial);
+#endif
+ out:
+ return start;
+}
+
+static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
+{
+ int i;
+
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_strings(start, end, dev);
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ if (start > end)
+ return start;
+ start = usb_dump_config(dev->speed,
+ start, end, dev->config + i,
+ /* active ? */
+ (dev->config + i) == dev->actconfig);
+ }
+ return start;
+}
+
+
+#ifdef PROC_EXTRA /* TBD: may want to add this code later */
+
+static char *usb_dump_hub_descriptor(char *start, char *end,
+ const struct usb_hub_descriptor *desc)
+{
+ int leng = USB_DT_HUB_NONVAR_SIZE;
+ unsigned char *ptr = (unsigned char *)desc;
+
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
+ while (leng && start <= end) {
+ start += sprintf(start, " %02x", *ptr);
+ ptr++; leng--;
+ }
+ *start++ = '\n';
+ return start;
+}
+
+static char *usb_dump_string(char *start, char *end,
+ const struct usb_device *dev, char *id, int index)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
+ if (index <= dev->maxstring && dev->stringindex &&
+ dev->stringindex[index])
+ start += sprintf(start, "%s: %.100s ", id,
+ dev->stringindex[index]);
+ return start;
+}
+
+#endif /* PROC_EXTRA */
+
+/*****************************************************************/
+
+/* This is a recursive function. Parameters:
+ * buffer - the user-space buffer to write data into
+ * nbytes - the maximum number of bytes to write
+ * skip_bytes - the number of bytes to skip before writing anything
+ * file_offset - the offset into the devices file on completion
+ * The caller must own the device lock.
+ */
+static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
+ loff_t *skip_bytes, loff_t *file_offset,
+ struct usb_device *usbdev, struct usb_bus *bus,
+ int level, int index, int count)
+{
+ int chix;
+ int ret, cnt = 0;
+ int parent_devnum = 0;
+ char *pages_start, *data_end, *speed;
+ unsigned int length;
+ ssize_t total_written = 0;
+ struct usb_device *childdev = NULL;
+
+ /* don't bother with anything else if we're not writing any data */
+ if (*nbytes <= 0)
+ return 0;
+
+ if (level > MAX_TOPO_LEVEL)
+ return 0;
+ /* allocate 2^1 pages = 8K (on i386);
+ * should be more than enough for one device */
+ pages_start = (char *)__get_free_pages(GFP_NOIO, 1);
+ if (!pages_start)
+ return -ENOMEM;
+
+ if (usbdev->parent && usbdev->parent->devnum != -1)
+ parent_devnum = usbdev->parent->devnum;
+ /*
+ * So the root hub's parent is 0 and any device that is
+ * plugged into the root hub has a parent of 0.
+ */
+ switch (usbdev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5"; break;
+ case USB_SPEED_UNKNOWN: /* usb 1.1 root hub code */
+ case USB_SPEED_FULL:
+ speed = "12"; break;
+ case USB_SPEED_WIRELESS: /* Wireless has no real fixed speed */
+ case USB_SPEED_HIGH:
+ speed = "480"; break;
+ case USB_SPEED_SUPER:
+ speed = "5000"; break;
+ case USB_SPEED_SUPER_PLUS:
+ speed = "10000"; break;
+ default:
+ speed = "??";
+ }
+ data_end = pages_start + sprintf(pages_start, format_topo,
+ bus->busnum, level, parent_devnum,
+ index, count, usbdev->devnum,
+ speed, usbdev->maxchild);
+ /*
+ * level = topology-tier level;
+ * parent_devnum = parent device number;
+ * index = parent's connector number;
+ * count = device count at this level
+ */
+ /* If this is the root hub, display the bandwidth information */
+ if (level == 0) {
+ int max;
+
+ /* super/high speed reserves 80%, full/low reserves 90% */
+ if (usbdev->speed == USB_SPEED_HIGH ||
+ usbdev->speed >= USB_SPEED_SUPER)
+ max = 800;
+ else
+ max = FRAME_TIME_MAX_USECS_ALLOC;
+
+ /* report "average" periodic allocation over a microsecond.
+ * the schedules are actually bursty, HCDs need to deal with
+ * that and just compute/report this average.
+ */
+ data_end += sprintf(data_end, format_bandwidth,
+ bus->bandwidth_allocated, max,
+ (100 * bus->bandwidth_allocated + max / 2)
+ / max,
+ bus->bandwidth_int_reqs,
+ bus->bandwidth_isoc_reqs);
+
+ }
+ data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256,
+ usbdev);
+
+ if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
+ data_end += sprintf(data_end, "(truncated)\n");
+
+ length = data_end - pages_start;
+ /* if we can start copying some data to the user */
+ if (length > *skip_bytes) {
+ length -= *skip_bytes;
+ if (length > *nbytes)
+ length = *nbytes;
+ if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
+ free_pages((unsigned long)pages_start, 1);
+ return -EFAULT;
+ }
+ *nbytes -= length;
+ *file_offset += length;
+ total_written += length;
+ *buffer += length;
+ *skip_bytes = 0;
+ } else
+ *skip_bytes -= length;
+
+ free_pages((unsigned long)pages_start, 1);
+
+ /* Now look at all of this device's children. */
+ usb_hub_for_each_child(usbdev, chix, childdev) {
+ usb_lock_device(childdev);
+ ret = usb_device_dump(buffer, nbytes, skip_bytes,
+ file_offset, childdev, bus,
+ level + 1, chix - 1, ++cnt);
+ usb_unlock_device(childdev);
+ if (ret == -EFAULT)
+ return total_written;
+ total_written += ret;
+ }
+ return total_written;
+}
+
+static ssize_t usb_device_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct usb_bus *bus;
+ ssize_t ret, total_written = 0;
+ loff_t skip_bytes = *ppos;
+ int id;
+
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+
+ mutex_lock(&usb_bus_idr_lock);
+ /* print devices for all busses */
+ idr_for_each_entry(&usb_bus_idr, bus, id) {
+ /* recurse through all children of the root hub */
+ if (!bus_to_hcd(bus)->rh_registered)
+ continue;
+ usb_lock_device(bus->root_hub);
+ ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
+ bus->root_hub, bus, 0, 0, 0);
+ usb_unlock_device(bus->root_hub);
+ if (ret < 0) {
+ mutex_unlock(&usb_bus_idr_lock);
+ return ret;
+ }
+ total_written += ret;
+ }
+ mutex_unlock(&usb_bus_idr_lock);
+ return total_written;
+}
+
+/* Kernel lock for "lastev" protection */
+static __poll_t usb_device_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ unsigned int event_count;
+
+ poll_wait(file, &device_event.wait, wait);
+
+ event_count = atomic_read(&device_event.count);
+ if (file->f_version != event_count) {
+ file->f_version = event_count;
+ return EPOLLIN | EPOLLRDNORM;
+ }
+
+ return 0;
+}
+
+const struct file_operations usbfs_devices_fops = {
+ .llseek = no_seek_end_llseek,
+ .read = usb_device_read,
+ .poll = usb_device_poll,
+};
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
new file mode 100644
index 000000000..a45443482
--- /dev/null
+++ b/drivers/usb/core/devio.c
@@ -0,0 +1,2705 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*****************************************************************************/
+
+/*
+ * devio.c -- User space communication with USB devices.
+ *
+ * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This file implements the usbfs/x/y files, where
+ * x is the bus number and y the device number.
+ *
+ * It allows user space programs/"drivers" to communicate directly
+ * with USB devices without intervening kernel driver.
+ *
+ * Revision history
+ * 22.12.1999 0.1 Initial release (split from proc_usb.c)
+ * 04.01.2000 0.2 Turned into its own filesystem
+ * 30.09.2005 0.3 Fix user-triggerable oops in async URB delivery
+ * (CAN-2005-3055)
+ */
+
+/*****************************************************************************/
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h> /* for usbcore internals */
+#include <linux/cdev.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
+#include <linux/user_namespace.h>
+#include <linux/scatterlist.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <asm/byteorder.h>
+#include <linux/moduleparam.h>
+
+#include "usb.h"
+
+#define USB_MAXBUS 64
+#define USB_DEVICE_MAX (USB_MAXBUS * 128)
+#define USB_SG_SIZE 16384 /* split-size for large txs */
+
+/* Mutual exclusion for removal, open, and release */
+DEFINE_MUTEX(usbfs_mutex);
+
+struct usb_dev_state {
+ struct list_head list; /* state list */
+ struct usb_device *dev;
+ struct file *file;
+ spinlock_t lock; /* protects the async urb lists */
+ struct list_head async_pending;
+ struct list_head async_completed;
+ struct list_head memory_list;
+ wait_queue_head_t wait; /* wake up if a request completed */
+ unsigned int discsignr;
+ struct pid *disc_pid;
+ const struct cred *cred;
+ void __user *disccontext;
+ unsigned long ifclaimed;
+ u32 disabled_bulk_eps;
+ bool privileges_dropped;
+ unsigned long interface_allowed_mask;
+};
+
+struct usb_memory {
+ struct list_head memlist;
+ int vma_use_count;
+ int urb_use_count;
+ u32 size;
+ void *mem;
+ dma_addr_t dma_handle;
+ unsigned long vm_start;
+ struct usb_dev_state *ps;
+};
+
+struct async {
+ struct list_head asynclist;
+ struct usb_dev_state *ps;
+ struct pid *pid;
+ const struct cred *cred;
+ unsigned int signr;
+ unsigned int ifnum;
+ void __user *userbuffer;
+ void __user *userurb;
+ struct urb *urb;
+ struct usb_memory *usbm;
+ unsigned int mem_usage;
+ int status;
+ u8 bulk_addr;
+ u8 bulk_status;
+};
+
+static bool usbfs_snoop;
+module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
+
+static unsigned usbfs_snoop_max = 65536;
+module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop_max,
+ "maximum number of bytes to print while snooping");
+
+#define snoop(dev, format, arg...) \
+ do { \
+ if (usbfs_snoop) \
+ dev_info(dev, format, ## arg); \
+ } while (0)
+
+enum snoop_when {
+ SUBMIT, COMPLETE
+};
+
+#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
+
+/* Limit on the total amount of memory we can allocate for transfers */
+static u32 usbfs_memory_mb = 16;
+module_param(usbfs_memory_mb, uint, 0644);
+MODULE_PARM_DESC(usbfs_memory_mb,
+ "maximum MB allowed for usbfs buffers (0 = no limit)");
+
+/* Hard limit, necessary to avoid arithmetic overflow */
+#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
+
+static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */
+
+/* Check whether it's okay to allocate more memory for a transfer */
+static int usbfs_increase_memory_usage(u64 amount)
+{
+ u64 lim;
+
+ lim = READ_ONCE(usbfs_memory_mb);
+ lim <<= 20;
+
+ atomic64_add(amount, &usbfs_memory_usage);
+
+ if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) {
+ atomic64_sub(amount, &usbfs_memory_usage);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Memory for a transfer is being deallocated */
+static void usbfs_decrease_memory_usage(u64 amount)
+{
+ atomic64_sub(amount, &usbfs_memory_usage);
+}
+
+static int connected(struct usb_dev_state *ps)
+{
+ return (!list_empty(&ps->list) &&
+ ps->dev->state != USB_STATE_NOTATTACHED);
+}
+
+static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
+{
+ struct usb_dev_state *ps = usbm->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ --*count;
+ if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) {
+ list_del(&usbm->memlist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ usb_free_coherent(ps->dev, usbm->size, usbm->mem,
+ usbm->dma_handle);
+ usbfs_decrease_memory_usage(
+ usbm->size + sizeof(struct usb_memory));
+ kfree(usbm);
+ } else {
+ spin_unlock_irqrestore(&ps->lock, flags);
+ }
+}
+
+static void usbdev_vm_open(struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = vma->vm_private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usbm->ps->lock, flags);
+ ++usbm->vma_use_count;
+ spin_unlock_irqrestore(&usbm->ps->lock, flags);
+}
+
+static void usbdev_vm_close(struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = vma->vm_private_data;
+
+ dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
+}
+
+static const struct vm_operations_struct usbdev_vm_ops = {
+ .open = usbdev_vm_open,
+ .close = usbdev_vm_close
+};
+
+static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct usb_memory *usbm = NULL;
+ struct usb_dev_state *ps = file->private_data;
+ size_t size = vma->vm_end - vma->vm_start;
+ void *mem;
+ unsigned long flags;
+ dma_addr_t dma_handle;
+ int ret;
+
+ ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
+ if (ret)
+ goto error;
+
+ usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
+ if (!usbm) {
+ ret = -ENOMEM;
+ goto error_decrease_mem;
+ }
+
+ mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN,
+ &dma_handle);
+ if (!mem) {
+ ret = -ENOMEM;
+ goto error_free_usbm;
+ }
+
+ memset(mem, 0, size);
+
+ usbm->mem = mem;
+ usbm->dma_handle = dma_handle;
+ usbm->size = size;
+ usbm->ps = ps;
+ usbm->vm_start = vma->vm_start;
+ usbm->vma_use_count = 1;
+ INIT_LIST_HEAD(&usbm->memlist);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_phys(usbm->mem) >> PAGE_SHIFT,
+ size, vma->vm_page_prot) < 0) {
+ dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
+ return -EAGAIN;
+ }
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
+ vma->vm_ops = &usbdev_vm_ops;
+ vma->vm_private_data = usbm;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_add_tail(&usbm->memlist, &ps->memory_list);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ return 0;
+
+error_free_usbm:
+ kfree(usbm);
+error_decrease_mem:
+ usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
+error:
+ return ret;
+}
+
+static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ struct usb_dev_state *ps = file->private_data;
+ struct usb_device *dev = ps->dev;
+ ssize_t ret = 0;
+ unsigned len;
+ loff_t pos;
+ int i;
+
+ pos = *ppos;
+ usb_lock_device(dev);
+ if (!connected(ps)) {
+ ret = -ENODEV;
+ goto err;
+ } else if (pos < 0) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (pos < sizeof(struct usb_device_descriptor)) {
+ /* 18 bytes - fits on the stack */
+ struct usb_device_descriptor temp_desc;
+
+ memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
+ le16_to_cpus(&temp_desc.bcdUSB);
+ le16_to_cpus(&temp_desc.idVendor);
+ le16_to_cpus(&temp_desc.idProduct);
+ le16_to_cpus(&temp_desc.bcdDevice);
+
+ len = sizeof(struct usb_device_descriptor) - pos;
+ if (len > nbytes)
+ len = nbytes;
+ if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ *ppos += len;
+ buf += len;
+ nbytes -= len;
+ ret += len;
+ }
+
+ pos = sizeof(struct usb_device_descriptor);
+ for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
+ struct usb_config_descriptor *config =
+ (struct usb_config_descriptor *)dev->rawdescriptors[i];
+ unsigned int length = le16_to_cpu(config->wTotalLength);
+
+ if (*ppos < pos + length) {
+
+ /* The descriptor may claim to be longer than it
+ * really is. Here is the actual allocated length. */
+ unsigned alloclen =
+ le16_to_cpu(dev->config[i].desc.wTotalLength);
+
+ len = length - (*ppos - pos);
+ if (len > nbytes)
+ len = nbytes;
+
+ /* Simply don't write (skip over) unallocated parts */
+ if (alloclen > (*ppos - pos)) {
+ alloclen -= (*ppos - pos);
+ if (copy_to_user(buf,
+ dev->rawdescriptors[i] + (*ppos - pos),
+ min(len, alloclen))) {
+ ret = -EFAULT;
+ goto err;
+ }
+ }
+
+ *ppos += len;
+ buf += len;
+ nbytes -= len;
+ ret += len;
+ }
+
+ pos += length;
+ }
+
+err:
+ usb_unlock_device(dev);
+ return ret;
+}
+
+/*
+ * async list handling
+ */
+
+static struct async *alloc_async(unsigned int numisoframes)
+{
+ struct async *as;
+
+ as = kzalloc(sizeof(struct async), GFP_KERNEL);
+ if (!as)
+ return NULL;
+ as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
+ if (!as->urb) {
+ kfree(as);
+ return NULL;
+ }
+ return as;
+}
+
+static void free_async(struct async *as)
+{
+ int i;
+
+ put_pid(as->pid);
+ if (as->cred)
+ put_cred(as->cred);
+ for (i = 0; i < as->urb->num_sgs; i++) {
+ if (sg_page(&as->urb->sg[i]))
+ kfree(sg_virt(&as->urb->sg[i]));
+ }
+
+ kfree(as->urb->sg);
+ if (as->usbm == NULL)
+ kfree(as->urb->transfer_buffer);
+ else
+ dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
+
+ kfree(as->urb->setup_packet);
+ usb_free_urb(as->urb);
+ usbfs_decrease_memory_usage(as->mem_usage);
+ kfree(as);
+}
+
+static void async_newpending(struct async *as)
+{
+ struct usb_dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_add_tail(&as->asynclist, &ps->async_pending);
+ spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+static void async_removepending(struct async *as)
+{
+ struct usb_dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_del_init(&as->asynclist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+static struct async *async_getcompleted(struct usb_dev_state *ps)
+{
+ unsigned long flags;
+ struct async *as = NULL;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ if (!list_empty(&ps->async_completed)) {
+ as = list_entry(ps->async_completed.next, struct async,
+ asynclist);
+ list_del_init(&as->asynclist);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return as;
+}
+
+static struct async *async_getpending(struct usb_dev_state *ps,
+ void __user *userurb)
+{
+ struct async *as;
+
+ list_for_each_entry(as, &ps->async_pending, asynclist)
+ if (as->userurb == userurb) {
+ list_del_init(&as->asynclist);
+ return as;
+ }
+
+ return NULL;
+}
+
+static void snoop_urb(struct usb_device *udev,
+ void __user *userurb, int pipe, unsigned length,
+ int timeout_or_status, enum snoop_when when,
+ unsigned char *data, unsigned data_len)
+{
+ static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
+ static const char *dirs[] = {"out", "in"};
+ int ep;
+ const char *t, *d;
+
+ if (!usbfs_snoop)
+ return;
+
+ ep = usb_pipeendpoint(pipe);
+ t = types[usb_pipetype(pipe)];
+ d = dirs[!!usb_pipein(pipe)];
+
+ if (userurb) { /* Async */
+ if (when == SUBMIT)
+ dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
+ "length %u\n",
+ userurb, ep, t, d, length);
+ else
+ dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
+ "actual_length %u status %d\n",
+ userurb, ep, t, d, length,
+ timeout_or_status);
+ } else {
+ if (when == SUBMIT)
+ dev_info(&udev->dev, "ep%d %s-%s, length %u, "
+ "timeout %d\n",
+ ep, t, d, length, timeout_or_status);
+ else
+ dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
+ "status %d\n",
+ ep, t, d, length, timeout_or_status);
+ }
+
+ data_len = min(data_len, usbfs_snoop_max);
+ if (data && data_len > 0) {
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+ data, data_len, 1);
+ }
+}
+
+static void snoop_urb_data(struct urb *urb, unsigned len)
+{
+ int i, size;
+
+ len = min(len, usbfs_snoop_max);
+ if (!usbfs_snoop || len == 0)
+ return;
+
+ if (urb->num_sgs == 0) {
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+ urb->transfer_buffer, len, 1);
+ return;
+ }
+
+ for (i = 0; i < urb->num_sgs && len; i++) {
+ size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+ sg_virt(&urb->sg[i]), size, 1);
+ len -= size;
+ }
+}
+
+static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
+{
+ unsigned i, len, size;
+
+ if (urb->number_of_packets > 0) /* Isochronous */
+ len = urb->transfer_buffer_length;
+ else /* Non-Isoc */
+ len = urb->actual_length;
+
+ if (urb->num_sgs == 0) {
+ if (copy_to_user(userbuffer, urb->transfer_buffer, len))
+ return -EFAULT;
+ return 0;
+ }
+
+ for (i = 0; i < urb->num_sgs && len; i++) {
+ size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
+ if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
+ return -EFAULT;
+ userbuffer += size;
+ len -= size;
+ }
+
+ return 0;
+}
+
+#define AS_CONTINUATION 1
+#define AS_UNLINK 2
+
+static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)
+__releases(ps->lock)
+__acquires(ps->lock)
+{
+ struct urb *urb;
+ struct async *as;
+
+ /* Mark all the pending URBs that match bulk_addr, up to but not
+ * including the first one without AS_CONTINUATION. If such an
+ * URB is encountered then a new transfer has already started so
+ * the endpoint doesn't need to be disabled; otherwise it does.
+ */
+ list_for_each_entry(as, &ps->async_pending, asynclist) {
+ if (as->bulk_addr == bulk_addr) {
+ if (as->bulk_status != AS_CONTINUATION)
+ goto rescan;
+ as->bulk_status = AS_UNLINK;
+ as->bulk_addr = 0;
+ }
+ }
+ ps->disabled_bulk_eps |= (1 << bulk_addr);
+
+ /* Now carefully unlink all the marked pending URBs */
+ rescan:
+ list_for_each_entry(as, &ps->async_pending, asynclist) {
+ if (as->bulk_status == AS_UNLINK) {
+ as->bulk_status = 0; /* Only once */
+ urb = as->urb;
+ usb_get_urb(urb);
+ spin_unlock(&ps->lock); /* Allow completions */
+ usb_unlink_urb(urb);
+ usb_put_urb(urb);
+ spin_lock(&ps->lock);
+ goto rescan;
+ }
+ }
+}
+
+static void async_completed(struct urb *urb)
+{
+ struct async *as = urb->context;
+ struct usb_dev_state *ps = as->ps;
+ struct siginfo sinfo;
+ struct pid *pid = NULL;
+ const struct cred *cred = NULL;
+ unsigned long flags;
+ int signr;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_move_tail(&as->asynclist, &ps->async_completed);
+ as->status = urb->status;
+ signr = as->signr;
+ if (signr) {
+ clear_siginfo(&sinfo);
+ sinfo.si_signo = as->signr;
+ sinfo.si_errno = as->status;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = as->userurb;
+ pid = get_pid(as->pid);
+ cred = get_cred(as->cred);
+ }
+ snoop(&urb->dev->dev, "urb complete\n");
+ snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
+ as->status, COMPLETE, NULL, 0);
+ if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
+ snoop_urb_data(urb, urb->actual_length);
+
+ if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
+ as->status != -ENOENT)
+ cancel_bulk_urbs(ps, as->bulk_addr);
+
+ wake_up(&ps->wait);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ if (signr) {
+ kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);
+ put_pid(pid);
+ put_cred(cred);
+ }
+}
+
+static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
+{
+ struct urb *urb;
+ struct async *as;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ while (!list_empty(list)) {
+ as = list_entry(list->next, struct async, asynclist);
+ list_del_init(&as->asynclist);
+ urb = as->urb;
+ usb_get_urb(urb);
+
+ /* drop the spinlock so the completion handler can run */
+ spin_unlock_irqrestore(&ps->lock, flags);
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
+ spin_lock_irqsave(&ps->lock, flags);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+static void destroy_async_on_interface(struct usb_dev_state *ps,
+ unsigned int ifnum)
+{
+ struct list_head *p, *q, hitlist;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&hitlist);
+ spin_lock_irqsave(&ps->lock, flags);
+ list_for_each_safe(p, q, &ps->async_pending)
+ if (ifnum == list_entry(p, struct async, asynclist)->ifnum)
+ list_move_tail(p, &hitlist);
+ spin_unlock_irqrestore(&ps->lock, flags);
+ destroy_async(ps, &hitlist);
+}
+
+static void destroy_all_async(struct usb_dev_state *ps)
+{
+ destroy_async(ps, &ps->async_pending);
+}
+
+/*
+ * interface claims are made only at the request of user level code,
+ * which can also release them (explicitly or by closing files).
+ * they're also undone when devices disconnect.
+ */
+
+static int driver_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return -ENODEV;
+}
+
+static void driver_disconnect(struct usb_interface *intf)
+{
+ struct usb_dev_state *ps = usb_get_intfdata(intf);
+ unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
+
+ if (!ps)
+ return;
+
+ /* NOTE: this relies on usbcore having canceled and completed
+ * all pending I/O requests; 2.6 does that.
+ */
+
+ if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
+ clear_bit(ifnum, &ps->ifclaimed);
+ else
+ dev_warn(&intf->dev, "interface number %u out of range\n",
+ ifnum);
+
+ usb_set_intfdata(intf, NULL);
+
+ /* force async requests to complete */
+ 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.
+ */
+static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ return 0;
+}
+
+static int driver_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
+struct usb_driver usbfs_driver = {
+ .name = "usbfs",
+ .probe = driver_probe,
+ .disconnect = driver_disconnect,
+ .suspend = driver_suspend,
+ .resume = driver_resume,
+};
+
+static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
+{
+ struct usb_device *dev = ps->dev;
+ struct usb_interface *intf;
+ int err;
+
+ if (ifnum >= 8*sizeof(ps->ifclaimed))
+ return -EINVAL;
+ /* already claimed */
+ if (test_bit(ifnum, &ps->ifclaimed))
+ return 0;
+
+ if (ps->privileges_dropped &&
+ !test_bit(ifnum, &ps->interface_allowed_mask))
+ return -EACCES;
+
+ intf = usb_ifnum_to_if(dev, ifnum);
+ if (!intf)
+ err = -ENOENT;
+ 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;
+}
+
+static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
+{
+ struct usb_device *dev;
+ struct usb_interface *intf;
+ int err;
+
+ err = -EINVAL;
+ if (ifnum >= 8*sizeof(ps->ifclaimed))
+ return err;
+ dev = ps->dev;
+ intf = usb_ifnum_to_if(dev, 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;
+}
+
+static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)
+{
+ if (ps->dev->state != USB_STATE_CONFIGURED)
+ return -EHOSTUNREACH;
+ if (ifnum >= 8*sizeof(ps->ifclaimed))
+ return -EINVAL;
+ if (test_bit(ifnum, &ps->ifclaimed))
+ return 0;
+ /* if not yet claimed, claim it for the driver */
+ dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
+ "interface %u before use\n", task_pid_nr(current),
+ current->comm, ifnum);
+ return claimintf(ps, ifnum);
+}
+
+static int findintfep(struct usb_device *dev, unsigned int ep)
+{
+ unsigned int i, j, e;
+ struct usb_interface *intf;
+ struct usb_host_interface *alts;
+ struct usb_endpoint_descriptor *endpt;
+
+ if (ep & ~(USB_DIR_IN|0xf))
+ return -EINVAL;
+ if (!dev->actconfig)
+ return -ESRCH;
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ intf = dev->actconfig->interface[i];
+ for (j = 0; j < intf->num_altsetting; j++) {
+ alts = &intf->altsetting[j];
+ for (e = 0; e < alts->desc.bNumEndpoints; e++) {
+ endpt = &alts->endpoint[e].desc;
+ if (endpt->bEndpointAddress == ep)
+ return alts->desc.bInterfaceNumber;
+ }
+ }
+ }
+ return -ENOENT;
+}
+
+static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,
+ unsigned int request, unsigned int index)
+{
+ int ret = 0;
+ struct usb_host_interface *alt_setting;
+
+ if (ps->dev->state != USB_STATE_UNAUTHENTICATED
+ && ps->dev->state != USB_STATE_ADDRESS
+ && ps->dev->state != USB_STATE_CONFIGURED)
+ return -EHOSTUNREACH;
+ if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
+ return 0;
+
+ /*
+ * check for the special corner case 'get_device_id' in the printer
+ * class specification, which we always want to allow as it is used
+ * to query things like ink level, etc.
+ */
+ if (requesttype == 0xa1 && request == 0) {
+ alt_setting = usb_find_alt_setting(ps->dev->actconfig,
+ index >> 8, index & 0xff);
+ if (alt_setting
+ && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
+ return 0;
+ }
+
+ index &= 0xff;
+ switch (requesttype & USB_RECIP_MASK) {
+ case USB_RECIP_ENDPOINT:
+ if ((index & ~USB_DIR_IN) == 0)
+ return 0;
+ ret = findintfep(ps->dev, index);
+ if (ret < 0) {
+ /*
+ * Some not fully compliant Win apps seem to get
+ * index wrong and have the endpoint number here
+ * rather than the endpoint address (with the
+ * correct direction). Win does let this through,
+ * so we'll not reject it here but leave it to
+ * the device to not break KVM. But we warn.
+ */
+ ret = findintfep(ps->dev, index ^ 0x80);
+ if (ret >= 0)
+ dev_info(&ps->dev->dev,
+ "%s: process %i (%s) requesting ep %02x but needs %02x\n",
+ __func__, task_pid_nr(current),
+ current->comm, index, index ^ 0x80);
+ }
+ if (ret >= 0)
+ ret = checkintf(ps, ret);
+ break;
+
+ case USB_RECIP_INTERFACE:
+ ret = checkintf(ps, index);
+ break;
+ }
+ return ret;
+}
+
+static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
+ unsigned char ep)
+{
+ if (ep & USB_ENDPOINT_DIR_MASK)
+ return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK];
+ else
+ return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
+}
+
+static int parse_usbdevfs_streams(struct usb_dev_state *ps,
+ struct usbdevfs_streams __user *streams,
+ unsigned int *num_streams_ret,
+ unsigned int *num_eps_ret,
+ struct usb_host_endpoint ***eps_ret,
+ struct usb_interface **intf_ret)
+{
+ unsigned int i, num_streams, num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf = NULL;
+ unsigned char ep;
+ int ifnum, ret;
+
+ if (get_user(num_streams, &streams->num_streams) ||
+ get_user(num_eps, &streams->num_eps))
+ return -EFAULT;
+
+ if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
+ return -EINVAL;
+
+ /* The XHCI controller allows max 2 ^ 16 streams */
+ if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
+ return -EINVAL;
+
+ eps = kmalloc_array(num_eps, sizeof(*eps), GFP_KERNEL);
+ if (!eps)
+ return -ENOMEM;
+
+ for (i = 0; i < num_eps; i++) {
+ if (get_user(ep, &streams->eps[i])) {
+ ret = -EFAULT;
+ goto error;
+ }
+ eps[i] = ep_to_host_endpoint(ps->dev, ep);
+ if (!eps[i]) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* usb_alloc/free_streams operate on an usb_interface */
+ ifnum = findintfep(ps->dev, ep);
+ if (ifnum < 0) {
+ ret = ifnum;
+ goto error;
+ }
+
+ if (i == 0) {
+ ret = checkintf(ps, ifnum);
+ if (ret < 0)
+ goto error;
+ intf = usb_ifnum_to_if(ps->dev, ifnum);
+ } else {
+ /* Verify all eps belong to the same interface */
+ if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ }
+
+ if (num_streams_ret)
+ *num_streams_ret = num_streams;
+ *num_eps_ret = num_eps;
+ *eps_ret = eps;
+ *intf_ret = intf;
+
+ return 0;
+
+error:
+ kfree(eps);
+ return ret;
+}
+
+static int match_devt(struct device *dev, void *data)
+{
+ return dev->devt == (dev_t) (unsigned long) 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);
+ if (!dev)
+ return NULL;
+ return to_usb_device(dev);
+}
+
+/*
+ * file operations
+ */
+static int usbdev_open(struct inode *inode, struct file *file)
+{
+ struct usb_device *dev = NULL;
+ struct usb_dev_state *ps;
+ int ret;
+
+ ret = -ENOMEM;
+ ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
+ if (!ps)
+ goto out_free_ps;
+
+ ret = -ENODEV;
+
+ /* Protect against simultaneous removal or release */
+ mutex_lock(&usbfs_mutex);
+
+ /* usbdev device-node */
+ if (imajor(inode) == USB_DEVICE_MAJOR)
+ dev = usbdev_lookup_by_devt(inode->i_rdev);
+
+ mutex_unlock(&usbfs_mutex);
+
+ if (!dev)
+ goto out_free_ps;
+
+ usb_lock_device(dev);
+ if (dev->state == USB_STATE_NOTATTACHED)
+ goto out_unlock_device;
+
+ ret = usb_autoresume_device(dev);
+ if (ret)
+ goto out_unlock_device;
+
+ ps->dev = dev;
+ ps->file = file;
+ ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
+ spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->list);
+ INIT_LIST_HEAD(&ps->async_pending);
+ INIT_LIST_HEAD(&ps->async_completed);
+ INIT_LIST_HEAD(&ps->memory_list);
+ init_waitqueue_head(&ps->wait);
+ ps->disc_pid = get_pid(task_pid(current));
+ ps->cred = get_current_cred();
+ smp_wmb();
+ list_add_tail(&ps->list, &dev->filelist);
+ file->private_data = ps;
+ usb_unlock_device(dev);
+ snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
+ current->comm);
+ return ret;
+
+ out_unlock_device:
+ usb_unlock_device(dev);
+ usb_put_dev(dev);
+ out_free_ps:
+ kfree(ps);
+ return ret;
+}
+
+static int usbdev_release(struct inode *inode, struct file *file)
+{
+ struct usb_dev_state *ps = file->private_data;
+ struct usb_device *dev = ps->dev;
+ unsigned int ifnum;
+ struct async *as;
+
+ usb_lock_device(dev);
+ usb_hub_release_all_ports(dev, ps);
+
+ list_del_init(&ps->list);
+
+ for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
+ ifnum++) {
+ if (test_bit(ifnum, &ps->ifclaimed))
+ releaseintf(ps, ifnum);
+ }
+ destroy_all_async(ps);
+ usb_autosuspend_device(dev);
+ usb_unlock_device(dev);
+ usb_put_dev(dev);
+ put_pid(ps->disc_pid);
+ put_cred(ps->cred);
+
+ as = async_getcompleted(ps);
+ while (as) {
+ free_async(as);
+ as = async_getcompleted(ps);
+ }
+
+ kfree(ps);
+ return 0;
+}
+
+static int proc_control(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usb_device *dev = ps->dev;
+ struct usbdevfs_ctrltransfer ctrl;
+ unsigned int tmo;
+ unsigned char *tbuf;
+ unsigned wLength;
+ int i, pipe, ret;
+
+ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+ return -EFAULT;
+ ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
+ ctrl.wIndex);
+ if (ret)
+ return ret;
+ wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
+ if (wLength > PAGE_SIZE)
+ return -EINVAL;
+ ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+ sizeof(struct usb_ctrlrequest));
+ if (ret)
+ return ret;
+ tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!tbuf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ tmo = ctrl.timeout;
+ snoop(&dev->dev, "control urb: bRequestType=%02x "
+ "bRequest=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ ctrl.bRequestType, ctrl.bRequest, ctrl.wValue,
+ ctrl.wIndex, ctrl.wLength);
+ if (ctrl.bRequestType & 0x80) {
+ if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
+ ctrl.wLength)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ pipe = usb_rcvctrlpipe(dev, 0);
+ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
+
+ usb_unlock_device(dev);
+ i = usb_control_msg(dev, pipe, ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
+ tbuf, max(i, 0));
+ if ((i > 0) && ctrl.wLength) {
+ if (copy_to_user(ctrl.data, tbuf, i)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ if (ctrl.wLength) {
+ if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ pipe = usb_sndctrlpipe(dev, 0);
+ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
+ tbuf, ctrl.wLength);
+
+ usb_unlock_device(dev);
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
+ }
+ if (i < 0 && i != -EPIPE) {
+ dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
+ "failed cmd %s rqt %u rq %u len %u ret %d\n",
+ current->comm, ctrl.bRequestType, ctrl.bRequest,
+ ctrl.wLength, i);
+ }
+ ret = i;
+ done:
+ free_page((unsigned long) tbuf);
+ usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+ sizeof(struct usb_ctrlrequest));
+ return ret;
+}
+
+static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usb_device *dev = ps->dev;
+ struct usbdevfs_bulktransfer bulk;
+ unsigned int tmo, len1, pipe;
+ int len2;
+ unsigned char *tbuf;
+ int i, ret;
+
+ if (copy_from_user(&bulk, arg, sizeof(bulk)))
+ return -EFAULT;
+ ret = findintfep(ps->dev, bulk.ep);
+ if (ret < 0)
+ return ret;
+ ret = checkintf(ps, ret);
+ if (ret)
+ return ret;
+ if (bulk.ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
+ if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
+ return -EINVAL;
+ len1 = bulk.len;
+ if (len1 >= (INT_MAX - sizeof(struct urb)))
+ return -EINVAL;
+ ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
+ if (ret)
+ return ret;
+
+ /*
+ * len1 can be almost arbitrarily large. Don't WARN if it's
+ * too big, just fail the request.
+ */
+ tbuf = kmalloc(len1, GFP_KERNEL | __GFP_NOWARN);
+ if (!tbuf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ tmo = bulk.timeout;
+ if (bulk.ep & 0x80) {
+ if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
+
+ usb_unlock_device(dev);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
+
+ if (!i && len2) {
+ if (copy_to_user(bulk.data, tbuf, len2)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ if (len1) {
+ if (copy_from_user(tbuf, bulk.data, len1)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
+
+ usb_unlock_device(dev);
+ i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_lock_device(dev);
+ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
+ }
+ ret = (i < 0 ? i : len2);
+ done:
+ kfree(tbuf);
+ usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
+ return ret;
+}
+
+static void check_reset_of_active_ep(struct usb_device *udev,
+ unsigned int epnum, char *ioctl_name)
+{
+ struct usb_host_endpoint **eps;
+ struct usb_host_endpoint *ep;
+
+ eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out;
+ ep = eps[epnum & 0x0f];
+ if (ep && !list_empty(&ep->urb_list))
+ dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n",
+ task_pid_nr(current), current->comm,
+ ioctl_name, epnum);
+}
+
+static int proc_resetep(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned int ep;
+ int ret;
+
+ if (get_user(ep, (unsigned int __user *)arg))
+ return -EFAULT;
+ ret = findintfep(ps->dev, ep);
+ if (ret < 0)
+ return ret;
+ ret = checkintf(ps, ret);
+ if (ret)
+ return ret;
+ check_reset_of_active_ep(ps->dev, ep, "RESETEP");
+ usb_reset_endpoint(ps->dev, ep);
+ return 0;
+}
+
+static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned int ep;
+ int pipe;
+ int ret;
+
+ if (get_user(ep, (unsigned int __user *)arg))
+ return -EFAULT;
+ ret = findintfep(ps->dev, ep);
+ if (ret < 0)
+ return ret;
+ ret = checkintf(ps, ret);
+ if (ret)
+ return ret;
+ check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");
+ if (ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+
+ return usb_clear_halt(ps->dev, pipe);
+}
+
+static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_getdriver gd;
+ struct usb_interface *intf;
+ int ret;
+
+ if (copy_from_user(&gd, arg, sizeof(gd)))
+ return -EFAULT;
+ intf = usb_ifnum_to_if(ps->dev, gd.interface);
+ if (!intf || !intf->dev.driver)
+ ret = -ENODATA;
+ else {
+ strlcpy(gd.driver, intf->dev.driver->name,
+ sizeof(gd.driver));
+ ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
+ }
+ return ret;
+}
+
+static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_connectinfo ci;
+
+ memset(&ci, 0, sizeof(ci));
+ ci.devnum = ps->dev->devnum;
+ ci.slow = ps->dev->speed == USB_SPEED_LOW;
+
+ if (copy_to_user(arg, &ci, sizeof(ci)))
+ return -EFAULT;
+ return 0;
+}
+
+static int proc_resetdevice(struct usb_dev_state *ps)
+{
+ struct usb_host_config *actconfig = ps->dev->actconfig;
+ struct usb_interface *interface;
+ int i, number;
+
+ /* Don't allow a device reset if the process has dropped the
+ * privilege to do such things and any of the interfaces are
+ * currently claimed.
+ */
+ if (ps->privileges_dropped && actconfig) {
+ for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+ interface = actconfig->interface[i];
+ number = interface->cur_altsetting->desc.bInterfaceNumber;
+ if (usb_interface_claimed(interface) &&
+ !test_bit(number, &ps->ifclaimed)) {
+ dev_warn(&ps->dev->dev,
+ "usbfs: interface %d claimed by %s while '%s' resets device\n",
+ number, interface->dev.driver->name, current->comm);
+ return -EACCES;
+ }
+ }
+ }
+
+ return usb_reset_device(ps->dev);
+}
+
+static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_setinterface setintf;
+ int ret;
+
+ if (copy_from_user(&setintf, arg, sizeof(setintf)))
+ return -EFAULT;
+ ret = checkintf(ps, setintf.interface);
+ if (ret)
+ return ret;
+
+ destroy_async_on_interface(ps, setintf.interface);
+
+ return usb_set_interface(ps->dev, setintf.interface,
+ setintf.altsetting);
+}
+
+static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
+{
+ int u;
+ int status = 0;
+ struct usb_host_config *actconfig;
+
+ if (get_user(u, (int __user *)arg))
+ return -EFAULT;
+
+ actconfig = ps->dev->actconfig;
+
+ /* Don't touch the device if any interfaces are claimed.
+ * It could interfere with other drivers' operations, and if
+ * an interface is claimed by usbfs it could easily deadlock.
+ */
+ if (actconfig) {
+ int i;
+
+ for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+ if (usb_interface_claimed(actconfig->interface[i])) {
+ dev_warn(&ps->dev->dev,
+ "usbfs: interface %d claimed by %s "
+ "while '%s' sets config #%d\n",
+ actconfig->interface[i]
+ ->cur_altsetting
+ ->desc.bInterfaceNumber,
+ actconfig->interface[i]
+ ->dev.driver->name,
+ current->comm, u);
+ status = -EBUSY;
+ break;
+ }
+ }
+ }
+
+ /* SET_CONFIGURATION is often abused as a "cheap" driver reset,
+ * so avoid usb_set_configuration()'s kick to sysfs
+ */
+ if (status == 0) {
+ if (actconfig && actconfig->desc.bConfigurationValue == u)
+ status = usb_reset_configuration(ps->dev);
+ else
+ status = usb_set_configuration(ps->dev, u);
+ }
+
+ return status;
+}
+
+static struct usb_memory *
+find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
+{
+ struct usb_memory *usbm = NULL, *iter;
+ unsigned long flags;
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_for_each_entry(iter, &ps->memory_list, memlist) {
+ if (uurb_start >= iter->vm_start &&
+ uurb_start < iter->vm_start + iter->size) {
+ if (uurb->buffer_length > iter->vm_start + iter->size -
+ uurb_start) {
+ usbm = ERR_PTR(-EINVAL);
+ } else {
+ usbm = iter;
+ usbm->urb_use_count++;
+ }
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return usbm;
+}
+
+static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
+ struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+ void __user *arg)
+{
+ struct usbdevfs_iso_packet_desc *isopkt = NULL;
+ struct usb_host_endpoint *ep;
+ struct async *as = NULL;
+ struct usb_ctrlrequest *dr = NULL;
+ unsigned int u, totlen, isofrmlen;
+ 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 |
+ USBDEVFS_URB_ZERO_PACKET |
+ 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)
+ return -EINVAL;
+ if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
+ (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+ ifnum = findintfep(ps->dev, uurb->endpoint);
+ if (ifnum < 0)
+ return ifnum;
+ ret = checkintf(ps, ifnum);
+ if (ret)
+ return ret;
+ }
+ ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);
+ if (!ep)
+ return -ENOENT;
+ is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
+
+ u = 0;
+ switch (uurb->type) {
+ case USBDEVFS_URB_TYPE_CONTROL:
+ if (!usb_endpoint_xfer_control(&ep->desc))
+ return -EINVAL;
+ /* min 8 byte setup packet */
+ if (uurb->buffer_length < 8)
+ return -EINVAL;
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+ if (copy_from_user(dr, uurb->buffer, 8)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
+ le16_to_cpup(&dr->wIndex));
+ if (ret)
+ goto error;
+ uurb->buffer_length = le16_to_cpup(&dr->wLength);
+ uurb->buffer += 8;
+ if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+ is_in = 1;
+ uurb->endpoint |= USB_DIR_IN;
+ } else {
+ 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",
+ dr->bRequestType, dr->bRequest,
+ __le16_to_cpup(&dr->wValue),
+ __le16_to_cpup(&dr->wIndex),
+ __le16_to_cpup(&dr->wLength));
+ u = sizeof(struct usb_ctrlrequest);
+ break;
+
+ case USBDEVFS_URB_TYPE_BULK:
+ 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:
+ return -EINVAL;
+ case USB_ENDPOINT_XFER_INT:
+ /* allow single-shot interrupt transfers */
+ uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+ goto interrupt_urb;
+ }
+ num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
+ if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
+ num_sgs = 0;
+ if (ep->streams)
+ stream_id = uurb->stream_id;
+ break;
+
+ case USBDEVFS_URB_TYPE_INTERRUPT:
+ 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:
+ /* arbitrary limit */
+ if (uurb->number_of_packets < 1 ||
+ uurb->number_of_packets > 128)
+ return -EINVAL;
+ if (!usb_endpoint_xfer_isoc(&ep->desc))
+ return -EINVAL;
+ number_of_packets = uurb->number_of_packets;
+ isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
+ number_of_packets;
+ isopkt = memdup_user(iso_frame_desc, isofrmlen);
+ if (IS_ERR(isopkt)) {
+ ret = PTR_ERR(isopkt);
+ isopkt = NULL;
+ goto error;
+ }
+ for (totlen = u = 0; u < number_of_packets; u++) {
+ /*
+ * arbitrary limit need for USB 3.0
+ * bMaxBurst (0~15 allowed, 1~16 packets)
+ * bmAttributes (bit 1:0, mult 0~2, 1~3 packets)
+ * sizemax: 1024 * 16 * 3 = 49152
+ */
+ if (isopkt[u].length > 49152) {
+ ret = -EINVAL;
+ goto error;
+ }
+ totlen += isopkt[u].length;
+ }
+ u *= sizeof(struct usb_iso_packet_descriptor);
+ uurb->buffer_length = totlen;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (uurb->buffer_length > 0 &&
+ !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ as = alloc_async(number_of_packets);
+ if (!as) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ as->usbm = find_memory_area(ps, uurb);
+ if (IS_ERR(as->usbm)) {
+ ret = PTR_ERR(as->usbm);
+ as->usbm = NULL;
+ goto error;
+ }
+
+ /* do not use SG buffers when memory mapped segments
+ * are in use
+ */
+ if (as->usbm)
+ num_sgs = 0;
+
+ u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
+ num_sgs * sizeof(struct scatterlist);
+ ret = usbfs_increase_memory_usage(u);
+ if (ret)
+ goto error;
+ as->mem_usage = u;
+
+ if (num_sgs) {
+ as->urb->sg = kmalloc_array(num_sgs,
+ sizeof(struct scatterlist),
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!as->urb->sg) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ as->urb->num_sgs = num_sgs;
+ sg_init_table(as->urb->sg, as->urb->num_sgs);
+
+ totlen = uurb->buffer_length;
+ for (i = 0; i < as->urb->num_sgs; i++) {
+ u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
+ buf = kmalloc(u, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ sg_set_buf(&as->urb->sg[i], buf, u);
+
+ if (!is_in) {
+ if (copy_from_user(buf, uurb->buffer, u)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ uurb->buffer += u;
+ }
+ totlen -= u;
+ }
+ } else if (uurb->buffer_length > 0) {
+ if (as->usbm) {
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
+
+ as->urb->transfer_buffer = as->usbm->mem +
+ (uurb_start - as->usbm->vm_start);
+ } else {
+ as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!as->urb->transfer_buffer) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ if (!is_in) {
+ if (copy_from_user(as->urb->transfer_buffer,
+ uurb->buffer,
+ uurb->buffer_length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
+ /*
+ * Isochronous input data may end up being
+ * discontiguous if some of the packets are
+ * short. Clear the buffer so that the gaps
+ * don't leak kernel data to userspace.
+ */
+ memset(as->urb->transfer_buffer, 0,
+ uurb->buffer_length);
+ }
+ }
+ }
+ as->urb->dev = ps->dev;
+ as->urb->pipe = (uurb->type << 30) |
+ __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+ (uurb->endpoint & USB_DIR_IN);
+
+ /* This tedious sequence is necessary because the URB_* flags
+ * are internal to the kernel and subject to change, whereas
+ * the USBDEVFS_URB_* flags are a user API and must not be changed.
+ */
+ u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
+ if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
+ u |= URB_ISO_ASAP;
+ if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
+ u |= URB_SHORT_NOT_OK;
+ 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;
+ as->urb->start_frame = uurb->start_frame;
+ as->urb->number_of_packets = number_of_packets;
+ as->urb->stream_id = stream_id;
+
+ if (ep->desc.bInterval) {
+ if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+ ps->dev->speed == USB_SPEED_HIGH ||
+ ps->dev->speed >= USB_SPEED_SUPER)
+ as->urb->interval = 1 <<
+ min(15, ep->desc.bInterval - 1);
+ else
+ as->urb->interval = ep->desc.bInterval;
+ }
+
+ as->urb->context = as;
+ as->urb->complete = async_completed;
+ for (totlen = u = 0; u < number_of_packets; u++) {
+ as->urb->iso_frame_desc[u].offset = totlen;
+ as->urb->iso_frame_desc[u].length = isopkt[u].length;
+ totlen += isopkt[u].length;
+ }
+ kfree(isopkt);
+ isopkt = NULL;
+ as->ps = ps;
+ as->userurb = arg;
+ if (as->usbm) {
+ unsigned long uurb_start = (unsigned long)uurb->buffer;
+
+ as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ as->urb->transfer_dma = as->usbm->dma_handle +
+ (uurb_start - as->usbm->vm_start);
+ } else if (is_in && uurb->buffer_length > 0)
+ as->userbuffer = uurb->buffer;
+ as->signr = uurb->signr;
+ as->ifnum = ifnum;
+ as->pid = get_pid(task_pid(current));
+ as->cred = get_current_cred();
+ snoop_urb(ps->dev, as->userurb, as->urb->pipe,
+ as->urb->transfer_buffer_length, 0, SUBMIT,
+ NULL, 0);
+ if (!is_in)
+ snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
+
+ async_newpending(as);
+
+ if (usb_endpoint_xfer_bulk(&ep->desc)) {
+ spin_lock_irq(&ps->lock);
+
+ /* Not exactly the endpoint address; the direction bit is
+ * shifted to the 0x10 position so that the value will be
+ * between 0 and 31.
+ */
+ as->bulk_addr = usb_endpoint_num(&ep->desc) |
+ ((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ >> 3);
+
+ /* If this bulk URB is the start of a new transfer, re-enable
+ * the endpoint. Otherwise mark it as a continuation URB.
+ */
+ if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
+ as->bulk_status = AS_CONTINUATION;
+ else
+ ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
+
+ /* Don't accept continuation URBs if the endpoint is
+ * disabled because of an earlier error.
+ */
+ if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
+ ret = -EREMOTEIO;
+ else
+ ret = usb_submit_urb(as->urb, GFP_ATOMIC);
+ spin_unlock_irq(&ps->lock);
+ } else {
+ ret = usb_submit_urb(as->urb, GFP_KERNEL);
+ }
+
+ if (ret) {
+ dev_printk(KERN_DEBUG, &ps->dev->dev,
+ "usbfs: usb_submit_urb returned %d\n", ret);
+ snoop_urb(ps->dev, as->userurb, as->urb->pipe,
+ 0, ret, COMPLETE, NULL, 0);
+ async_removepending(as);
+ goto error;
+ }
+ return 0;
+
+ error:
+ kfree(isopkt);
+ kfree(dr);
+ if (as)
+ free_async(as);
+ return ret;
+}
+
+static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_urb uurb;
+
+ if (copy_from_user(&uurb, arg, sizeof(uurb)))
+ return -EFAULT;
+
+ return proc_do_submiturb(ps, &uurb,
+ (((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
+ arg);
+}
+
+static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
+{
+ struct urb *urb;
+ struct async *as;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ as = async_getpending(ps, arg);
+ if (!as) {
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return -EINVAL;
+ }
+
+ urb = as->urb;
+ usb_get_urb(urb);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
+
+ 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;
+ struct usbdevfs_urb __user *userurb = as->userurb;
+ 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;
+ }
+ if (put_user(as->status, &userurb->status))
+ goto err_out;
+ if (put_user(urb->actual_length, &userurb->actual_length))
+ goto err_out;
+ if (put_user(urb->error_count, &userurb->error_count))
+ goto err_out;
+
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
+ &userurb->iso_frame_desc[i].actual_length))
+ goto err_out;
+ if (put_user(urb->iso_frame_desc[i].status,
+ &userurb->iso_frame_desc[i].status))
+ goto err_out;
+ }
+ }
+
+ if (put_user(addr, (void __user * __user *)arg))
+ return -EFAULT;
+ return 0;
+
+err_out:
+ return -EFAULT;
+}
+
+static struct async *reap_as(struct usb_dev_state *ps)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct async *as = NULL;
+ struct usb_device *dev = ps->dev;
+
+ add_wait_queue(&ps->wait, &wait);
+ for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
+ as = async_getcompleted(ps);
+ if (as || !connected(ps))
+ break;
+ if (signal_pending(current))
+ break;
+ usb_unlock_device(dev);
+ schedule();
+ usb_lock_device(dev);
+ }
+ remove_wait_queue(&ps->wait, &wait);
+ set_current_state(TASK_RUNNING);
+ return as;
+}
+
+static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+
+ if (as) {
+ int retval;
+
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
+ retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
+ if (signal_pending(current))
+ return -EINTR;
+ return -ENODEV;
+}
+
+static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
+{
+ int retval;
+ struct async *as;
+
+ as = async_getcompleted(ps);
+ if (as) {
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
+ retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ } else {
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
+ }
+ return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static int proc_control_compat(struct usb_dev_state *ps,
+ struct usbdevfs_ctrltransfer32 __user *p32)
+{
+ struct usbdevfs_ctrltransfer __user *p;
+ __u32 udata;
+ p = compat_alloc_user_space(sizeof(*p));
+ if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
+ get_user(udata, &p32->data) ||
+ put_user(compat_ptr(udata), &p->data))
+ return -EFAULT;
+ return proc_control(ps, p);
+}
+
+static int proc_bulk_compat(struct usb_dev_state *ps,
+ struct usbdevfs_bulktransfer32 __user *p32)
+{
+ struct usbdevfs_bulktransfer __user *p;
+ compat_uint_t n;
+ compat_caddr_t addr;
+
+ p = compat_alloc_user_space(sizeof(*p));
+
+ if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
+ get_user(n, &p32->len) || put_user(n, &p->len) ||
+ get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
+ get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
+ return -EFAULT;
+
+ return proc_bulk(ps, p);
+}
+static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_disconnectsignal32 ds;
+
+ if (copy_from_user(&ds, arg, sizeof(ds)))
+ return -EFAULT;
+ ps->discsignr = ds.signr;
+ ps->disccontext = compat_ptr(ds.context);
+ return 0;
+}
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+ struct usbdevfs_urb32 __user *uurb)
+{
+ struct usbdevfs_urb32 urb32;
+ if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
+ return -EFAULT;
+ kurb->type = urb32.type;
+ kurb->endpoint = urb32.endpoint;
+ kurb->status = urb32.status;
+ kurb->flags = urb32.flags;
+ kurb->buffer = compat_ptr(urb32.buffer);
+ kurb->buffer_length = urb32.buffer_length;
+ kurb->actual_length = urb32.actual_length;
+ kurb->start_frame = urb32.start_frame;
+ kurb->number_of_packets = urb32.number_of_packets;
+ kurb->error_count = urb32.error_count;
+ kurb->signr = urb32.signr;
+ kurb->usercontext = compat_ptr(urb32.usercontext);
+ return 0;
+}
+
+static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_urb uurb;
+
+ if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
+ return -EFAULT;
+
+ return proc_do_submiturb(ps, &uurb,
+ ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
+ arg);
+}
+
+static int processcompl_compat(struct async *as, void __user * __user *arg)
+{
+ struct urb *urb = as->urb;
+ struct usbdevfs_urb32 __user *userurb = as->userurb;
+ 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;
+ }
+ if (put_user(as->status, &userurb->status))
+ return -EFAULT;
+ if (put_user(urb->actual_length, &userurb->actual_length))
+ return -EFAULT;
+ if (put_user(urb->error_count, &userurb->error_count))
+ return -EFAULT;
+
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
+ &userurb->iso_frame_desc[i].actual_length))
+ return -EFAULT;
+ if (put_user(urb->iso_frame_desc[i].status,
+ &userurb->iso_frame_desc[i].status))
+ return -EFAULT;
+ }
+ }
+
+ if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
+ return -EFAULT;
+ return 0;
+}
+
+static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+
+ if (as) {
+ int retval;
+
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
+ retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
+ if (signal_pending(current))
+ return -EINTR;
+ return -ENODEV;
+}
+
+static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
+{
+ int retval;
+ struct async *as;
+
+ as = async_getcompleted(ps);
+ if (as) {
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
+ retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ } else {
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
+ }
+ return retval;
+}
+
+
+#endif
+
+static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_disconnectsignal ds;
+
+ if (copy_from_user(&ds, arg, sizeof(ds)))
+ return -EFAULT;
+ ps->discsignr = ds.signr;
+ ps->disccontext = ds.context;
+ return 0;
+}
+
+static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned int ifnum;
+
+ if (get_user(ifnum, (unsigned int __user *)arg))
+ return -EFAULT;
+ return claimintf(ps, ifnum);
+}
+
+static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned int ifnum;
+ int ret;
+
+ if (get_user(ifnum, (unsigned int __user *)arg))
+ return -EFAULT;
+ ret = releaseintf(ps, ifnum);
+ if (ret < 0)
+ return ret;
+ destroy_async_on_interface(ps, ifnum);
+ return 0;
+}
+
+static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
+{
+ int size;
+ void *buf = NULL;
+ int retval = 0;
+ struct usb_interface *intf = NULL;
+ struct usb_driver *driver = NULL;
+
+ if (ps->privileges_dropped)
+ return -EACCES;
+
+ /* alloc buffer */
+ size = _IOC_SIZE(ctl->ioctl_code);
+ if (size > 0) {
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
+ if (copy_from_user(buf, ctl->data, size)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+ } else {
+ memset(buf, 0, size);
+ }
+ }
+
+ if (!connected(ps)) {
+ kfree(buf);
+ return -ENODEV;
+ }
+
+ if (ps->dev->state != USB_STATE_CONFIGURED)
+ retval = -EHOSTUNREACH;
+ else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
+ retval = -EINVAL;
+ else switch (ctl->ioctl_code) {
+
+ /* disconnect kernel driver from interface */
+ case USBDEVFS_DISCONNECT:
+ if (intf->dev.driver) {
+ driver = to_usb_driver(intf->dev.driver);
+ dev_dbg(&intf->dev, "disconnect by usbfs\n");
+ usb_driver_release_interface(driver, intf);
+ } else
+ retval = -ENODATA;
+ break;
+
+ /* let kernel drivers try to (re)bind to the interface */
+ case USBDEVFS_CONNECT:
+ if (!intf->dev.driver)
+ retval = device_attach(&intf->dev);
+ else
+ retval = -EBUSY;
+ break;
+
+ /* talk directly to the interface's driver */
+ default:
+ if (intf->dev.driver)
+ driver = to_usb_driver(intf->dev.driver);
+ if (driver == NULL || driver->unlocked_ioctl == NULL) {
+ retval = -ENOTTY;
+ } else {
+ retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
+ if (retval == -ENOIOCTLCMD)
+ retval = -ENOTTY;
+ }
+ }
+
+ /* cleanup and return */
+ if (retval >= 0
+ && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
+ && size > 0
+ && copy_to_user(ctl->data, buf, size) != 0)
+ retval = -EFAULT;
+
+ kfree(buf);
+ return retval;
+}
+
+static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_ioctl ctrl;
+
+ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+ return -EFAULT;
+ return proc_ioctl(ps, &ctrl);
+}
+
+#ifdef CONFIG_COMPAT
+static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
+{
+ struct usbdevfs_ioctl32 ioc32;
+ struct usbdevfs_ioctl ctrl;
+
+ if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
+ return -EFAULT;
+ ctrl.ifno = ioc32.ifno;
+ ctrl.ioctl_code = ioc32.ioctl_code;
+ ctrl.data = compat_ptr(ioc32.data);
+ return proc_ioctl(ps, &ctrl);
+}
+#endif
+
+static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned portnum;
+ int rc;
+
+ if (get_user(portnum, (unsigned __user *) arg))
+ return -EFAULT;
+ rc = usb_hub_claim_port(ps->dev, portnum, ps);
+ if (rc == 0)
+ snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
+ portnum, task_pid_nr(current), current->comm);
+ return rc;
+}
+
+static int proc_release_port(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned portnum;
+
+ if (get_user(portnum, (unsigned __user *) arg))
+ return -EFAULT;
+ return usb_hub_release_port(ps->dev, portnum, ps);
+}
+
+static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
+{
+ __u32 caps;
+
+ caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
+ USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
+ USBDEVFS_CAP_DROP_PRIVILEGES;
+ if (!ps->dev->bus->no_stop_on_short)
+ caps |= USBDEVFS_CAP_BULK_CONTINUATION;
+ if (ps->dev->bus->sg_tablesize)
+ caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
+
+ if (put_user(caps, (__u32 __user *)arg))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_disconnect_claim dc;
+ struct usb_interface *intf;
+
+ if (copy_from_user(&dc, arg, sizeof(dc)))
+ return -EFAULT;
+
+ intf = usb_ifnum_to_if(ps->dev, dc.interface);
+ if (!intf)
+ return -EINVAL;
+
+ if (intf->dev.driver) {
+ struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+ if (ps->privileges_dropped)
+ return -EACCES;
+
+ if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
+ strncmp(dc.driver, intf->dev.driver->name,
+ sizeof(dc.driver)) != 0)
+ return -EBUSY;
+
+ if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
+ strncmp(dc.driver, intf->dev.driver->name,
+ sizeof(dc.driver)) == 0)
+ return -EBUSY;
+
+ dev_dbg(&intf->dev, "disconnect by usbfs\n");
+ usb_driver_release_interface(driver, intf);
+ }
+
+ return claimintf(ps, dc.interface);
+}
+
+static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned num_streams, num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf;
+ int r;
+
+ r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
+ &eps, &intf);
+ if (r)
+ return r;
+
+ destroy_async_on_interface(ps,
+ intf->altsetting[0].desc.bInterfaceNumber);
+
+ r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
+ kfree(eps);
+ return r;
+}
+
+static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf;
+ int r;
+
+ r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
+ if (r)
+ return r;
+
+ destroy_async_on_interface(ps,
+ intf->altsetting[0].desc.bInterfaceNumber);
+
+ r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
+ kfree(eps);
+ return r;
+}
+
+static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
+{
+ u32 data;
+
+ if (copy_from_user(&data, arg, sizeof(data)))
+ return -EFAULT;
+
+ /* This is a one way operation. Once privileges are
+ * dropped, you cannot regain them. You may however reissue
+ * this ioctl to shrink the allowed interfaces mask.
+ */
+ ps->interface_allowed_mask &= data;
+ ps->privileges_dropped = true;
+
+ return 0;
+}
+
+/*
+ * NOTE: All requests here that have interface numbers as parameters
+ * are assuming that somehow the configuration has been prevented from
+ * changing. But there's no mechanism to ensure that...
+ */
+static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
+ void __user *p)
+{
+ struct usb_dev_state *ps = file->private_data;
+ struct inode *inode = file_inode(file);
+ struct usb_device *dev = ps->dev;
+ int ret = -ENOTTY;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EPERM;
+
+ usb_lock_device(dev);
+
+ /* Reap operations are allowed even after disconnection */
+ switch (cmd) {
+ case USBDEVFS_REAPURB:
+ snoop(&dev->dev, "%s: REAPURB\n", __func__);
+ ret = proc_reapurb(ps, p);
+ goto done;
+
+ case USBDEVFS_REAPURBNDELAY:
+ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
+ ret = proc_reapurbnonblock(ps, p);
+ goto done;
+
+#ifdef CONFIG_COMPAT
+ case USBDEVFS_REAPURB32:
+ snoop(&dev->dev, "%s: REAPURB32\n", __func__);
+ ret = proc_reapurb_compat(ps, p);
+ goto done;
+
+ case USBDEVFS_REAPURBNDELAY32:
+ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
+ ret = proc_reapurbnonblock_compat(ps, p);
+ goto done;
+#endif
+ }
+
+ if (!connected(ps)) {
+ usb_unlock_device(dev);
+ return -ENODEV;
+ }
+
+ switch (cmd) {
+ case USBDEVFS_CONTROL:
+ snoop(&dev->dev, "%s: CONTROL\n", __func__);
+ ret = proc_control(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_BULK:
+ snoop(&dev->dev, "%s: BULK\n", __func__);
+ ret = proc_bulk(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_RESETEP:
+ snoop(&dev->dev, "%s: RESETEP\n", __func__);
+ ret = proc_resetep(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_RESET:
+ snoop(&dev->dev, "%s: RESET\n", __func__);
+ ret = proc_resetdevice(ps);
+ break;
+
+ case USBDEVFS_CLEAR_HALT:
+ snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
+ ret = proc_clearhalt(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_GETDRIVER:
+ snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
+ ret = proc_getdriver(ps, p);
+ break;
+
+ case USBDEVFS_CONNECTINFO:
+ snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
+ ret = proc_connectinfo(ps, p);
+ break;
+
+ case USBDEVFS_SETINTERFACE:
+ snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
+ ret = proc_setintf(ps, p);
+ break;
+
+ case USBDEVFS_SETCONFIGURATION:
+ snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
+ ret = proc_setconfig(ps, p);
+ break;
+
+ case USBDEVFS_SUBMITURB:
+ snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
+ ret = proc_submiturb(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+#ifdef CONFIG_COMPAT
+ case USBDEVFS_CONTROL32:
+ snoop(&dev->dev, "%s: CONTROL32\n", __func__);
+ ret = proc_control_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_BULK32:
+ snoop(&dev->dev, "%s: BULK32\n", __func__);
+ ret = proc_bulk_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_DISCSIGNAL32:
+ snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
+ ret = proc_disconnectsignal_compat(ps, p);
+ break;
+
+ case USBDEVFS_SUBMITURB32:
+ snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
+ ret = proc_submiturb_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = current_time(inode);
+ break;
+
+ case USBDEVFS_IOCTL32:
+ snoop(&dev->dev, "%s: IOCTL32\n", __func__);
+ ret = proc_ioctl_compat(ps, ptr_to_compat(p));
+ break;
+#endif
+
+ case USBDEVFS_DISCARDURB:
+ snoop(&dev->dev, "%s: DISCARDURB %px\n", __func__, p);
+ ret = proc_unlinkurb(ps, p);
+ break;
+
+ case USBDEVFS_DISCSIGNAL:
+ snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
+ ret = proc_disconnectsignal(ps, p);
+ break;
+
+ case USBDEVFS_CLAIMINTERFACE:
+ snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
+ ret = proc_claiminterface(ps, p);
+ break;
+
+ case USBDEVFS_RELEASEINTERFACE:
+ snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
+ ret = proc_releaseinterface(ps, p);
+ break;
+
+ case USBDEVFS_IOCTL:
+ snoop(&dev->dev, "%s: IOCTL\n", __func__);
+ ret = proc_ioctl_default(ps, p);
+ break;
+
+ case USBDEVFS_CLAIM_PORT:
+ snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
+ ret = proc_claim_port(ps, p);
+ break;
+
+ case USBDEVFS_RELEASE_PORT:
+ snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
+ ret = proc_release_port(ps, p);
+ break;
+ case USBDEVFS_GET_CAPABILITIES:
+ ret = proc_get_capabilities(ps, p);
+ break;
+ case USBDEVFS_DISCONNECT_CLAIM:
+ ret = proc_disconnect_claim(ps, p);
+ break;
+ case USBDEVFS_ALLOC_STREAMS:
+ ret = proc_alloc_streams(ps, p);
+ break;
+ case USBDEVFS_FREE_STREAMS:
+ ret = proc_free_streams(ps, p);
+ break;
+ case USBDEVFS_DROP_PRIVILEGES:
+ ret = proc_drop_privileges(ps, p);
+ break;
+ case USBDEVFS_GET_SPEED:
+ ret = ps->dev->speed;
+ break;
+ }
+
+ done:
+ usb_unlock_device(dev);
+ if (ret >= 0)
+ inode->i_atime = current_time(inode);
+ return ret;
+}
+
+static long usbdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
+
+ 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)
+{
+ struct usb_dev_state *ps = file->private_data;
+ __poll_t mask = 0;
+
+ poll_wait(file, &ps->wait, wait);
+ if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+ if (!connected(ps))
+ mask |= EPOLLHUP;
+ if (list_empty(&ps->list))
+ mask |= EPOLLERR;
+ return mask;
+}
+
+const struct file_operations usbdev_file_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_seek_end_llseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+ .unlocked_ioctl = usbdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usbdev_compat_ioctl,
+#endif
+ .mmap = usbdev_mmap,
+ .open = usbdev_open,
+ .release = usbdev_release,
+};
+
+static void usbdev_remove(struct usb_device *udev)
+{
+ struct usb_dev_state *ps;
+ struct siginfo sinfo;
+
+ 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);
+ list_del_init(&ps->list);
+ if (ps->discsignr) {
+ clear_siginfo(&sinfo);
+ sinfo.si_signo = ps->discsignr;
+ sinfo.si_errno = EPIPE;
+ sinfo.si_code = SI_ASYNCIO;
+ sinfo.si_addr = ps->disccontext;
+ kill_pid_info_as_cred(ps->discsignr, &sinfo,
+ ps->disc_pid, ps->cred);
+ }
+ }
+}
+
+static int usbdev_notify(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ switch (action) {
+ case USB_DEVICE_ADD:
+ break;
+ case USB_DEVICE_REMOVE:
+ usbdev_remove(dev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block usbdev_nb = {
+ .notifier_call = usbdev_notify,
+};
+
+static struct cdev usb_device_cdev;
+
+int __init usb_devio_init(void)
+{
+ int retval;
+
+ retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
+ "usb_device");
+ if (retval) {
+ printk(KERN_ERR "Unable to register minors for usb_device\n");
+ goto out;
+ }
+ cdev_init(&usb_device_cdev, &usbdev_file_operations);
+ retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
+ if (retval) {
+ printk(KERN_ERR "Unable to get usb_device major %d\n",
+ USB_DEVICE_MAJOR);
+ goto error_cdev;
+ }
+ usb_register_notify(&usbdev_nb);
+out:
+ return retval;
+
+error_cdev:
+ unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+ goto out;
+}
+
+void usb_devio_cleanup(void)
+{
+ usb_unregister_notify(&usbdev_nb);
+ cdev_del(&usb_device_cdev);
+ unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
new file mode 100644
index 000000000..3255b2bb0
--- /dev/null
+++ b/drivers/usb/core/driver.c
@@ -0,0 +1,1928 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/driver.c - most of the driver model stuff for usb
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * based on drivers/usb/usb.c which had the following copyrights:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2004
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ * Released under the GPLv2 only.
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+ * matching, probing, releasing, suspending and resuming for
+ * real drivers.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include <linux/usb/hcd.h>
+
+#include "usb.h"
+
+
+/*
+ * Adds a new dynamic USBdevice ID to this driver,
+ * and cause the driver to probe for all devices again.
+ */
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ const struct usb_device_id *id_table,
+ struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_dynid *dynid;
+ u32 idVendor = 0;
+ u32 idProduct = 0;
+ unsigned int bInterfaceClass = 0;
+ u32 refVendor, refProduct;
+ int fields = 0;
+ int retval = 0;
+
+ fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct,
+ &bInterfaceClass, &refVendor, &refProduct);
+ if (fields < 2)
+ return -EINVAL;
+
+ dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+ if (!dynid)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dynid->node);
+ dynid->id.idVendor = idVendor;
+ dynid->id.idProduct = idProduct;
+ dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ if (fields > 2 && bInterfaceClass) {
+ if (bInterfaceClass > 255) {
+ retval = -EINVAL;
+ goto fail;
+ }
+
+ dynid->id.bInterfaceClass = (u8)bInterfaceClass;
+ dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+ }
+
+ if (fields > 4) {
+ const struct usb_device_id *id = id_table;
+
+ if (!id) {
+ retval = -ENODEV;
+ goto fail;
+ }
+
+ for (; id->match_flags; id++)
+ if (id->idVendor == refVendor && id->idProduct == refProduct)
+ break;
+
+ if (id->match_flags) {
+ dynid->id.driver_info = id->driver_info;
+ } else {
+ retval = -ENODEV;
+ goto fail;
+ }
+ }
+
+ spin_lock(&dynids->lock);
+ list_add_tail(&dynid->node, &dynids->list);
+ spin_unlock(&dynids->lock);
+
+ retval = driver_attach(driver);
+
+ if (retval)
+ return retval;
+ return count;
+
+fail:
+ kfree(dynid);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
+{
+ struct usb_dynid *dynid;
+ size_t count = 0;
+
+ list_for_each_entry(dynid, &dynids->list, node)
+ if (dynid->id.bInterfaceClass != 0)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n",
+ dynid->id.idVendor, dynid->id.idProduct,
+ dynid->id.bInterfaceClass);
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n",
+ dynid->id.idVendor, dynid->id.idProduct);
+ return count;
+}
+EXPORT_SYMBOL_GPL(usb_show_dynids);
+
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
+static ssize_t new_id_store(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, driver, buf, count);
+}
+static DRIVER_ATTR_RW(new_id);
+
+/*
+ * Remove a USB device ID from this driver
+ */
+static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
+ size_t count)
+{
+ struct usb_dynid *dynid, *n;
+ struct usb_driver *usb_driver = to_usb_driver(driver);
+ u32 idVendor;
+ u32 idProduct;
+ int fields;
+
+ fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
+ if (fields < 2)
+ return -EINVAL;
+
+ spin_lock(&usb_driver->dynids.lock);
+ list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
+ struct usb_device_id *id = &dynid->id;
+
+ if ((id->idVendor == idVendor) &&
+ (id->idProduct == idProduct)) {
+ list_del(&dynid->node);
+ kfree(dynid);
+ break;
+ }
+ }
+ spin_unlock(&usb_driver->dynids.lock);
+ return count;
+}
+
+static ssize_t remove_id_show(struct device_driver *driver, char *buf)
+{
+ return new_id_show(driver, buf);
+}
+static DRIVER_ATTR_RW(remove_id);
+
+static int usb_create_newid_files(struct usb_driver *usb_drv)
+{
+ int error = 0;
+
+ if (usb_drv->no_dynamic_id)
+ goto exit;
+
+ if (usb_drv->probe != NULL) {
+ error = driver_create_file(&usb_drv->drvwrap.driver,
+ &driver_attr_new_id);
+ if (error == 0) {
+ error = driver_create_file(&usb_drv->drvwrap.driver,
+ &driver_attr_remove_id);
+ if (error)
+ driver_remove_file(&usb_drv->drvwrap.driver,
+ &driver_attr_new_id);
+ }
+ }
+exit:
+ return error;
+}
+
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
+{
+ if (usb_drv->no_dynamic_id)
+ return;
+
+ if (usb_drv->probe != NULL) {
+ driver_remove_file(&usb_drv->drvwrap.driver,
+ &driver_attr_remove_id);
+ driver_remove_file(&usb_drv->drvwrap.driver,
+ &driver_attr_new_id);
+ }
+}
+
+static void usb_free_dynids(struct usb_driver *usb_drv)
+{
+ struct usb_dynid *dynid, *n;
+
+ spin_lock(&usb_drv->dynids.lock);
+ list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) {
+ list_del(&dynid->node);
+ kfree(dynid);
+ }
+ spin_unlock(&usb_drv->dynids.lock);
+}
+
+static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
+ struct usb_driver *drv)
+{
+ struct usb_dynid *dynid;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (usb_match_one_id(intf, &dynid->id)) {
+ spin_unlock(&drv->dynids.lock);
+ return &dynid->id;
+ }
+ }
+ spin_unlock(&drv->dynids.lock);
+ return NULL;
+}
+
+
+/* called from driver core with dev locked */
+static int usb_probe_device(struct device *dev)
+{
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+ struct usb_device *udev = to_usb_device(dev);
+ int error = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* TODO: Add real matching code */
+
+ /* The device should always appear to be in use
+ * unless the driver supports autosuspend.
+ */
+ if (!udriver->supports_autosuspend)
+ error = usb_autoresume_device(udev);
+
+ if (!error)
+ error = udriver->probe(udev);
+ return error;
+}
+
+/* called from driver core with dev locked */
+static int usb_unbind_device(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+
+ udriver->disconnect(udev);
+ if (!udriver->supports_autosuspend)
+ usb_autosuspend_device(udev);
+ return 0;
+}
+
+/* called from driver core with dev locked */
+static int usb_probe_interface(struct device *dev)
+{
+ struct usb_driver *driver = to_usb_driver(dev->driver);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ const struct usb_device_id *id;
+ int error = -ENODEV;
+ int lpm_disable_error = -ENODEV;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ intf->needs_binding = 0;
+
+ if (usb_device_is_owned(udev))
+ return error;
+
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return error;
+ } else if (intf->authorized == 0) {
+ dev_err(&intf->dev, "Interface %d is not authorized for usage\n",
+ intf->altsetting->desc.bInterfaceNumber);
+ return error;
+ }
+
+ id = usb_match_dynamic_id(intf, driver);
+ if (!id)
+ id = usb_match_id(intf, driver->id_table);
+ if (!id)
+ return error;
+
+ dev_dbg(dev, "%s - got id\n", __func__);
+
+ error = usb_autoresume_device(udev);
+ if (error)
+ return error;
+
+ intf->condition = USB_INTERFACE_BINDING;
+
+ /* Probed interfaces are initially active. They are
+ * runtime-PM-enabled only if the driver has autosuspend support.
+ * They are sensitive to their children's power states.
+ */
+ pm_runtime_set_active(dev);
+ pm_suspend_ignore_children(dev, false);
+ if (driver->supports_autosuspend)
+ pm_runtime_enable(dev);
+
+ /* If the new driver doesn't allow hub-initiated LPM, and we can't
+ * disable hub-initiated LPM, then fail the probe.
+ *
+ * Otherwise, leaving LPM enabled should be harmless, because the
+ * endpoint intervals should remain the same, and the U1/U2 timeouts
+ * should remain the same.
+ *
+ * If we need to install alt setting 0 before probe, or another alt
+ * setting during probe, that should also be fine. usb_set_interface()
+ * will attempt to disable LPM, and fail if it can't disable it.
+ */
+ 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);
+ error = lpm_disable_error;
+ goto err;
+ }
+ }
+
+ /* Carry out a deferred switch to altsetting 0 */
+ if (intf->needs_altsetting0) {
+ error = usb_set_interface(udev, intf->altsetting[0].
+ desc.bInterfaceNumber, 0);
+ if (error < 0)
+ goto err;
+ intf->needs_altsetting0 = 0;
+ }
+
+ error = driver->probe(intf, id);
+ if (error)
+ goto err;
+
+ intf->condition = USB_INTERFACE_BOUND;
+
+ /* If the LPM disable succeeded, balance the ref counts. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
+ usb_autosuspend_device(udev);
+ return error;
+
+ err:
+ usb_set_intfdata(intf, NULL);
+ intf->needs_remote_wakeup = 0;
+ intf->condition = USB_INTERFACE_UNBOUND;
+
+ /* If the LPM disable succeeded, balance the ref counts. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
+ /* Unbound interfaces are always runtime-PM-disabled and -suspended */
+ if (driver->supports_autosuspend)
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+ usb_autosuspend_device(udev);
+ return error;
+}
+
+/* called from driver core with dev locked */
+static int usb_unbind_interface(struct device *dev)
+{
+ struct usb_driver *driver = to_usb_driver(dev->driver);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_host_endpoint *ep, **eps = NULL;
+ struct usb_device *udev;
+ int i, j, error, r;
+ int lpm_disable_error = -ENODEV;
+
+ intf->condition = USB_INTERFACE_UNBINDING;
+
+ /* Autoresume for set_interface call below */
+ udev = interface_to_usbdev(intf);
+ error = usb_autoresume_device(udev);
+
+ /* If hub-initiated LPM policy may change, attempt to disable LPM until
+ * the driver is unbound. If LPM isn't disabled, that's fine because it
+ * wouldn't be enabled unless all the bound interfaces supported
+ * hub-initiated LPM.
+ */
+ if (driver->disable_hub_initiated_lpm)
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+
+ /*
+ * Terminate all URBs for this interface unless the driver
+ * supports "soft" unbinding and the device is still present.
+ */
+ if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED)
+ usb_disable_interface(udev, intf, false);
+
+ driver->disconnect(intf);
+
+ /* Free streams */
+ for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+ ep = &intf->cur_altsetting->endpoint[i];
+ if (ep->streams == 0)
+ continue;
+ if (j == 0) {
+ eps = kmalloc_array(USB_MAXENDPOINTS, sizeof(void *),
+ GFP_KERNEL);
+ if (!eps)
+ break;
+ }
+ eps[j++] = ep;
+ }
+ if (j) {
+ usb_free_streams(intf, eps, j, GFP_KERNEL);
+ kfree(eps);
+ }
+
+ /* Reset other interface state.
+ * We cannot do a Set-Interface if the device is suspended or
+ * if it is prepared for a system sleep (since installing a new
+ * altsetting means creating new endpoint device entries).
+ * When either of these happens, defer the Set-Interface.
+ */
+ if (intf->cur_altsetting->desc.bAlternateSetting == 0) {
+ /* Already in altsetting 0 so skip Set-Interface.
+ * Just re-enable it without affecting the endpoint toggles.
+ */
+ usb_enable_interface(udev, intf, false);
+ } else if (!error && !intf->dev.power.is_prepared) {
+ r = usb_set_interface(udev, intf->altsetting[0].
+ desc.bInterfaceNumber, 0);
+ if (r < 0)
+ intf->needs_altsetting0 = 1;
+ } else {
+ intf->needs_altsetting0 = 1;
+ }
+ usb_set_intfdata(intf, NULL);
+
+ intf->condition = USB_INTERFACE_UNBOUND;
+ intf->needs_remote_wakeup = 0;
+
+ /* Attempt to re-enable USB3 LPM, if the disable succeeded. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
+ /* Unbound interfaces are always runtime-PM-disabled and -suspended */
+ if (driver->supports_autosuspend)
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+ if (!error)
+ usb_autosuspend_device(udev);
+
+ return 0;
+}
+
+/**
+ * usb_driver_claim_interface - bind a driver to an interface
+ * @driver: the driver to be bound
+ * @iface: the interface to which it will be bound; must be in the
+ * usb device's active configuration
+ * @priv: driver data associated with that interface
+ *
+ * This is used by usb device drivers that need to claim more than one
+ * interface on a device when probing (audio and acm are current examples).
+ * No device driver should directly modify internal usb_interface or
+ * usb_device structure members.
+ *
+ * Few drivers should need to use this routine, since the most natural
+ * way to bind to an interface is to return the private data from
+ * the driver's probe() method.
+ *
+ * Callers must own the device lock, so driver probe() entries don't need
+ * extra locking, but other call contexts may need to explicitly claim that
+ * lock.
+ *
+ * Return: 0 on success.
+ */
+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;
+
+ if (!iface)
+ return -ENODEV;
+
+ dev = &iface->dev;
+ if (dev->driver)
+ return -EBUSY;
+
+ /* reject claim if interface is not authorized */
+ 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;
+
+ /* 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
+ * device from being autosuspended, but left disabled. In either
+ * case they are sensitive to their children's power states.
+ */
+ pm_suspend_ignore_children(dev, false);
+ if (driver->supports_autosuspend)
+ pm_runtime_enable(dev);
+ else
+ pm_runtime_set_active(dev);
+
+ /* if interface was already added, bind now; else let
+ * the future device_add() bind it, bypassing probe()
+ */
+ if (device_is_registered(dev))
+ retval = device_bind_driver(dev);
+
+ 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;
+}
+EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
+
+/**
+ * usb_driver_release_interface - unbind a driver from an interface
+ * @driver: the driver to be unbound
+ * @iface: the interface from which it will be unbound
+ *
+ * This can be used by drivers to release an interface without waiting
+ * for their disconnect() methods to be called. In typical cases this
+ * also causes the driver disconnect() method to be called.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ * Callers must own the device lock, so driver disconnect() entries don't
+ * need extra locking, but other call contexts may need to explicitly claim
+ * that lock.
+ */
+void usb_driver_release_interface(struct usb_driver *driver,
+ struct usb_interface *iface)
+{
+ struct device *dev = &iface->dev;
+
+ /* this should never happen, don't release something that's not ours */
+ if (!dev->driver || dev->driver != &driver->drvwrap.driver)
+ return;
+
+ /* don't release from within disconnect() */
+ if (iface->condition != USB_INTERFACE_BOUND)
+ return;
+ iface->condition = USB_INTERFACE_UNBINDING;
+
+ /* Release via the driver core only if the interface
+ * has already been registered
+ */
+ if (device_is_registered(dev)) {
+ device_release_driver(dev);
+ } else {
+ device_lock(dev);
+ usb_unbind_interface(dev);
+ dev->driver = NULL;
+ device_unlock(dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_driver_release_interface);
+
+/* returns 0 if no match, 1 if match */
+int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
+{
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
+ return 0;
+
+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
+ greater than any unsigned number. */
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != dev->descriptor.bDeviceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+ return 0;
+
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id_intf(struct usb_device *dev,
+ struct usb_host_interface *intf,
+ const struct usb_device_id *id)
+{
+ /* The interface class, subclass, protocol and number should never be
+ * checked for a match if the device class is Vendor Specific,
+ * unless the match record specifies the Vendor ID. */
+ if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
+ !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+ USB_DEVICE_ID_MATCH_INT_NUMBER)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+ (id->bInterfaceClass != intf->desc.bInterfaceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+ (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+ (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+ (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
+ return 0;
+
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *intf;
+ struct usb_device *dev;
+
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
+ if (id == NULL)
+ return 0;
+
+ intf = interface->cur_altsetting;
+ dev = interface_to_usbdev(interface);
+
+ if (!usb_match_device(dev, id))
+ return 0;
+
+ return usb_match_one_id_intf(dev, intf, id);
+}
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
+/**
+ * usb_match_id - find first usb_device_id matching device or interface
+ * @interface: the interface of interest
+ * @id: array of usb_device_id structures, terminated by zero entry
+ *
+ * usb_match_id searches an array of usb_device_id's and returns
+ * the first one matching the device or interface, or null.
+ * This is used when binding (or rebinding) a driver to an interface.
+ * Most USB device drivers will use this indirectly, through the usb core,
+ * but some layered driver frameworks use it directly.
+ * These device tables are exported with MODULE_DEVICE_TABLE, through
+ * modutils, to support the driver loading functionality of USB hotplugging.
+ *
+ * Return: The first matching usb_device_id, or %NULL.
+ *
+ * What Matches:
+ *
+ * The "match_flags" element in a usb_device_id controls which
+ * members are used. If the corresponding bit is set, the
+ * value in the device_id must match its corresponding member
+ * in the device or interface descriptor, or else the device_id
+ * does not match.
+ *
+ * "driver_info" is normally used only by device drivers,
+ * but you can create a wildcard "matches anything" usb_device_id
+ * as a driver's "modules.usbmap" entry if you provide an id with
+ * only a nonzero "driver_info" field. If you do this, the USB device
+ * driver's probe() routine should use additional intelligence to
+ * decide whether to bind to the specified interface.
+ *
+ * What Makes Good usb_device_id Tables:
+ *
+ * The match algorithm is very simple, so that intelligence in
+ * driver selection must come from smart driver id records.
+ * Unless you have good reasons to use another selection policy,
+ * provide match elements only in related groups, and order match
+ * specifiers from specific to general. Use the macros provided
+ * for that purpose if you can.
+ *
+ * The most specific match specifiers use device descriptor
+ * data. These are commonly used with product-specific matches;
+ * the USB_DEVICE macro lets you provide vendor and product IDs,
+ * and you can also match against ranges of product revisions.
+ * These are widely used for devices with application or vendor
+ * specific bDeviceClass values.
+ *
+ * Matches based on device class/subclass/protocol specifications
+ * are slightly more general; use the USB_DEVICE_INFO macro, or
+ * its siblings. These are used with single-function devices
+ * where bDeviceClass doesn't specify that each interface has
+ * its own class.
+ *
+ * Matches based on interface class/subclass/protocol are the
+ * most general; they let drivers bind to any interface on a
+ * multiple-function device. Use the USB_INTERFACE_INFO
+ * macro, or its siblings, to match class-per-interface style
+ * devices (as recorded in bInterfaceClass).
+ *
+ * Note that an entry created by USB_INTERFACE_INFO won't match
+ * any interface if the device class is set to Vendor-Specific.
+ * This is deliberate; according to the USB spec the meanings of
+ * the interface class/subclass/protocol for these devices are also
+ * vendor-specific, and hence matching against a standard product
+ * class wouldn't work anyway. If you really want to use an
+ * interface-based match for such a device, create a match record
+ * that also specifies the vendor ID. (Unforunately there isn't a
+ * standard macro for creating records like this.)
+ *
+ * Within those groups, remember that not all combinations are
+ * meaningful. For example, don't give a product version range
+ * without vendor and product IDs; or specify a protocol without
+ * its associated class and subclass.
+ */
+const struct usb_device_id *usb_match_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
+ if (id == NULL)
+ return NULL;
+
+ /* It is important to check that id->driver_info is nonzero,
+ since an entry that is all zeroes except for a nonzero
+ id->driver_info is the way to create an entry that
+ indicates that the driver want to examine every
+ device and interface. */
+ for (; id->idVendor || id->idProduct || id->bDeviceClass ||
+ id->bInterfaceClass || id->driver_info; id++) {
+ if (usb_match_one_id(interface, id))
+ return id;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_match_id);
+
+static int usb_device_match(struct device *dev, struct device_driver *drv)
+{
+ /* devices and interfaces are handled separately */
+ if (is_usb_device(dev)) {
+
+ /* interface drivers never match devices */
+ if (!is_usb_device_driver(drv))
+ return 0;
+
+ /* TODO: Add real matching code */
+ return 1;
+
+ } else if (is_usb_interface(dev)) {
+ struct usb_interface *intf;
+ struct usb_driver *usb_drv;
+ const struct usb_device_id *id;
+
+ /* device drivers never match interfaces */
+ if (is_usb_device_driver(drv))
+ return 0;
+
+ intf = to_usb_interface(dev);
+ usb_drv = to_usb_driver(drv);
+
+ id = usb_match_id(intf, usb_drv->id_table);
+ if (id)
+ return 1;
+
+ id = usb_match_dynamic_id(intf, usb_drv);
+ if (id)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_device *usb_dev;
+
+ if (is_usb_device(dev)) {
+ usb_dev = to_usb_device(dev);
+ } else if (is_usb_interface(dev)) {
+ struct usb_interface *intf = to_usb_interface(dev);
+
+ usb_dev = interface_to_usbdev(intf);
+ } else {
+ return 0;
+ }
+
+ if (usb_dev->devnum < 0) {
+ /* driver is often null here; dev_dbg() would oops */
+ pr_debug("usb %s: already deleted?\n", dev_name(dev));
+ return -ENODEV;
+ }
+ if (!usb_dev->bus) {
+ pr_debug("usb %s: bus removed?\n", dev_name(dev));
+ return -ENODEV;
+ }
+
+ /* per-device configurations are common */
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+ return -ENOMEM;
+
+ /* class-based driver binding models */
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol))
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * usb_register_device_driver - register a USB device (not interface) driver
+ * @new_udriver: USB operations for the device driver
+ * @owner: module owner of this driver.
+ *
+ * Registers a USB device driver with the USB core. The list of
+ * unattached devices will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized devices.
+ *
+ * Return: A negative error code on failure and 0 on success.
+ */
+int usb_register_device_driver(struct usb_device_driver *new_udriver,
+ struct module *owner)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ new_udriver->drvwrap.for_devices = 1;
+ new_udriver->drvwrap.driver.name = new_udriver->name;
+ new_udriver->drvwrap.driver.bus = &usb_bus_type;
+ new_udriver->drvwrap.driver.probe = usb_probe_device;
+ new_udriver->drvwrap.driver.remove = usb_unbind_device;
+ new_udriver->drvwrap.driver.owner = owner;
+
+ retval = driver_register(&new_udriver->drvwrap.driver);
+
+ if (!retval)
+ pr_info("%s: registered new device driver %s\n",
+ usbcore_name, new_udriver->name);
+ else
+ printk(KERN_ERR "%s: error %d registering device "
+ " driver %s\n",
+ usbcore_name, retval, new_udriver->name);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_register_device_driver);
+
+/**
+ * usb_deregister_device_driver - unregister a USB device (not interface) driver
+ * @udriver: USB operations of the device driver to unregister
+ * Context: must be able to sleep
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+ */
+void usb_deregister_device_driver(struct usb_device_driver *udriver)
+{
+ pr_info("%s: deregistering device driver %s\n",
+ usbcore_name, udriver->name);
+
+ driver_unregister(&udriver->drvwrap.driver);
+}
+EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
+
+/**
+ * usb_register_driver - register a USB interface driver
+ * @new_driver: USB operations for the interface driver
+ * @owner: module owner of this driver.
+ * @mod_name: module name string
+ *
+ * Registers a USB interface driver with the USB core. The list of
+ * unattached interfaces will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized interfaces.
+ *
+ * Return: A negative error code on failure and 0 on success.
+ *
+ * NOTE: if you want your driver to use the USB major number, you must call
+ * usb_register_dev() to enable that functionality. This function no longer
+ * takes care of that.
+ */
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ const char *mod_name)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ new_driver->drvwrap.for_devices = 0;
+ new_driver->drvwrap.driver.name = new_driver->name;
+ new_driver->drvwrap.driver.bus = &usb_bus_type;
+ new_driver->drvwrap.driver.probe = usb_probe_interface;
+ new_driver->drvwrap.driver.remove = usb_unbind_interface;
+ new_driver->drvwrap.driver.owner = owner;
+ new_driver->drvwrap.driver.mod_name = mod_name;
+ spin_lock_init(&new_driver->dynids.lock);
+ INIT_LIST_HEAD(&new_driver->dynids.list);
+
+ retval = driver_register(&new_driver->drvwrap.driver);
+ if (retval)
+ goto out;
+
+ retval = usb_create_newid_files(new_driver);
+ if (retval)
+ goto out_newid;
+
+ pr_info("%s: registered new interface driver %s\n",
+ usbcore_name, new_driver->name);
+
+out:
+ return retval;
+
+out_newid:
+ driver_unregister(&new_driver->drvwrap.driver);
+
+ printk(KERN_ERR "%s: error %d registering interface "
+ " driver %s\n",
+ usbcore_name, retval, new_driver->name);
+ goto out;
+}
+EXPORT_SYMBOL_GPL(usb_register_driver);
+
+/**
+ * usb_deregister - unregister a USB interface driver
+ * @driver: USB operations of the interface driver to unregister
+ * Context: must be able to sleep
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+ *
+ * NOTE: If you called usb_register_dev(), you still need to call
+ * usb_deregister_dev() to clean up your driver's allocated minor numbers,
+ * this * call will no longer do it for you.
+ */
+void usb_deregister(struct usb_driver *driver)
+{
+ pr_info("%s: deregistering interface driver %s\n",
+ usbcore_name, driver->name);
+
+ usb_remove_newid_files(driver);
+ driver_unregister(&driver->drvwrap.driver);
+ usb_free_dynids(driver);
+}
+EXPORT_SYMBOL_GPL(usb_deregister);
+
+/* Forced unbinding of a USB interface driver, either because
+ * it doesn't support pre_reset/post_reset/reset_resume or
+ * because it doesn't support suspend/resume.
+ *
+ * The caller must hold @intf's device's lock, but not @intf's lock.
+ */
+void usb_forced_unbind_intf(struct usb_interface *intf)
+{
+ struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+ dev_dbg(&intf->dev, "forced unbind\n");
+ usb_driver_release_interface(driver, intf);
+
+ /* Mark the interface for later rebinding */
+ intf->needs_binding = 1;
+}
+
+/*
+ * Unbind drivers for @udev's marked interfaces. These interfaces have
+ * the needs_binding flag set, for example by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_marked_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+ if (intf->dev.driver && intf->needs_binding)
+ usb_forced_unbind_intf(intf);
+ }
+ }
+}
+
+/* Delayed forced unbinding of a USB interface driver and scan
+ * for rebinding.
+ *
+ * The caller must hold @intf's device's lock, but not @intf's lock.
+ *
+ * Note: Rebinds will be skipped if a system sleep transition is in
+ * progress and the PM "complete" callback hasn't occurred yet.
+ */
+static void usb_rebind_intf(struct usb_interface *intf)
+{
+ int rc;
+
+ /* Delayed unbind of an existing driver */
+ if (intf->dev.driver)
+ usb_forced_unbind_intf(intf);
+
+ /* Try to rebind the interface */
+ if (!intf->dev.power.is_prepared) {
+ intf->needs_binding = 0;
+ rc = device_attach(&intf->dev);
+ if (rc < 0 && rc != -EPROBE_DEFER)
+ dev_warn(&intf->dev, "rebind failed: %d\n", rc);
+ }
+}
+
+/*
+ * Rebind drivers to @udev's marked interfaces. These interfaces have
+ * the needs_binding flag set.
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void rebind_marked_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+ if (intf->needs_binding)
+ usb_rebind_intf(intf);
+ }
+ }
+}
+
+/*
+ * Unbind all of @udev's marked interfaces and then rebind all of them.
+ * This ordering is necessary because some drivers claim several interfaces
+ * when they are first probed.
+ *
+ * The caller must hold @udev's device lock.
+ */
+void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev)
+{
+ unbind_marked_interfaces(udev);
+ rebind_marked_interfaces(udev);
+}
+
+#ifdef CONFIG_PM
+
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
+ * There is no check for reset_resume here because it can be determined
+ * only during resume whether reset_resume is needed.
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+ struct usb_driver *drv;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+
+ if (intf->dev.driver) {
+ drv = to_usb_driver(intf->dev.driver);
+ if (!drv->suspend || !drv->resume)
+ usb_forced_unbind_intf(intf);
+ }
+ }
+ }
+}
+
+static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED)
+ goto done;
+
+ /* For devices that don't have a driver, we do a generic suspend. */
+ if (udev->dev.driver)
+ udriver = to_usb_device_driver(udev->dev.driver);
+ else {
+ udev->do_remote_wakeup = 0;
+ udriver = &usb_generic_driver;
+ }
+ status = udriver->suspend(udev, msg);
+
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ return status;
+}
+
+static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (udev->dev.driver == NULL) {
+ status = -ENOTCONN;
+ goto done;
+ }
+
+ /* Non-root devices on a full/low-speed bus must wait for their
+ * companion high-speed root hub, in case a handoff is needed.
+ */
+ if (!PMSG_IS_AUTO(msg) && udev->parent && udev->bus->hs_companion)
+ device_pm_wait_for_dev(&udev->dev,
+ &udev->bus->hs_companion->root_hub->dev);
+
+ if (udev->quirks & USB_QUIRK_RESET_RESUME)
+ udev->reset_resume = 1;
+
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->resume(udev, msg);
+
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ return status;
+}
+
+static int usb_suspend_interface(struct usb_device *udev,
+ struct usb_interface *intf, pm_message_t msg)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ intf->condition == USB_INTERFACE_UNBOUND)
+ goto done;
+ driver = to_usb_driver(intf->dev.driver);
+
+ /* at this time we know the driver supports suspend */
+ status = driver->suspend(intf, msg);
+ if (status && !PMSG_IS_AUTO(msg))
+ dev_err(&intf->dev, "suspend error %d\n", status);
+
+ done:
+ dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
+ return status;
+}
+
+static int usb_resume_interface(struct usb_device *udev,
+ struct usb_interface *intf, pm_message_t msg, int reset_resume)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED)
+ goto done;
+
+ /* Don't let autoresume interfere with unbinding */
+ if (intf->condition == USB_INTERFACE_UNBINDING)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (intf->condition == USB_INTERFACE_UNBOUND) {
+
+ /* Carry out a deferred switch to altsetting 0 */
+ if (intf->needs_altsetting0 && !intf->dev.power.is_prepared) {
+ usb_set_interface(udev, intf->altsetting[0].
+ desc.bInterfaceNumber, 0);
+ intf->needs_altsetting0 = 0;
+ }
+ goto done;
+ }
+
+ /* Don't resume if the interface is marked for rebinding */
+ if (intf->needs_binding)
+ goto done;
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (reset_resume) {
+ if (driver->reset_resume) {
+ status = driver->reset_resume(intf);
+ if (status)
+ dev_err(&intf->dev, "%s error %d\n",
+ "reset_resume", status);
+ } else {
+ intf->needs_binding = 1;
+ dev_dbg(&intf->dev, "no reset_resume for driver %s?\n",
+ driver->name);
+ }
+ } else {
+ status = driver->resume(intf);
+ if (status)
+ dev_err(&intf->dev, "resume error %d\n", status);
+ }
+
+done:
+ dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
+
+ /* Later we will unbind the driver and/or reprobe, if necessary */
+ return status;
+}
+
+/**
+ * usb_suspend_both - suspend a USB device and its interfaces
+ * @udev: the usb_device to suspend
+ * @msg: Power Management message describing this state transition
+ *
+ * This is the central routine for suspending USB devices. It calls the
+ * suspend methods for all the interface drivers in @udev and then calls
+ * the suspend method for @udev itself. When the routine is called in
+ * autosuspend, if an error occurs at any stage, all the interfaces
+ * which were suspended are resumed so that they remain in the same
+ * state as the device, but when called from system sleep, all error
+ * from suspend methods of interfaces and the non-root-hub device itself
+ * are simply ignored, so all suspended interfaces are only resumed
+ * to the device's state when @udev is root-hub and its suspend method
+ * returns failure.
+ *
+ * Autosuspend requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other suspend calls will hold the lock. Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle suspend calls arriving at
+ * unpredictable times.
+ *
+ * This routine can run only in process context.
+ *
+ * Return: 0 if the suspend succeeded.
+ */
+static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
+{
+ int status = 0;
+ int i = 0, n = 0;
+ struct usb_interface *intf;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED)
+ goto done;
+
+ /* Suspend all the interfaces and then udev itself */
+ if (udev->actconfig) {
+ n = udev->actconfig->desc.bNumInterfaces;
+ for (i = n - 1; i >= 0; --i) {
+ intf = udev->actconfig->interface[i];
+ status = usb_suspend_interface(udev, intf, msg);
+
+ /* Ignore errors during system sleep transitions */
+ if (!PMSG_IS_AUTO(msg))
+ status = 0;
+ if (status != 0)
+ break;
+ }
+ }
+ if (status == 0) {
+ status = usb_suspend_device(udev, msg);
+
+ /*
+ * Ignore errors from non-root-hub devices during
+ * system sleep transitions. For the most part,
+ * these devices should go to low power anyway when
+ * the entire bus is suspended.
+ */
+ if (udev->parent && !PMSG_IS_AUTO(msg))
+ status = 0;
+
+ /*
+ * If the device is inaccessible, don't try to resume
+ * suspended interfaces and just return the error.
+ */
+ if (status && status != -EBUSY) {
+ int err;
+ u16 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",
+ status);
+ goto done;
+ }
+ }
+ }
+
+ /* If the suspend failed, resume interfaces that did get suspended */
+ if (status != 0) {
+ if (udev->actconfig) {
+ msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
+ while (++i < n) {
+ intf = udev->actconfig->interface[i];
+ usb_resume_interface(udev, intf, msg, 0);
+ }
+ }
+
+ /* If the suspend succeeded then prevent any more URB submissions
+ * and flush any outstanding URBs.
+ */
+ } else {
+ udev->can_submit = 0;
+ for (i = 0; i < 16; ++i) {
+ usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+ usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+ }
+ }
+
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ return status;
+}
+
+/**
+ * usb_resume_both - resume a USB device and its interfaces
+ * @udev: the usb_device to resume
+ * @msg: Power Management message describing this state transition
+ *
+ * This is the central routine for resuming USB devices. It calls the
+ * the resume method for @udev and then calls the resume methods for all
+ * the interface drivers in @udev.
+ *
+ * Autoresume requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other resume calls will hold the lock. Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle resume calls arriving at
+ * unpredictable times.
+ *
+ * This routine can run only in process context.
+ *
+ * Return: 0 on success.
+ */
+static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
+{
+ int status = 0;
+ int i;
+ struct usb_interface *intf;
+
+ if (udev->state == USB_STATE_NOTATTACHED) {
+ status = -ENODEV;
+ goto done;
+ }
+ udev->can_submit = 1;
+
+ /* Resume the device */
+ if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume)
+ status = usb_resume_device(udev, msg);
+
+ /* Resume the interfaces */
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ usb_resume_interface(udev, intf, msg,
+ udev->reset_resume);
+ }
+ }
+ usb_mark_last_busy(udev);
+
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ if (!status)
+ udev->reset_resume = 0;
+ return status;
+}
+
+static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
+{
+ int w;
+
+ /* Remote wakeup is needed only when we actually go to sleep.
+ * For things like FREEZE and QUIESCE, if the device is already
+ * autosuspended then its current wakeup setting is okay.
+ */
+ if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
+ if (udev->state != USB_STATE_SUSPENDED)
+ udev->do_remote_wakeup = 0;
+ return;
+ }
+
+ /* Enable remote wakeup if it is allowed, even if no interface drivers
+ * actually want it.
+ */
+ w = device_may_wakeup(&udev->dev);
+
+ /* If the device is autosuspended with the wrong wakeup setting,
+ * autoresume now so the setting can be changed.
+ */
+ if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup)
+ pm_runtime_resume(&udev->dev);
+ udev->do_remote_wakeup = w;
+}
+
+/* The device lock is held by the PM core */
+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);
+
+ /* From now on we are sure all drivers support suspend/resume
+ * but not necessarily reset_resume()
+ * so we may still need to unbind and rebind upon resume
+ */
+ choose_wakeup(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 */
+int usb_resume_complete(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ /* For PM complete calls, all we do is rebind interfaces
+ * whose needs_binding flag is set
+ */
+ if (udev->state != USB_STATE_NOTATTACHED)
+ rebind_marked_interfaces(udev);
+ return 0;
+}
+
+/* The device lock is held by the PM core */
+int usb_resume(struct device *dev, pm_message_t msg)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
+
+ /* For all calls, take the device back to full power and
+ * tell the PM core in case it was autosuspended previously.
+ * Unbind the interfaces that will need rebinding later,
+ * because they fail to support reset_resume.
+ * (This can't be done in usb_resume_interface()
+ * above because it doesn't own the right set of locks.)
+ */
+ status = usb_resume_both(udev, msg);
+ if (status == 0) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ unbind_marked_interfaces(udev);
+ }
+
+ /* Avoid PM error messages for devices disconnected while suspended
+ * as we'll display regular disconnect messages just a bit later.
+ */
+ if (status == -ENODEV || status == -ESHUTDOWN)
+ status = 0;
+ return status;
+}
+
+/**
+ * usb_enable_autosuspend - allow a USB device to be autosuspended
+ * @udev: the USB device which may be autosuspended
+ *
+ * This routine allows @udev to be autosuspended. An autosuspend won't
+ * take place until the autosuspend_delay has elapsed and all the other
+ * necessary conditions are satisfied.
+ *
+ * The caller must hold @udev's device lock.
+ */
+void usb_enable_autosuspend(struct usb_device *udev)
+{
+ pm_runtime_allow(&udev->dev);
+}
+EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
+
+/**
+ * usb_disable_autosuspend - prevent a USB device from being autosuspended
+ * @udev: the USB device which may not be autosuspended
+ *
+ * This routine prevents @udev from being autosuspended and wakes it up
+ * if it is already autosuspended.
+ *
+ * The caller must hold @udev's device lock.
+ */
+void usb_disable_autosuspend(struct usb_device *udev)
+{
+ pm_runtime_forbid(&udev->dev);
+}
+EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
+
+/**
+ * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ *
+ * This routine should be called when a core subsystem is finished using
+ * @udev and wants to allow it to autosuspend. Examples would be when
+ * @udev's device file in usbfs is closed or after a configuration change.
+ *
+ * @udev's usage counter is decremented; if it drops to 0 and all the
+ * interfaces are inactive then a delayed autosuspend will be attempted.
+ * The attempt may fail (see autosuspend_check()).
+ *
+ * The caller must hold @udev's device lock.
+ *
+ * This routine can run only in process context.
+ */
+void usb_autosuspend_device(struct usb_device *udev)
+{
+ int status;
+
+ usb_mark_last_busy(udev);
+ status = pm_runtime_put_sync_autosuspend(&udev->dev);
+ dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&udev->dev.power.usage_count),
+ status);
+}
+
+/**
+ * usb_autoresume_device - immediately autoresume a USB device and its interfaces
+ * @udev: the usb_device to autoresume
+ *
+ * This routine should be called when a core subsystem wants to use @udev
+ * and needs to guarantee that it is not suspended. No autosuspend will
+ * occur until usb_autosuspend_device() is called. (Note that this will
+ * not prevent suspend events originating in the PM core.) Examples would
+ * be when @udev's device file in usbfs is opened or when a remote-wakeup
+ * request is received.
+ *
+ * @udev's usage counter is incremented to prevent subsequent autosuspends.
+ * However if the autoresume fails then the usage counter is re-decremented.
+ *
+ * The caller must hold @udev's device lock.
+ *
+ * This routine can run only in process context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
+ */
+int usb_autoresume_device(struct usb_device *udev)
+{
+ int status;
+
+ status = pm_runtime_get_sync(&udev->dev);
+ if (status < 0)
+ pm_runtime_put_sync(&udev->dev);
+ dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&udev->dev.power.usage_count),
+ status);
+ if (status > 0)
+ status = 0;
+ return status;
+}
+
+/**
+ * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine should be called by an interface driver when it is
+ * finished using @intf and wants to allow it to autosuspend. A typical
+ * example would be a character-device driver when its device file is
+ * closed.
+ *
+ * The routine decrements @intf's usage counter. When the counter reaches
+ * 0, a delayed autosuspend request for @intf's device is attempted. The
+ * attempt may fail (see autosuspend_check()).
+ *
+ * This routine can run only in process context.
+ */
+void usb_autopm_put_interface(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
+
+ usb_mark_last_busy(udev);
+ status = pm_runtime_put_sync(&intf->dev);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
+
+/**
+ * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine does much the same thing as usb_autopm_put_interface():
+ * It decrements @intf's usage counter and schedules a delayed
+ * autosuspend request if the counter is <= 0. The difference is that it
+ * does not perform any synchronization; callers should hold a private
+ * lock and handle all synchronization issues themselves.
+ *
+ * Typically a driver would call this routine during an URB's completion
+ * handler, if no more URBs were pending.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_async(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
+
+ usb_mark_last_busy(udev);
+ status = pm_runtime_put(&intf->dev);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
+
+/**
+ * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine decrements @intf's usage counter but does not carry out an
+ * autosuspend.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_mark_last_busy(udev);
+ pm_runtime_put_noidle(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
+
+/**
+ * usb_autopm_get_interface - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine should be called by an interface driver when it wants to
+ * use @intf and needs to guarantee that it is not suspended. In addition,
+ * the routine prevents @intf from being autosuspended subsequently. (Note
+ * that this will not prevent suspend events originating in the PM core.)
+ * This prevention will persist until usb_autopm_put_interface() is called
+ * or @intf is unbound. A typical example would be a character-device
+ * driver when its device file is opened.
+ *
+ * @intf's usage counter is incremented to prevent subsequent autosuspends.
+ * However if the autoresume fails then the counter is re-decremented.
+ *
+ * This routine can run only in process context.
+ *
+ * Return: 0 on success.
+ */
+int usb_autopm_get_interface(struct usb_interface *intf)
+{
+ int status;
+
+ status = pm_runtime_get_sync(&intf->dev);
+ if (status < 0)
+ pm_runtime_put_sync(&intf->dev);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+ if (status > 0)
+ status = 0;
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
+
+/**
+ * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine does much the same thing as
+ * usb_autopm_get_interface(): It increments @intf's usage counter and
+ * queues an autoresume request if the device is suspended. The
+ * differences are that it does not perform any synchronization (callers
+ * should hold a private lock and handle all synchronization issues
+ * themselves), and it does not autoresume the device directly (it only
+ * queues a request). After a successful call, the device may not yet be
+ * resumed.
+ *
+ * This routine can run in atomic context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
+ */
+int usb_autopm_get_interface_async(struct usb_interface *intf)
+{
+ int status;
+
+ status = pm_runtime_get(&intf->dev);
+ if (status < 0 && status != -EINPROGRESS)
+ pm_runtime_put_noidle(&intf->dev);
+ dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+ __func__, atomic_read(&intf->dev.power.usage_count),
+ status);
+ if (status > 0 || status == -EINPROGRESS)
+ status = 0;
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
+
+/**
+ * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine increments @intf's usage counter but does not carry out an
+ * autoresume.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_mark_last_busy(udev);
+ pm_runtime_get_noresume(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
+
+/* Internal routine to check whether we may autosuspend a device. */
+static int autosuspend_check(struct usb_device *udev)
+{
+ int w, i;
+ struct usb_interface *intf;
+
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+
+ /* Fail if autosuspend is disabled, or any interfaces are in use, or
+ * any interface drivers require remote wakeup but it isn't available.
+ */
+ w = 0;
+ if (udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+
+ /* We don't need to check interfaces that are
+ * disabled for runtime PM. Either they are unbound
+ * or else their drivers don't support autosuspend
+ * and so they are permanently active.
+ */
+ if (intf->dev.power.disable_depth)
+ continue;
+ if (atomic_read(&intf->dev.power.usage_count) > 0)
+ return -EBUSY;
+ w |= intf->needs_remote_wakeup;
+
+ /* Don't allow autosuspend if the device will need
+ * a reset-resume and any of its interface drivers
+ * doesn't include support or needs remote wakeup.
+ */
+ if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+ struct usb_driver *driver;
+
+ driver = to_usb_driver(intf->dev.driver);
+ if (!driver->reset_resume ||
+ intf->needs_remote_wakeup)
+ return -EOPNOTSUPP;
+ }
+ }
+ }
+ if (w && !device_can_wakeup(&udev->dev)) {
+ dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
+ return -EOPNOTSUPP;
+ }
+
+ /*
+ * If the device is a direct child of the root hub and the HCD
+ * doesn't handle wakeup requests, don't allow autosuspend when
+ * wakeup is needed.
+ */
+ if (w && udev->parent == udev->bus->root_hub &&
+ bus_to_hcd(udev->bus)->cant_recv_wakeups) {
+ dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
+ return -EOPNOTSUPP;
+ }
+
+ udev->do_remote_wakeup = w;
+ return 0;
+}
+
+int usb_runtime_suspend(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
+
+ /* A USB device can be suspended if it passes the various autosuspend
+ * checks. Runtime suspend for a USB device means suspending all the
+ * interfaces and then the device itself.
+ */
+ if (autosuspend_check(udev) != 0)
+ return -EAGAIN;
+
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+
+ /* Allow a retry if autosuspend failed temporarily */
+ if (status == -EAGAIN || status == -EBUSY)
+ usb_mark_last_busy(udev);
+
+ /*
+ * The PM core reacts badly unless the return code is 0,
+ * -EAGAIN, or -EBUSY, so always return -EBUSY on an error
+ * (except for root hubs, because they don't suspend through
+ * an upstream port like other USB devices).
+ */
+ if (status != 0 && udev->parent)
+ return -EBUSY;
+ return status;
+}
+
+int usb_runtime_resume(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
+
+ /* Runtime resume for a USB device means resuming both the device
+ * and all its interfaces.
+ */
+ status = usb_resume_both(udev, PMSG_AUTO_RESUME);
+ return status;
+}
+
+int usb_runtime_idle(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ /* An idle USB device can be suspended if it passes the various
+ * autosuspend checks.
+ */
+ if (autosuspend_check(udev) == 0)
+ pm_runtime_autosuspend(dev);
+ /* Tell the core not to suspend it, though. */
+ return -EBUSY;
+}
+
+static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret = -EPERM;
+
+ if (hcd->driver->set_usb2_hw_lpm) {
+ ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
+ if (!ret)
+ udev->usb2_hw_lpm_enabled = enable;
+ }
+
+ return ret;
+}
+
+int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
+{
+ if (!udev->usb2_hw_lpm_capable ||
+ !udev->usb2_hw_lpm_allowed ||
+ udev->usb2_hw_lpm_enabled)
+ return 0;
+
+ return usb_set_usb2_hardware_lpm(udev, 1);
+}
+
+int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
+{
+ if (!udev->usb2_hw_lpm_enabled)
+ return 0;
+
+ return usb_set_usb2_hardware_lpm(udev, 0);
+}
+
+#endif /* CONFIG_PM */
+
+struct bus_type usb_bus_type = {
+ .name = "usb",
+ .match = usb_device_match,
+ .uevent = usb_uevent,
+ .need_parent_lock = true,
+};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
new file mode 100644
index 000000000..1c2c04079
--- /dev/null
+++ b/drivers/usb/core/endpoint.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/core/endpoint.c
+ *
+ * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
+ * (C) Copyright 2002,2004 IBM Corp.
+ * (C) Copyright 2006 Novell Inc.
+ *
+ * Released under the GPLv2 only.
+ *
+ * Endpoint sysfs stuff
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "usb.h"
+
+struct ep_device {
+ struct usb_endpoint_descriptor *desc;
+ struct usb_device *udev;
+ struct device dev;
+};
+#define to_ep_device(_dev) \
+ container_of(_dev, struct ep_device, dev)
+
+struct ep_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct usb_device *,
+ struct usb_endpoint_descriptor *, char *);
+};
+#define to_ep_attribute(_attr) \
+ container_of(_attr, struct ep_attribute, attr)
+
+#define usb_ep_attr(field, format_string) \
+static ssize_t field##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ep_device *ep = to_ep_device(dev); \
+ return sprintf(buf, format_string, ep->desc->field); \
+} \
+static DEVICE_ATTR_RO(field)
+
+usb_ep_attr(bLength, "%02x\n");
+usb_ep_attr(bEndpointAddress, "%02x\n");
+usb_ep_attr(bmAttributes, "%02x\n");
+usb_ep_attr(bInterval, "%02x\n");
+
+static ssize_t wMaxPacketSize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ep_device *ep = to_ep_device(dev);
+ return sprintf(buf, "%04x\n", usb_endpoint_maxp(ep->desc));
+}
+static DEVICE_ATTR_RO(wMaxPacketSize);
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ep_device *ep = to_ep_device(dev);
+ char *type = "unknown";
+
+ switch (usb_endpoint_type(ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "Control";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ type = "Isoc";
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = "Bulk";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = "Interrupt";
+ break;
+ }
+ return sprintf(buf, "%s\n", type);
+}
+static DEVICE_ATTR_RO(type);
+
+static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ep_device *ep = to_ep_device(dev);
+ char unit;
+ unsigned interval = 0;
+ unsigned in;
+
+ in = (ep->desc->bEndpointAddress & USB_DIR_IN);
+
+ switch (usb_endpoint_type(ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ if (ep->udev->speed == USB_SPEED_HIGH)
+ /* uframes per NAK */
+ interval = ep->desc->bInterval;
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ interval = 1 << (ep->desc->bInterval - 1);
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ if (ep->udev->speed == USB_SPEED_HIGH && !in)
+ /* uframes per NAK */
+ interval = ep->desc->bInterval;
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ if (ep->udev->speed == USB_SPEED_HIGH)
+ interval = 1 << (ep->desc->bInterval - 1);
+ else
+ interval = ep->desc->bInterval;
+ break;
+ }
+ interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
+ if (interval % 1000)
+ unit = 'u';
+ else {
+ unit = 'm';
+ interval /= 1000;
+ }
+
+ return sprintf(buf, "%d%cs\n", interval, unit);
+}
+static DEVICE_ATTR_RO(interval);
+
+static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ep_device *ep = to_ep_device(dev);
+ char *direction;
+
+ if (usb_endpoint_xfer_control(ep->desc))
+ direction = "both";
+ else if (usb_endpoint_dir_in(ep->desc))
+ direction = "in";
+ else
+ direction = "out";
+ return sprintf(buf, "%s\n", direction);
+}
+static DEVICE_ATTR_RO(direction);
+
+static struct attribute *ep_dev_attrs[] = {
+ &dev_attr_bLength.attr,
+ &dev_attr_bEndpointAddress.attr,
+ &dev_attr_bmAttributes.attr,
+ &dev_attr_bInterval.attr,
+ &dev_attr_wMaxPacketSize.attr,
+ &dev_attr_interval.attr,
+ &dev_attr_type.attr,
+ &dev_attr_direction.attr,
+ NULL,
+};
+static struct attribute_group ep_dev_attr_grp = {
+ .attrs = ep_dev_attrs,
+};
+static const struct attribute_group *ep_dev_groups[] = {
+ &ep_dev_attr_grp,
+ NULL
+};
+
+static void ep_device_release(struct device *dev)
+{
+ struct ep_device *ep_dev = to_ep_device(dev);
+
+ kfree(ep_dev);
+}
+
+struct device_type usb_ep_device_type = {
+ .name = "usb_endpoint",
+ .release = ep_device_release,
+};
+
+int usb_create_ep_devs(struct device *parent,
+ struct usb_host_endpoint *endpoint,
+ struct usb_device *udev)
+{
+ struct ep_device *ep_dev;
+ int retval;
+
+ ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
+ if (!ep_dev) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ ep_dev->desc = &endpoint->desc;
+ ep_dev->udev = udev;
+ ep_dev->dev.groups = ep_dev_groups;
+ ep_dev->dev.type = &usb_ep_device_type;
+ ep_dev->dev.parent = parent;
+ dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
+
+ retval = device_register(&ep_dev->dev);
+ if (retval)
+ goto error_register;
+
+ device_enable_async_suspend(&ep_dev->dev);
+ endpoint->ep_dev = ep_dev;
+ return retval;
+
+error_register:
+ put_device(&ep_dev->dev);
+exit:
+ return retval;
+}
+
+void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
+{
+ struct ep_device *ep_dev = endpoint->ep_dev;
+
+ if (ep_dev) {
+ device_unregister(&ep_dev->dev);
+ endpoint->ep_dev = NULL;
+ }
+}
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
new file mode 100644
index 000000000..558890ada
--- /dev/null
+++ b/drivers/usb/core/file.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/core/file.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
+ * more docs, etc)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+
+#include "usb.h"
+
+#define MAX_USB_MINORS 256
+static const struct file_operations *usb_minors[MAX_USB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
+static DEFINE_MUTEX(init_usb_class_mutex);
+
+static int usb_open(struct inode *inode, struct file *file)
+{
+ int err = -ENODEV;
+ const struct file_operations *new_fops;
+
+ down_read(&minor_rwsem);
+ new_fops = fops_get(usb_minors[iminor(inode)]);
+
+ if (!new_fops)
+ goto done;
+
+ replace_fops(file, new_fops);
+ /* Curiouser and curiouser... NULL ->open() as "no device" ? */
+ if (file->f_op->open)
+ err = file->f_op->open(inode, file);
+ done:
+ up_read(&minor_rwsem);
+ return err;
+}
+
+static const struct file_operations usb_fops = {
+ .owner = THIS_MODULE,
+ .open = usb_open,
+ .llseek = noop_llseek,
+};
+
+static struct usb_class {
+ struct kref kref;
+ struct class *class;
+} *usb_class;
+
+static char *usb_devnode(struct device *dev, umode_t *mode)
+{
+ struct usb_class_driver *drv;
+
+ drv = dev_get_drvdata(dev);
+ if (!drv || !drv->devnode)
+ return NULL;
+ return drv->devnode(dev, mode);
+}
+
+static int init_usb_class(void)
+{
+ int result = 0;
+
+ if (usb_class != NULL) {
+ kref_get(&usb_class->kref);
+ goto exit;
+ }
+
+ usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL);
+ if (!usb_class) {
+ result = -ENOMEM;
+ goto exit;
+ }
+
+ kref_init(&usb_class->kref);
+ usb_class->class = class_create(THIS_MODULE, "usbmisc");
+ if (IS_ERR(usb_class->class)) {
+ result = PTR_ERR(usb_class->class);
+ printk(KERN_ERR "class_create failed for usb devices\n");
+ kfree(usb_class);
+ usb_class = NULL;
+ goto exit;
+ }
+ usb_class->class->devnode = usb_devnode;
+
+exit:
+ return result;
+}
+
+static void release_usb_class(struct kref *kref)
+{
+ /* Ok, we cheat as we know we only have one usb_class */
+ class_destroy(usb_class->class);
+ kfree(usb_class);
+ usb_class = NULL;
+}
+
+static void destroy_usb_class(void)
+{
+ mutex_lock(&init_usb_class_mutex);
+ kref_put(&usb_class->kref, release_usb_class);
+ mutex_unlock(&init_usb_class_mutex);
+}
+
+int usb_major_init(void)
+{
+ int error;
+
+ error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
+ if (error)
+ printk(KERN_ERR "Unable to get major %d for usb devices\n",
+ USB_MAJOR);
+
+ return error;
+}
+
+void usb_major_cleanup(void)
+{
+ unregister_chrdev(USB_MAJOR, "usb");
+}
+
+/**
+ * usb_register_dev - register a USB device, and ask for a minor number
+ * @intf: pointer to the usb_interface that is being registered
+ * @class_driver: pointer to the usb_class_driver for this device
+ *
+ * This should be called by all USB drivers that use the USB major number.
+ * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
+ * dynamically allocated out of the list of available ones. If it is not
+ * enabled, the minor number will be based on the next available free minor,
+ * starting at the class_driver->minor_base.
+ *
+ * This function also creates a usb class device in the sysfs tree.
+ *
+ * usb_deregister_dev() must be called when the driver is done with
+ * the minor numbers given out by this function.
+ *
+ * Return: -EINVAL if something bad happens with trying to register a
+ * device, and 0 on success.
+ */
+int usb_register_dev(struct usb_interface *intf,
+ struct usb_class_driver *class_driver)
+{
+ int retval;
+ int minor_base = class_driver->minor_base;
+ int minor;
+ char name[20];
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+ /*
+ * We don't care what the device tries to start at, we want to start
+ * at zero to pack the devices into the smallest available space with
+ * no holes in the minor range.
+ */
+ minor_base = 0;
+#endif
+
+ if (class_driver->fops == NULL)
+ return -EINVAL;
+ if (intf->minor >= 0)
+ return -EADDRINUSE;
+
+ mutex_lock(&init_usb_class_mutex);
+ retval = init_usb_class();
+ mutex_unlock(&init_usb_class_mutex);
+
+ if (retval)
+ return retval;
+
+ dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
+
+ down_write(&minor_rwsem);
+ for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
+ if (usb_minors[minor])
+ continue;
+
+ usb_minors[minor] = class_driver->fops;
+ intf->minor = minor;
+ break;
+ }
+ if (intf->minor < 0) {
+ up_write(&minor_rwsem);
+ return -EXFULL;
+ }
+
+ /* create a usb class device for this usb interface */
+ snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
+ intf->usb_dev = device_create(usb_class->class, &intf->dev,
+ MKDEV(USB_MAJOR, minor), class_driver,
+ "%s", kbasename(name));
+ if (IS_ERR(intf->usb_dev)) {
+ usb_minors[minor] = NULL;
+ intf->minor = -1;
+ retval = PTR_ERR(intf->usb_dev);
+ }
+ up_write(&minor_rwsem);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_register_dev);
+
+/**
+ * usb_deregister_dev - deregister a USB device's dynamic minor.
+ * @intf: pointer to the usb_interface that is being deregistered
+ * @class_driver: pointer to the usb_class_driver for this device
+ *
+ * Used in conjunction with usb_register_dev(). This function is called
+ * when the USB driver is finished with the minor numbers gotten from a
+ * call to usb_register_dev() (usually when the device is disconnected
+ * from the system.)
+ *
+ * This function also removes the usb class device from the sysfs tree.
+ *
+ * This should be called by all drivers that use the USB major number.
+ */
+void usb_deregister_dev(struct usb_interface *intf,
+ struct usb_class_driver *class_driver)
+{
+ if (intf->minor == -1)
+ return;
+
+ dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
+ device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+
+ down_write(&minor_rwsem);
+ usb_minors[intf->minor] = NULL;
+ up_write(&minor_rwsem);
+
+ intf->usb_dev = NULL;
+ intf->minor = -1;
+ destroy_usb_class();
+}
+EXPORT_SYMBOL_GPL(usb_deregister_dev);
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
new file mode 100644
index 000000000..bc8242bc4
--- /dev/null
+++ b/drivers/usb/core/generic.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/generic.c - generic driver for USB devices (not interfaces)
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * based on drivers/usb/usb.c which had the following copyrights:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2004
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+static inline const char *plural(int n)
+{
+ return (n == 1 ? "" : "s");
+}
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
+int usb_choose_configuration(struct usb_device *udev)
+{
+ int i;
+ int num_configs;
+ int insufficient_power = 0;
+ struct usb_host_config *c, *best;
+
+ if (usb_device_is_owned(udev))
+ return 0;
+
+ best = NULL;
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ /* It's possible that a config has no interfaces! */
+ if (c->desc.bNumInterfaces > 0)
+ desc = &c->intf_cache[0]->altsetting->desc;
+
+ /*
+ * HP's USB bus-powered keyboard has only one configuration
+ * and it claims to be self-powered; other devices may have
+ * similar errors in their descriptors. If the next test
+ * were allowed to execute, such configurations would always
+ * be rejected and the devices would not work as expected.
+ * In the meantime, we run the risk of selecting a config
+ * that requires external power at a time when that power
+ * isn't available. It seems to be the lesser of two evils.
+ *
+ * Bugzilla #6448 reports a device that appears to crash
+ * when it receives a GET_DEVICE_STATUS request! We don't
+ * have any other way to tell whether a device is self-powered,
+ * but since we don't use that information anywhere but here,
+ * the call has been removed.
+ *
+ * Maybe the GET_DEVICE_STATUS call and the test below can
+ * be reinstated when device firmwares become more reliable.
+ * Don't hold your breath.
+ */
+#if 0
+ /* Rule out self-powered configs for a bus-powered device */
+ if (bus_powered && (c->desc.bmAttributes &
+ USB_CONFIG_ATT_SELFPOWER))
+ continue;
+#endif
+
+ /*
+ * The next test may not be as effective as it should be.
+ * Some hubs have errors in their descriptor, claiming
+ * to be self-powered when they are really bus-powered.
+ * We will overestimate the amount of current such hubs
+ * make available for each port.
+ *
+ * This is a fairly benign sort of failure. It won't
+ * cause us to reject configurations that we should have
+ * accepted.
+ */
+
+ /* Rule out configs that draw too much bus current */
+ if (usb_get_max_power(udev, c) > udev->bus_mA) {
+ insufficient_power++;
+ continue;
+ }
+
+ /* When the first config's first interface is one of Microsoft's
+ * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+ * this kernel has enabled the necessary host side driver.
+ * But: Don't ignore it if it's the only config.
+ */
+ if (i == 0 && num_configs > 1 && desc &&
+ (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+ continue;
+#else
+ best = c;
+#endif
+ }
+
+ /* 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
+ * than a vendor-specific driver. */
+ else if (udev->descriptor.bDeviceClass !=
+ USB_CLASS_VENDOR_SPEC &&
+ (desc && desc->bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC)) {
+ best = c;
+ break;
+ }
+
+ /* If all the remaining configs are vendor-specific,
+ * choose the first one. */
+ else if (!best)
+ best = c;
+ }
+
+ if (insufficient_power > 0)
+ dev_info(&udev->dev, "rejected %d configuration%s "
+ "due to insufficient available bus power\n",
+ insufficient_power, plural(insufficient_power));
+
+ if (best) {
+ i = best->desc.bConfigurationValue;
+ dev_dbg(&udev->dev,
+ "configuration #%d chosen from %d choice%s\n",
+ i, num_configs, plural(num_configs));
+ } else {
+ i = -1;
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
+ }
+ return i;
+}
+EXPORT_SYMBOL_GPL(usb_choose_configuration);
+
+static int generic_probe(struct usb_device *udev)
+{
+ int err, c;
+
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ if (udev->authorized == 0)
+ dev_err(&udev->dev, "Device is not authorized for usage\n");
+ else {
+ c = usb_choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err && err != -ENODEV) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ c, err);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+ }
+ /* USB device state == configured ... usable */
+ usb_notify_add_device(udev);
+
+ return 0;
+}
+
+static void generic_disconnect(struct usb_device *udev)
+{
+ usb_notify_remove_device(udev);
+
+ /* if this is only an unbind, not a physical disconnect, then
+ * unconfigure the device */
+ if (udev->actconfig)
+ usb_set_configuration(udev, -1);
+}
+
+#ifdef CONFIG_PM
+
+static int generic_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ int rc;
+
+ /* Normal USB devices suspend through their upstream port.
+ * Root hubs don't have upstream ports to suspend,
+ * so we have to shut down their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") suspend.
+ */
+ if (!udev->parent)
+ rc = hcd_bus_suspend(udev, msg);
+
+ /*
+ * Non-root USB2 devices don't need to do anything for FREEZE
+ * or PRETHAW. USB3 devices don't support global suspend and
+ * needs to be selectively suspended.
+ */
+ else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ && (udev->speed < USB_SPEED_SUPER))
+ rc = 0;
+ else
+ rc = usb_port_suspend(udev, msg);
+
+ return rc;
+}
+
+static int generic_resume(struct usb_device *udev, pm_message_t msg)
+{
+ int rc;
+
+ /* Normal USB devices resume/reset through their upstream port.
+ * Root hubs don't have upstream ports to resume or reset,
+ * so we have to start up their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") resume.
+ */
+ if (!udev->parent)
+ rc = hcd_bus_resume(udev, msg);
+ else
+ rc = usb_port_resume(udev, msg);
+ return rc;
+}
+
+#endif /* CONFIG_PM */
+
+struct usb_device_driver usb_generic_driver = {
+ .name = "usb",
+ .probe = generic_probe,
+ .disconnect = generic_disconnect,
+#ifdef CONFIG_PM
+ .suspend = generic_suspend,
+ .resume = generic_resume,
+#endif
+ .supports_autosuspend = 1,
+};
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
new file mode 100644
index 000000000..fed331d78
--- /dev/null
+++ b/drivers/usb/core/hcd-pci.c
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright David Brownell 2000-2002
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/prom.h>
+#endif
+
+#include "usb.h"
+
+
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+
+/*
+ * Coordinate handoffs between EHCI and companion controllers
+ * during EHCI probing and system resume.
+ */
+
+static DECLARE_RWSEM(companions_rwsem);
+
+#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
+#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
+#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
+
+static inline int is_ohci_or_uhci(struct pci_dev *pdev)
+{
+ return pdev->class == CL_OHCI || pdev->class == CL_UHCI;
+}
+
+typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd);
+
+/* Iterate over PCI devices in the same slot as pdev and call fn for each */
+static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
+ companion_fn fn)
+{
+ struct pci_dev *companion;
+ struct usb_hcd *companion_hcd;
+ unsigned int slot = PCI_SLOT(pdev->devfn);
+
+ /*
+ * Iterate through other PCI functions in the same slot.
+ * If the function's drvdata isn't set then it isn't bound to
+ * a USB host controller driver, so skip it.
+ */
+ companion = NULL;
+ for_each_pci_dev(companion) {
+ if (companion->bus != pdev->bus ||
+ PCI_SLOT(companion->devfn) != slot)
+ continue;
+
+ /*
+ * Companion device should be either UHCI,OHCI or EHCI host
+ * controller, otherwise skip.
+ */
+ if (companion->class != CL_UHCI && companion->class != CL_OHCI &&
+ companion->class != CL_EHCI)
+ continue;
+
+ companion_hcd = pci_get_drvdata(companion);
+ if (!companion_hcd || !companion_hcd->self.root_hub)
+ continue;
+ fn(pdev, hcd, companion, companion_hcd);
+ }
+}
+
+/*
+ * We're about to add an EHCI controller, which will unceremoniously grab
+ * all the port connections away from its companions. To prevent annoying
+ * error messages, lock the companion's root hub and gracefully unconfigure
+ * it beforehand. Leave it locked until the EHCI controller is all set.
+ */
+static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ struct usb_device *udev;
+
+ if (is_ohci_or_uhci(companion)) {
+ udev = companion_hcd->self.root_hub;
+ usb_lock_device(udev);
+ usb_set_configuration(udev, 0);
+ }
+}
+
+/*
+ * Adding the EHCI controller has either succeeded or failed. Set the
+ * companion pointer accordingly, and in either case, reconfigure and
+ * unlock the root hub.
+ */
+static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ struct usb_device *udev;
+
+ if (is_ohci_or_uhci(companion)) {
+ if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */
+ dev_dbg(&pdev->dev, "HS companion for %s\n",
+ dev_name(&companion->dev));
+ companion_hcd->self.hs_companion = &hcd->self;
+ }
+ udev = companion_hcd->self.root_hub;
+ usb_set_configuration(udev, 1);
+ usb_unlock_device(udev);
+ }
+}
+
+/*
+ * We just added a non-EHCI controller. Find the EHCI controller to
+ * which it is a companion, and store a pointer to the bus structure.
+ */
+static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) {
+ dev_dbg(&pdev->dev, "FS/LS companion for %s\n",
+ dev_name(&companion->dev));
+ hcd->self.hs_companion = &companion_hcd->self;
+ }
+}
+
+/* We are removing an EHCI controller. Clear the companions' pointers. */
+static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ if (is_ohci_or_uhci(companion))
+ companion_hcd->self.hs_companion = NULL;
+}
+
+#ifdef CONFIG_PM
+
+/* An EHCI controller must wait for its companions before resuming. */
+static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ if (is_ohci_or_uhci(companion))
+ device_pm_wait_for_dev(&pdev->dev, &companion->dev);
+}
+
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ *
+ * Return: 0 if successful.
+ */
+int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct hc_driver *driver;
+ struct usb_hcd *hcd;
+ int retval;
+ int hcd_irq = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (!id)
+ return -EINVAL;
+ driver = (struct hc_driver *)id->driver_data;
+ if (!driver)
+ return -EINVAL;
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ /*
+ * The xHCI driver has its own irq management
+ * make sure irq setup is not touched for xhci in generic hcd code
+ */
+ if ((driver->flags & HCD_MASK) < HCD_USB3) {
+ if (!dev->irq) {
+ dev_err(&dev->dev,
+ "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
+ pci_name(dev));
+ retval = -ENODEV;
+ goto disable_pci;
+ }
+ hcd_irq = dev->irq;
+ }
+
+ hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto disable_pci;
+ }
+
+ hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) &&
+ driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0;
+
+ if (driver->flags & HCD_MEMORY) {
+ /* EHCI, OHCI */
+ hcd->rsrc_start = pci_resource_start(dev, 0);
+ hcd->rsrc_len = pci_resource_len(dev, 0);
+ 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 = devm_ioremap_nocache(&dev->dev, hcd->rsrc_start,
+ hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&dev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto put_hcd;
+ }
+
+ } else {
+ /* UHCI */
+ int region;
+
+ for (region = 0; region < PCI_ROM_RESOURCE; 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 (devm_request_region(&dev->dev, hcd->rsrc_start,
+ hcd->rsrc_len, driver->description))
+ break;
+ }
+ if (region == PCI_ROM_RESOURCE) {
+ dev_dbg(&dev->dev, "no i/o regions available\n");
+ retval = -EBUSY;
+ goto put_hcd;
+ }
+ }
+
+ pci_set_master(dev);
+
+ /* Note: dev_set_drvdata must be called while holding the rwsem */
+ if (dev->class == CL_EHCI) {
+ down_write(&companions_rwsem);
+ dev_set_drvdata(&dev->dev, hcd);
+ for_each_companion(dev, hcd, ehci_pre_add);
+ retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+ if (retval != 0)
+ dev_set_drvdata(&dev->dev, NULL);
+ for_each_companion(dev, hcd, ehci_post_add);
+ up_write(&companions_rwsem);
+ } else {
+ down_read(&companions_rwsem);
+ dev_set_drvdata(&dev->dev, hcd);
+ retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+ if (retval != 0)
+ dev_set_drvdata(&dev->dev, NULL);
+ else
+ for_each_companion(dev, hcd, non_ehci_add);
+ up_read(&companions_rwsem);
+ }
+
+ if (retval != 0)
+ goto put_hcd;
+ device_wakeup_enable(hcd->self.controller);
+
+ if (pci_dev_run_wake(dev))
+ pm_runtime_put_noidle(&dev->dev);
+ return retval;
+
+put_hcd:
+ usb_put_hcd(hcd);
+disable_pci:
+ pci_disable_device(dev);
+ dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+ if (!hcd)
+ return;
+
+ if (pci_dev_run_wake(dev))
+ pm_runtime_get_noresume(&dev->dev);
+
+ /* Fake an interrupt request in order to give the driver a chance
+ * to test whether the controller hardware has been removed (e.g.,
+ * cardbus physical eject).
+ */
+ local_irq_disable();
+ usb_hcd_irq(0, hcd);
+ local_irq_enable();
+
+ /* Note: dev_set_drvdata must be called while holding the rwsem */
+ if (dev->class == CL_EHCI) {
+ down_write(&companions_rwsem);
+ for_each_companion(dev, hcd, ehci_remove);
+ usb_remove_hcd(hcd);
+ dev_set_drvdata(&dev->dev, NULL);
+ up_write(&companions_rwsem);
+ } else {
+ /* Not EHCI; just clear the companion pointer */
+ down_read(&companions_rwsem);
+ hcd->self.hs_companion = NULL;
+ usb_remove_hcd(hcd);
+ dev_set_drvdata(&dev->dev, NULL);
+ up_read(&companions_rwsem);
+ }
+ usb_put_hcd(hcd);
+ pci_disable_device(dev);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
+
+/**
+ * usb_hcd_pci_shutdown - shutdown host controller
+ * @dev: USB Host Controller being shutdown
+ */
+void usb_hcd_pci_shutdown(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+ if (!hcd)
+ return;
+
+ if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
+ hcd->driver->shutdown) {
+ hcd->driver->shutdown(hcd);
+ if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
+ free_irq(hcd->irq, hcd);
+ pci_disable_device(dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
+
+#ifdef CONFIG_PM
+
+#ifdef CONFIG_PPC_PMAC
+static void powermac_set_asic(struct pci_dev *pci_dev, int enable)
+{
+ /* Enanble or disable ASIC clocks for USB */
+ if (machine_is(powermac)) {
+ struct device_node *of_node;
+
+ of_node = pci_device_to_OF_node(pci_dev);
+ if (of_node)
+ pmac_call_feature(PMAC_FTR_USB_ENABLE,
+ of_node, 0, enable);
+ }
+}
+
+#else
+
+static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable)
+{}
+
+#endif /* CONFIG_PPC_PMAC */
+
+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);
+
+ if (HCD_RH_RUNNING(hcd)) {
+ dev_warn(dev, "Root hub is not suspended\n");
+ return -EBUSY;
+ }
+ if (hcd->shared_hcd) {
+ hcd = hcd->shared_hcd;
+ if (HCD_RH_RUNNING(hcd)) {
+ dev_warn(dev, "Secondary root hub is not suspended\n");
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+static int suspend_common(struct device *dev, bool do_wakeup)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
+ int retval;
+
+ /* Root hub suspend should have stopped all downstream traffic,
+ * and all bus master traffic. And done so for both the interface
+ * and the stub usb_device (which we check here). But maybe it
+ * didn't; writing sysfs power/state files ignores such rules...
+ */
+ retval = check_root_hub_suspended(dev);
+ if (retval)
+ return retval;
+
+ if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) {
+ /* Optimization: Don't suspend if a root-hub wakeup is
+ * pending and it would cause the HCD to wake up anyway.
+ */
+ if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
+ return -EBUSY;
+ if (do_wakeup && hcd->shared_hcd &&
+ HCD_WAKEUP_PENDING(hcd->shared_hcd))
+ return -EBUSY;
+ retval = hcd->driver->pci_suspend(hcd, do_wakeup);
+ suspend_report_result(hcd->driver->pci_suspend, retval);
+
+ /* Check again in case wakeup raced with pci_suspend */
+ if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) ||
+ (retval == 0 && do_wakeup && hcd->shared_hcd &&
+ HCD_WAKEUP_PENDING(hcd->shared_hcd))) {
+ if (hcd->driver->pci_resume)
+ hcd->driver->pci_resume(hcd, false);
+ retval = -EBUSY;
+ }
+ if (retval)
+ return retval;
+ }
+
+ /* If MSI-X is enabled, the driver will have synchronized all vectors
+ * in pci_suspend(). If MSI or legacy PCI is enabled, that will be
+ * synchronized here.
+ */
+ if (!hcd->msix_enabled)
+ synchronize_irq(pci_dev->irq);
+
+ /* Downstream ports from this root hub should already be quiesced, so
+ * there will be no DMA activity. Now we can shut down the upstream
+ * link (except maybe for PME# resume signaling). We'll enter a
+ * low power state during suspend_noirq, if the hardware allows.
+ */
+ pci_disable_device(pci_dev);
+ return retval;
+}
+
+static int resume_common(struct device *dev, int event)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
+ int retval;
+
+ if (HCD_RH_RUNNING(hcd) ||
+ (hcd->shared_hcd &&
+ HCD_RH_RUNNING(hcd->shared_hcd))) {
+ dev_dbg(dev, "can't resume, not suspended!\n");
+ return 0;
+ }
+
+ retval = pci_enable_device(pci_dev);
+ if (retval < 0) {
+ dev_err(dev, "can't re-enable after resume, %d!\n", retval);
+ return retval;
+ }
+
+ pci_set_master(pci_dev);
+
+ if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
+
+ /*
+ * Only EHCI controllers have to wait for their companions.
+ * No locking is needed because PCI controller drivers do not
+ * get unbound during system resume.
+ */
+ if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)
+ for_each_companion(pci_dev, hcd,
+ ehci_wait_for_companions);
+
+ retval = hcd->driver->pci_resume(hcd,
+ event == PM_EVENT_RESTORE);
+ if (retval) {
+ dev_err(dev, "PCI post-resume error %d!\n", retval);
+ usb_hc_died(hcd);
+ }
+ }
+ return retval;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int hcd_pci_suspend(struct device *dev)
+{
+ return suspend_common(dev, device_may_wakeup(dev));
+}
+
+static int hcd_pci_suspend_noirq(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
+ int retval;
+
+ retval = check_root_hub_suspended(dev);
+ if (retval)
+ return retval;
+
+ pci_save_state(pci_dev);
+
+ /* If the root hub is dead rather than suspended, disallow remote
+ * wakeup. usb_hc_died() should ensure that both hosts are marked as
+ * dying, so we only need to check the primary roothub.
+ */
+ if (HCD_DEAD(hcd))
+ device_set_wakeup_enable(dev, 0);
+ dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev));
+
+ /* Possibly enable remote wakeup,
+ * choose the appropriate low-power state, and go to that state.
+ */
+ retval = pci_prepare_to_sleep(pci_dev);
+ if (retval == -EIO) { /* Low-power not supported */
+ dev_dbg(dev, "--> PCI D0 legacy\n");
+ retval = 0;
+ } else if (retval == 0) {
+ dev_dbg(dev, "--> PCI %s\n",
+ pci_power_name(pci_dev->current_state));
+ } else {
+ suspend_report_result(pci_prepare_to_sleep, retval);
+ return retval;
+ }
+
+ powermac_set_asic(pci_dev, 0);
+ return retval;
+}
+
+static int hcd_pci_resume_noirq(struct device *dev)
+{
+ powermac_set_asic(to_pci_dev(dev), 1);
+ return 0;
+}
+
+static int hcd_pci_resume(struct device *dev)
+{
+ return resume_common(dev, PM_EVENT_RESUME);
+}
+
+static int hcd_pci_restore(struct device *dev)
+{
+ return resume_common(dev, PM_EVENT_RESTORE);
+}
+
+#else
+
+#define hcd_pci_suspend NULL
+#define hcd_pci_suspend_noirq NULL
+#define hcd_pci_resume_noirq NULL
+#define hcd_pci_resume NULL
+#define hcd_pci_restore NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
+static int hcd_pci_runtime_suspend(struct device *dev)
+{
+ int retval;
+
+ retval = suspend_common(dev, true);
+ if (retval == 0)
+ powermac_set_asic(to_pci_dev(dev), 0);
+ dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
+ return retval;
+}
+
+static int hcd_pci_runtime_resume(struct device *dev)
+{
+ int retval;
+
+ powermac_set_asic(to_pci_dev(dev), 1);
+ retval = resume_common(dev, PM_EVENT_AUTO_RESUME);
+ dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
+ return retval;
+}
+
+const struct dev_pm_ops usb_hcd_pci_pm_ops = {
+ .suspend = hcd_pci_suspend,
+ .suspend_noirq = hcd_pci_suspend_noirq,
+ .resume_noirq = hcd_pci_resume_noirq,
+ .resume = hcd_pci_resume,
+ .freeze = hcd_pci_suspend,
+ .freeze_noirq = check_root_hub_suspended,
+ .thaw_noirq = NULL,
+ .thaw = hcd_pci_resume,
+ .poweroff = hcd_pci_suspend,
+ .poweroff_noirq = hcd_pci_suspend_noirq,
+ .restore_noirq = hcd_pci_resume_noirq,
+ .restore = hcd_pci_restore,
+ .runtime_suspend = hcd_pci_runtime_suspend,
+ .runtime_resume = hcd_pci_runtime_resume,
+};
+EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
+
+#endif /* CONFIG_PM */
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
new file mode 100644
index 000000000..df661460e
--- /dev/null
+++ b/drivers/usb/core/hcd.c
@@ -0,0 +1,3087 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2002
+ */
+
+#include <linux/bcd.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched/task_stack.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/utsname.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#include <linux/phy/phy.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
+
+#include "usb.h"
+#include "phy.h"
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences. That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead. The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ...
+ *
+ * HISTORY:
+ * 2002-02-21 Pull in most of the usb_bus support from usb.c; some
+ * associated cleanup. "usb_hcd" still != "usb_bus".
+ * 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* Keep track of which host controller drivers are loaded */
+unsigned long usb_hcds_loaded;
+EXPORT_SYMBOL_GPL(usb_hcds_loaded);
+
+/* host controllers we manage */
+DEFINE_IDR (usb_bus_idr);
+EXPORT_SYMBOL_GPL (usb_bus_idr);
+
+/* used when allocating bus numbers */
+#define USB_MAXBUS 64
+
+/* used when updating list of hcds */
+DEFINE_MUTEX(usb_bus_idr_lock); /* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_idr_lock);
+
+/* used for controlling access to virtual root hubs */
+static DEFINE_SPINLOCK(hcd_root_hub_lock);
+
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
+
+/* used to protect against unlinking URBs after the device is gone */
+static DEFINE_SPINLOCK(hcd_urb_unlink_lock);
+
+/* wait queue for synchronous unlinks */
+DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
+
+static inline int is_root_hub(struct usb_device *udev)
+{
+ return (udev->parent == NULL);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+#define KERNEL_REL bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
+#define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
+
+/* usb 3.1 root hub device descriptor */
+static const u8 usb31_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x10, 0x03, /* __le16 bcdUSB; v3.1 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x03, /* __u8 bDeviceProtocol; USB 3 hub */
+ 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* usb 3.0 root hub device descriptor */
+static const u8 usb3_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x00, 0x03, /* __le16 bcdUSB; v3.0 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */
+ 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
+static const u8 usb25_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x50, 0x02, /* __le16 bcdUSB; v2.5 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
+ 0xFF, /* __u8 bMaxPacketSize0; always 0xFF (WUSB Spec 7.4.1). */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x02, 0x00, /* __le16 idProduct; device 0x0002 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x00, 0x02, /* __le16 bcdUSB; v2.0 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
+ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x02, 0x00, /* __le16 idProduct; device 0x0002 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
+ 0x10, 0x01, /* __le16 bcdUSB; v1.1 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
+ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
+
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
+ 0x01, 0x00, /* __le16 idProduct; device 0x0001 */
+ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptors for our root hubs */
+
+static const u8 fs_rh_config_descriptor[] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __le16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0xc0, /* __u8 bmAttributes;
+ Bit 7: must be set,
+ 6: Self-powered,
+ 5: Remote wakeup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const u8 hs_rh_config_descriptor[] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __le16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0xc0, /* __u8 bmAttributes;
+ Bit 7: must be set,
+ 6: Self-powered,
+ 5: Remote wakeup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
+ * see hub.c:hub_configure() for details. */
+ (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
+ 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
+};
+
+static const u8 ss_rh_config_descriptor[] = {
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
+ 0x1f, 0x00, /* __le16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0xc0, /* __u8 bmAttributes;
+ Bit 7: must be set,
+ 6: Self-powered,
+ 5: Remote wakeup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
+ * see hub.c:hub_configure() for details. */
+ (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
+ 0x0c, /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
+
+ /* one SuperSpeed endpoint companion descriptor */
+ 0x06, /* __u8 ss_bLength */
+ USB_DT_SS_ENDPOINT_COMP, /* __u8 ss_bDescriptorType; SuperSpeed EP */
+ /* Companion */
+ 0x00, /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */
+ 0x00, /* __u8 ss_bmAttributes; 1 packet per service interval */
+ 0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
+};
+
+/* authorized_default behaviour:
+ * -1 is authorized for all devices except wireless (old behaviour)
+ * 0 is unauthorized for all devices
+ * 1 is authorized for all devices
+ */
+static int authorized_default = -1;
+module_param(authorized_default, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(authorized_default,
+ "Default USB device authorization: 0 is not authorized, 1 is "
+ "authorized, -1 is authorized except for wireless USB (default, "
+ "old behaviour");
+/*-------------------------------------------------------------------------*/
+
+/**
+ * ascii2desc() - Helper routine for producing UTF-16LE string descriptors
+ * @s: Null-terminated ASCII (actually ISO-8859-1) string
+ * @buf: Buffer for USB string descriptor (header + UTF-16LE)
+ * @len: Length (in bytes; may be odd) of descriptor buffer.
+ *
+ * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
+ * whichever is less.
+ *
+ * Note:
+ * USB String descriptors can contain at most 126 characters; input
+ * strings longer than that are truncated.
+ */
+static unsigned
+ascii2desc(char const *s, u8 *buf, unsigned len)
+{
+ unsigned n, t = 2 + 2*strlen(s);
+
+ if (t > 254)
+ t = 254; /* Longest possible UTF string descriptor */
+ if (len > t)
+ len = t;
+
+ t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */
+
+ n = len;
+ while (n--) {
+ *buf++ = t;
+ if (!n--)
+ break;
+ *buf++ = t >> 8;
+ t = (unsigned char)*s++;
+ }
+ return len;
+}
+
+/**
+ * rh_string() - provides string descriptors for root hub
+ * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
+ * @hcd: the host controller for this root hub
+ * @data: buffer for output packet
+ * @len: length of the provided buffer
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ *
+ * Return: The number of bytes filled in: the length of the descriptor or
+ * of the provided buffer, whichever is less.
+ */
+static unsigned
+rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)
+{
+ char buf[100];
+ char const *s;
+ static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};
+
+ /* language ids */
+ switch (id) {
+ case 0:
+ /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
+ /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
+ if (len > 4)
+ len = 4;
+ memcpy(data, langids, len);
+ return len;
+ case 1:
+ /* Serial number */
+ s = hcd->self.bus_name;
+ break;
+ case 2:
+ /* Product name */
+ s = hcd->product_desc;
+ break;
+ case 3:
+ /* Manufacturer */
+ snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
+ init_utsname()->release, hcd->driver->description);
+ s = buf;
+ break;
+ default:
+ /* Can't happen; caller guarantees it */
+ return 0;
+ }
+
+ return ascii2desc(s, data, len);
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+ struct usb_ctrlrequest *cmd;
+ u16 typeReq, wValue, wIndex, wLength;
+ u8 *ubuf = urb->transfer_buffer;
+ unsigned len = 0;
+ int status;
+ u8 patch_wakeup = 0;
+ u8 patch_protocol = 0;
+ u16 tbuf_size;
+ u8 *tbuf = NULL;
+ const u8 *bufp;
+
+ might_sleep();
+
+ spin_lock_irq(&hcd_root_hub_lock);
+ status = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irq(&hcd_root_hub_lock);
+ if (status)
+ return status;
+ urb->hcpriv = hcd; /* Indicate it's queued */
+
+ cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+ typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
+ wValue = le16_to_cpu (cmd->wValue);
+ wIndex = le16_to_cpu (cmd->wIndex);
+ wLength = le16_to_cpu (cmd->wLength);
+
+ if (wLength > urb->transfer_buffer_length)
+ goto error;
+
+ /*
+ * tbuf should be at least as big as the
+ * USB hub descriptor.
+ */
+ tbuf_size = max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
+ tbuf = kzalloc(tbuf_size, GFP_KERNEL);
+ if (!tbuf) {
+ status = -ENOMEM;
+ goto err_alloc;
+ }
+
+ bufp = tbuf;
+
+
+ urb->actual_length = 0;
+ switch (typeReq) {
+
+ /* DEVICE REQUESTS */
+
+ /* The root hub's remote wakeup enable bit is implemented using
+ * driver model wakeup flags. If this system supports wakeup
+ * through USB, userspace may change the default "allow wakeup"
+ * policy through sysfs or these calls.
+ *
+ * Most root hubs support wakeup from downstream devices, for
+ * runtime power management (disabling USB clocks and reducing
+ * VBUS power usage). However, not all of them do so; silicon,
+ * board, and BIOS bugs here are not uncommon, so these can't
+ * be treated quite like external hubs.
+ *
+ * Likewise, not all root hubs will pass wakeup events upstream,
+ * to wake up the whole system. So don't assume root hub and
+ * controller capabilities are identical.
+ */
+
+ case DeviceRequest | USB_REQ_GET_STATUS:
+ tbuf[0] = (device_may_wakeup(&hcd->self.root_hub->dev)
+ << USB_DEVICE_REMOTE_WAKEUP)
+ | (1 << USB_DEVICE_SELF_POWERED);
+ tbuf[1] = 0;
+ len = 2;
+ break;
+ case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+ if (wValue == USB_DEVICE_REMOTE_WAKEUP)
+ device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
+ else
+ goto error;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ if (device_can_wakeup(&hcd->self.root_hub->dev)
+ && wValue == USB_DEVICE_REMOTE_WAKEUP)
+ device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
+ else
+ goto error;
+ break;
+ case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+ tbuf[0] = 1;
+ len = 1;
+ /* FALLTHROUGH */
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch (wValue & 0xff00) {
+ case USB_DT_DEVICE << 8:
+ switch (hcd->speed) {
+ case HCD_USB32:
+ case HCD_USB31:
+ bufp = usb31_rh_dev_descriptor;
+ break;
+ case HCD_USB3:
+ bufp = usb3_rh_dev_descriptor;
+ break;
+ case HCD_USB25:
+ bufp = usb25_rh_dev_descriptor;
+ break;
+ case HCD_USB2:
+ bufp = usb2_rh_dev_descriptor;
+ break;
+ case HCD_USB11:
+ bufp = usb11_rh_dev_descriptor;
+ break;
+ default:
+ goto error;
+ }
+ len = 18;
+ if (hcd->has_tt)
+ patch_protocol = 1;
+ break;
+ case USB_DT_CONFIG << 8:
+ switch (hcd->speed) {
+ case HCD_USB32:
+ case HCD_USB31:
+ case HCD_USB3:
+ bufp = ss_rh_config_descriptor;
+ len = sizeof ss_rh_config_descriptor;
+ break;
+ case HCD_USB25:
+ case HCD_USB2:
+ bufp = hs_rh_config_descriptor;
+ len = sizeof hs_rh_config_descriptor;
+ break;
+ case HCD_USB11:
+ bufp = fs_rh_config_descriptor;
+ len = sizeof fs_rh_config_descriptor;
+ break;
+ default:
+ goto error;
+ }
+ if (device_can_wakeup(&hcd->self.root_hub->dev))
+ patch_wakeup = 1;
+ break;
+ case USB_DT_STRING << 8:
+ if ((wValue & 0xff) < 4)
+ urb->actual_length = rh_string(wValue & 0xff,
+ hcd, ubuf, wLength);
+ else /* unsupported IDs --> "protocol stall" */
+ goto error;
+ break;
+ case USB_DT_BOS << 8:
+ goto nongeneric;
+ default:
+ goto error;
+ }
+ break;
+ case DeviceRequest | USB_REQ_GET_INTERFACE:
+ tbuf[0] = 0;
+ len = 1;
+ /* FALLTHROUGH */
+ case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+ break;
+ case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+ /* wValue == urb->dev->devaddr */
+ dev_dbg (hcd->self.controller, "root hub device address %d\n",
+ wValue);
+ break;
+
+ /* INTERFACE REQUESTS (no defined feature/status flags) */
+
+ /* ENDPOINT REQUESTS */
+
+ case EndpointRequest | USB_REQ_GET_STATUS:
+ /* ENDPOINT_HALT flag */
+ tbuf[0] = 0;
+ tbuf[1] = 0;
+ len = 2;
+ /* FALLTHROUGH */
+ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+ case EndpointOutRequest | USB_REQ_SET_FEATURE:
+ dev_dbg (hcd->self.controller, "no endpoint features yet\n");
+ break;
+
+ /* CLASS REQUESTS (and errors) */
+
+ default:
+nongeneric:
+ /* non-generic request */
+ switch (typeReq) {
+ case GetHubStatus:
+ len = 4;
+ break;
+ case GetPortStatus:
+ if (wValue == HUB_PORT_STATUS)
+ len = 4;
+ else
+ /* other port status types return 8 bytes */
+ len = 8;
+ break;
+ case GetHubDescriptor:
+ len = sizeof (struct usb_hub_descriptor);
+ break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ /* len is returned by hub_control */
+ break;
+ }
+ status = hcd->driver->hub_control (hcd,
+ typeReq, wValue, wIndex,
+ tbuf, wLength);
+
+ if (typeReq == GetHubDescriptor)
+ usb_hub_adjust_deviceremovable(hcd->self.root_hub,
+ (struct usb_hub_descriptor *)tbuf);
+ break;
+error:
+ /* "protocol stall" on error */
+ status = -EPIPE;
+ }
+
+ if (status < 0) {
+ len = 0;
+ if (status != -EPIPE) {
+ dev_dbg (hcd->self.controller,
+ "CTRL: TypeReq=0x%x val=0x%x "
+ "idx=0x%x len=%d ==> %d\n",
+ typeReq, wValue, wIndex,
+ wLength, status);
+ }
+ } else if (status > 0) {
+ /* hub_control may return the length of data copied. */
+ len = status;
+ status = 0;
+ }
+ if (len) {
+ if (urb->transfer_buffer_length < len)
+ len = urb->transfer_buffer_length;
+ urb->actual_length = len;
+ /* always USB_DIR_IN, toward host */
+ memcpy (ubuf, bufp, len);
+
+ /* report whether RH hardware supports remote wakeup */
+ if (patch_wakeup &&
+ len > offsetof (struct usb_config_descriptor,
+ bmAttributes))
+ ((struct usb_config_descriptor *)ubuf)->bmAttributes
+ |= USB_CONFIG_ATT_WAKEUP;
+
+ /* report whether RH hardware has an integrated TT */
+ if (patch_protocol &&
+ len > offsetof(struct usb_device_descriptor,
+ bDeviceProtocol))
+ ((struct usb_device_descriptor *) ubuf)->
+ bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
+ }
+
+ kfree(tbuf);
+ err_alloc:
+
+ /* any errors get returned through the urb completion */
+ spin_lock_irq(&hcd_root_hub_lock);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_unlock_irq(&hcd_root_hub_lock);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are polled using a timer if the
+ * driver requests it; otherwise the driver is responsible for
+ * calling usb_hcd_poll_rh_status() when an event occurs.
+ *
+ * Completions are called in_interrupt(), but they may or may not
+ * be in_irq().
+ */
+void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
+{
+ struct urb *urb;
+ int length;
+ int status;
+ unsigned long flags;
+ char buffer[6]; /* Any root hubs with > 31 ports? */
+
+ if (unlikely(!hcd->rh_pollable))
+ return;
+ if (!hcd->uses_new_polling && !hcd->status_urb)
+ return;
+
+ length = hcd->driver->hub_status_data(hcd, buffer);
+ if (length > 0) {
+
+ /* try to complete the status urb */
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ urb = hcd->status_urb;
+ if (urb) {
+ clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
+ hcd->status_urb = NULL;
+ if (urb->transfer_buffer_length >= length) {
+ status = 0;
+ } else {
+ status = -EOVERFLOW;
+ length = urb->transfer_buffer_length;
+ }
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ } else {
+ length = 0;
+ set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
+ }
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ }
+
+ /* The USB 2.0 spec says 256 ms. This is close enough and won't
+ * exceed that limit if HZ is 100. The math is more clunky than
+ * maybe expected, this is to make sure that all timers for USB devices
+ * fire at the same time to give the CPU a break in between */
+ if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
+ (length == 0 && hcd->status_urb != NULL))
+ mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+}
+EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
+
+/* timer callback */
+static void rh_timer_func (struct timer_list *t)
+{
+ struct usb_hcd *_hcd = from_timer(_hcd, t, rh_timer);
+
+ usb_hcd_poll_rh_status(_hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
+{
+ int retval;
+ unsigned long flags;
+ unsigned len = 1 + (urb->dev->maxchild / 8);
+
+ spin_lock_irqsave (&hcd_root_hub_lock, flags);
+ if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
+ retval = -EINVAL;
+ goto done;
+ }
+
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
+ goto done;
+
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
+ if (!hcd->uses_new_polling)
+ mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+ /* If a status change has already occurred, report it ASAP */
+ else if (HCD_POLL_PENDING(hcd))
+ mod_timer(&hcd->rh_timer, jiffies);
+ retval = 0;
+ done:
+ spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+ return retval;
+}
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+ if (usb_endpoint_xfer_int(&urb->ep->desc))
+ return rh_queue_status (hcd, urb);
+ if (usb_endpoint_xfer_control(&urb->ep->desc))
+ return rh_call_control (hcd, urb);
+ return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Unlinks of root-hub control URBs are legal, but they don't do anything
+ * since these URBs always execute synchronously.
+ */
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
+ ; /* Do nothing */
+
+ } else { /* Status URB */
+ if (!hcd->uses_new_polling)
+ del_timer (&hcd->rh_timer);
+ if (urb == hcd->status_urb) {
+ hcd->status_urb = NULL;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ }
+ }
+ done:
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ return rc;
+}
+
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t authorized_default_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *hcd;
+
+ hcd = bus_to_hcd(usb_bus);
+ return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd));
+}
+
+static ssize_t authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned val;
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *hcd;
+
+ hcd = bus_to_hcd(usb_bus);
+ result = sscanf(buf, "%u\n", &val);
+ if (result == 1) {
+ if (val)
+ set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+ else
+ clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+
+ result = size;
+ } else {
+ result = -EINVAL;
+ }
+ return result;
+}
+static DEVICE_ATTR_RW(authorized_default);
+
+/*
+ * interface_authorized_default_show - show default authorization status
+ * for USB interfaces
+ *
+ * note: interface_authorized_default is the default value
+ * for initializing the authorized attribute of interfaces
+ */
+static ssize_t interface_authorized_default_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
+
+ return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
+}
+
+/*
+ * interface_authorized_default_store - store default authorization status
+ * for USB interfaces
+ *
+ * note: interface_authorized_default is the default value
+ * for initializing the authorized attribute of interfaces
+ */
+static ssize_t interface_authorized_default_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
+ int rc = count;
+ bool val;
+
+ if (strtobool(buf, &val) != 0)
+ return -EINVAL;
+
+ if (val)
+ set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
+ else
+ clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
+
+ return rc;
+}
+static DEVICE_ATTR_RW(interface_authorized_default);
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+ &dev_attr_authorized_default.attr,
+ &dev_attr_interface_authorized_default.attr,
+ NULL,
+};
+
+static const struct attribute_group usb_bus_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = usb_bus_attrs,
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_bus_init - shared initialization code
+ * @bus: the bus structure being initialized
+ *
+ * This code is used to initialize a usb_bus structure, memory for which is
+ * separately managed.
+ */
+static void usb_bus_init (struct usb_bus *bus)
+{
+ memset (&bus->devmap, 0, sizeof(struct usb_devmap));
+
+ bus->devnum_next = 1;
+
+ bus->root_hub = NULL;
+ bus->busnum = -1;
+ bus->bandwidth_allocated = 0;
+ bus->bandwidth_int_reqs = 0;
+ bus->bandwidth_isoc_reqs = 0;
+ mutex_init(&bus->devnum_next_mutex);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_register_bus - registers the USB host controller with the usb core
+ * @bus: pointer to the bus to register
+ * Context: !in_interrupt()
+ *
+ * Assigns a bus number, and links the controller into usbcore data
+ * structures so that it can be seen by scanning the bus list.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+static int usb_register_bus(struct usb_bus *bus)
+{
+ int result = -E2BIG;
+ int busnum;
+
+ mutex_lock(&usb_bus_idr_lock);
+ busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL);
+ if (busnum < 0) {
+ pr_err("%s: failed to get bus number\n", usbcore_name);
+ goto error_find_busnum;
+ }
+ bus->busnum = busnum;
+ mutex_unlock(&usb_bus_idr_lock);
+
+ usb_notify_add_bus(bus);
+
+ dev_info (bus->controller, "new USB bus registered, assigned bus "
+ "number %d\n", bus->busnum);
+ return 0;
+
+error_find_busnum:
+ mutex_unlock(&usb_bus_idr_lock);
+ return result;
+}
+
+/**
+ * usb_deregister_bus - deregisters the USB host controller
+ * @bus: pointer to the bus to deregister
+ * Context: !in_interrupt()
+ *
+ * Recycles the bus number, and unlinks the controller from usbcore data
+ * structures so that it won't be seen by scanning the bus list.
+ */
+static void usb_deregister_bus (struct usb_bus *bus)
+{
+ dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);
+
+ /*
+ * NOTE: make sure that all the devices are removed by the
+ * controller code, as well as having it call this when cleaning
+ * itself up
+ */
+ mutex_lock(&usb_bus_idr_lock);
+ idr_remove(&usb_bus_idr, bus->busnum);
+ mutex_unlock(&usb_bus_idr_lock);
+
+ usb_notify_remove_bus(bus);
+}
+
+/**
+ * register_root_hub - called by usb_add_hcd() to register a root hub
+ * @hcd: host controller for this root hub
+ *
+ * This function registers the root hub with the USB subsystem. It sets up
+ * the device properly in the device tree and then calls usb_new_device()
+ * to register the usb device. It also assigns the root hub's USB address
+ * (always 1).
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+static int register_root_hub(struct usb_hcd *hcd)
+{
+ struct device *parent_dev = hcd->self.controller;
+ struct usb_device *usb_dev = hcd->self.root_hub;
+ const int devnum = 1;
+ int retval;
+
+ usb_dev->devnum = devnum;
+ usb_dev->bus->devnum_next = devnum + 1;
+ memset (&usb_dev->bus->devmap.devicemap, 0,
+ sizeof usb_dev->bus->devmap.devicemap);
+ set_bit (devnum, usb_dev->bus->devmap.devicemap);
+ usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
+
+ mutex_lock(&usb_bus_idr_lock);
+
+ usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
+ retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
+ if (retval != sizeof usb_dev->descriptor) {
+ mutex_unlock(&usb_bus_idr_lock);
+ dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
+ dev_name(&usb_dev->dev), retval);
+ return (retval < 0) ? retval : -EMSGSIZE;
+ }
+
+ if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
+ retval = usb_get_bos_descriptor(usb_dev);
+ if (!retval) {
+ usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
+ } else if (usb_dev->speed >= USB_SPEED_SUPER) {
+ mutex_unlock(&usb_bus_idr_lock);
+ dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
+ dev_name(&usb_dev->dev), retval);
+ return retval;
+ }
+ }
+
+ retval = usb_new_device (usb_dev);
+ if (retval) {
+ dev_err (parent_dev, "can't register root hub for %s, %d\n",
+ dev_name(&usb_dev->dev), retval);
+ } else {
+ spin_lock_irq (&hcd_root_hub_lock);
+ hcd->rh_registered = 1;
+ spin_unlock_irq (&hcd_root_hub_lock);
+
+ /* Did the HC die before the root hub was registered? */
+ if (HCD_DEAD(hcd))
+ usb_hc_died (hcd); /* This time clean up */
+ }
+ mutex_unlock(&usb_bus_idr_lock);
+
+ return retval;
+}
+
+/*
+ * usb_hcd_start_port_resume - a root-hub port is sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal is
+ * being sent to a root-hub port. The root hub will be prevented from
+ * going into autosuspend until usb_hcd_end_port_resume() is called.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
+{
+ unsigned bit = 1 << portnum;
+
+ if (!(bus->resuming_ports & bit)) {
+ bus->resuming_ports |= bit;
+ pm_runtime_get_noresume(&bus->root_hub->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
+
+/*
+ * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal has
+ * stopped being sent to a root-hub port. The root hub will be allowed to
+ * autosuspend again.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
+{
+ unsigned bit = 1 << portnum;
+
+ if (bus->resuming_ports & bit) {
+ bus->resuming_ports &= ~bit;
+ pm_runtime_put_noidle(&bus->root_hub->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_calc_bus_time - approximate periodic transaction time in nanoseconds
+ * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
+ * @is_input: true iff the transaction sends data to the host
+ * @isoc: true for isochronous transactions, false for interrupt ones
+ * @bytecount: how many bytes in the transaction.
+ *
+ * Return: Approximate bus time in nanoseconds for a periodic transaction.
+ *
+ * Note:
+ * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
+ * scheduled in software, this function is only used for such scheduling.
+ */
+long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+{
+ unsigned long tmp;
+
+ switch (speed) {
+ case USB_SPEED_LOW: /* INTR only */
+ if (is_input) {
+ tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
+ return 64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp;
+ } else {
+ tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
+ return 64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp;
+ }
+ case USB_SPEED_FULL: /* ISOC or INTR */
+ if (isoc) {
+ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+ return ((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp;
+ } else {
+ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+ return 9107L + BW_HOST_DELAY + tmp;
+ }
+ case USB_SPEED_HIGH: /* ISOC or INTR */
+ /* FIXME adjust for input vs output */
+ if (isoc)
+ tmp = HS_NSECS_ISO (bytecount);
+ else
+ tmp = HS_NSECS (bytecount);
+ return tmp;
+ default:
+ pr_debug ("%s: bogus device speed!\n", usbcore_name);
+ return -1;
+ }
+}
+EXPORT_SYMBOL_GPL(usb_calc_bus_time);
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Return: 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail). If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+ int rc = 0;
+
+ spin_lock(&hcd_urb_list_lock);
+
+ /* Check that the URB isn't being killed */
+ if (unlikely(atomic_read(&urb->reject))) {
+ rc = -EPERM;
+ goto done;
+ }
+
+ if (unlikely(!urb->ep->enabled)) {
+ rc = -ENOENT;
+ goto done;
+ }
+
+ if (unlikely(!urb->dev->can_submit)) {
+ rc = -EHOSTUNREACH;
+ goto done;
+ }
+
+ /*
+ * Check the host controller's state and add the URB to the
+ * endpoint's queue.
+ */
+ if (HCD_RH_RUNNING(hcd)) {
+ urb->unlinked = 0;
+ list_add_tail(&urb->urb_list, &urb->ep->urb_list);
+ } else {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+ done:
+ spin_unlock(&hcd_urb_list_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Return: 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail). The possible error codes are:
+ *
+ * -EIDRM: @urb was not submitted or has already completed.
+ * The completion function may not have been called yet.
+ *
+ * -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct list_head *tmp;
+
+ /* insist the urb is still queued */
+ list_for_each(tmp, &urb->ep->urb_list) {
+ if (tmp == &urb->urb_list)
+ break;
+ }
+ if (tmp != &urb->urb_list)
+ return -EIDRM;
+
+ /* Any status except -EINPROGRESS means something already started to
+ * unlink this URB from the hardware. So there's no more work to do.
+ */
+ if (urb->unlinked)
+ return -EBUSY;
+ urb->unlinked = status;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
+ * interrupts must be disabled. The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* clear all state linking urb to this dev (and hcd) */
+ spin_lock(&hcd_urb_list_lock);
+ list_del_init(&urb->urb_list);
+ spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+/*
+ * Some usb host controllers can only perform dma using a small SRAM area.
+ * The usb core itself is however optimized for host controllers that can dma
+ * using regular system memory - like pci devices doing bus mastering.
+ *
+ * To support host controllers with limited dma capabilities we provide dma
+ * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
+ * 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 HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
+ * dma using dma_alloc_coherent() which in turn allocates from the memory
+ * area pointed out with dma_declare_coherent_memory().
+ *
+ * So, to summarize...
+ *
+ * - We need "local" memory, canonical example being
+ * a small SRAM on a discrete controller being the
+ * only memory that the controller can read ...
+ * (a) "normal" kernel memory is no good, and
+ * (b) there's not enough to share
+ *
+ * - The only *portable* hook for such stuff in the
+ * DMA framework is dma_declare_coherent_memory()
+ *
+ * - So we use that, even though the primary requirement
+ * is that the memory be "local" (hence addressable
+ * by that device), not "coherent".
+ *
+ */
+
+static int hcd_alloc_coherent(struct usb_bus *bus,
+ gfp_t mem_flags, dma_addr_t *dma_handle,
+ void **vaddr_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned char *vaddr;
+
+ if (*vaddr_handle == NULL) {
+ WARN_ON_ONCE(1);
+ return -EFAULT;
+ }
+
+ vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
+ mem_flags, dma_handle);
+ if (!vaddr)
+ return -ENOMEM;
+
+ /*
+ * Store the virtual address of the buffer at the end
+ * of the allocated dma buffer. The size of the buffer
+ * may be uneven so use unaligned functions instead
+ * of just rounding up. It makes sense to optimize for
+ * memory footprint over access speed since the amount
+ * of memory available for dma may be limited.
+ */
+ put_unaligned((unsigned long)*vaddr_handle,
+ (unsigned long *)(vaddr + size));
+
+ if (dir == DMA_TO_DEVICE)
+ memcpy(vaddr, *vaddr_handle, size);
+
+ *vaddr_handle = vaddr;
+ return 0;
+}
+
+static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
+ void **vaddr_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned char *vaddr = *vaddr_handle;
+
+ vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size));
+
+ if (dir == DMA_FROM_DEVICE)
+ memcpy(vaddr, *vaddr_handle, size);
+
+ hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle);
+
+ *vaddr_handle = vaddr;
+ *dma_handle = 0;
+}
+
+void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_SETUP_MAP_SINGLE))
+ dma_unmap_single(hcd->self.sysdev,
+ urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
+ hcd_free_coherent(urb->dev->bus,
+ &urb->setup_dma,
+ (void **) &urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+
+ /* Make it safe to call this routine more than once */
+ urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_setup_for_dma);
+
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (hcd->driver->unmap_urb_for_dma)
+ hcd->driver->unmap_urb_for_dma(hcd, urb);
+ else
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+}
+
+void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ enum dma_data_direction dir;
+
+ usb_hcd_unmap_urb_setup_for_dma(hcd, urb);
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_SG))
+ dma_unmap_sg(hcd->self.sysdev,
+ urb->sg,
+ urb->num_sgs,
+ dir);
+ else if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_PAGE))
+ dma_unmap_page(hcd->self.sysdev,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+ else if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_SINGLE))
+ dma_unmap_single(hcd->self.sysdev,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+ else if (urb->transfer_flags & URB_MAP_LOCAL)
+ hcd_free_coherent(urb->dev->bus,
+ &urb->transfer_dma,
+ &urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+
+ /* Make it safe to call this routine more than once */
+ urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
+ URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_for_dma);
+
+static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ if (hcd->driver->map_urb_for_dma)
+ return hcd->driver->map_urb_for_dma(hcd, urb, mem_flags);
+ else
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+}
+
+int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ int ret = 0;
+
+ /* Map the URB's buffers for DMA access.
+ * Lower level HCD code should use *_dma exclusively,
+ * unless it uses pio or talks to another transport,
+ * or uses the provided scatter gather list for bulk.
+ */
+
+ if (usb_endpoint_xfer_control(&urb->ep->desc)) {
+ if (hcd->self.uses_pio_for_control)
+ return ret;
+ if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+ 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)) {
+ WARN_ONCE(1, "setup packet is on stack\n");
+ return -EAGAIN;
+ }
+
+ urb->setup_dma = dma_map_single(
+ hcd->self.sysdev,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(hcd->self.sysdev,
+ urb->setup_dma))
+ return -EAGAIN;
+ urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+ } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ 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 (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+ if (urb->num_sgs) {
+ int n;
+
+ /* We don't support sg for isoc transfers ! */
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ n = dma_map_sg(
+ hcd->self.sysdev,
+ urb->sg,
+ urb->num_sgs,
+ dir);
+ if (n <= 0)
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_SG;
+ urb->num_mapped_sgs = n;
+ if (n != urb->num_sgs)
+ urb->transfer_flags |=
+ URB_DMA_SG_COMBINED;
+ } else if (urb->sg) {
+ struct scatterlist *sg = urb->sg;
+ urb->transfer_dma = dma_map_page(
+ hcd->self.sysdev,
+ sg_page(sg),
+ sg->offset,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.sysdev,
+ urb->transfer_dma))
+ 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;
+ } else {
+ urb->transfer_dma = dma_map_single(
+ hcd->self.sysdev,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.sysdev,
+ urb->transfer_dma))
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+ }
+ } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ 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)))
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_map_urb_for_dma);
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+ int status;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+
+ /* increment urb's reference count as part of giving it to the HCD
+ * (which will control it). HCD guarantees that it either returns
+ * an error or calls giveback(), but not both.
+ */
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usbmon_urb_submit(&hcd->self, urb);
+
+ /* NOTE requirements on root-hub callers (usbfs and the hub
+ * driver, for now): URBs' urb->transfer_buffer must be
+ * valid and usb_buffer_{sync,unmap}() not be needed, since
+ * they could clobber root hub response data. Also, control
+ * URBs must be submitted in process context with interrupts
+ * enabled.
+ */
+
+ if (is_root_hub(urb->dev)) {
+ status = rh_urb_enqueue(hcd, urb);
+ } else {
+ status = map_urb_for_dma(hcd, urb, mem_flags);
+ if (likely(status == 0)) {
+ status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+ if (unlikely(status))
+ unmap_urb_for_dma(hcd, urb);
+ }
+ }
+
+ if (unlikely(status)) {
+ usbmon_urb_submit_error(&hcd->self, urb, status);
+ urb->hcpriv = NULL;
+ INIT_LIST_HEAD(&urb->urb_list);
+ atomic_dec(&urb->use_count);
+ /*
+ * Order the write of urb->use_count above before the read
+ * of urb->reject below. Pairs with the memory barriers in
+ * usb_kill_urb() and usb_poison_urb().
+ */
+ smp_mb__after_atomic();
+
+ atomic_dec(&urb->dev->urbnum);
+ if (atomic_read(&urb->reject))
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
+ }
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* this makes the hcd giveback() the urb more quickly, by kicking it
+ * off hardware queues (which may take a while) and returning it as
+ * soon as practical. we've already set up the urb's return status,
+ * but we can't know if the callback completed already.
+ */
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ int value;
+
+ if (is_root_hub(urb->dev))
+ value = usb_rh_urb_dequeue(hcd, urb, status);
+ else {
+
+ /* The only reason an HCD might fail this call is if
+ * it has not yet fully queued the urb to begin with.
+ * Such failures should be harmless. */
+ value = hcd->driver->urb_dequeue(hcd, urb, status);
+ }
+ return value;
+}
+
+/*
+ * called in any context
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+int usb_hcd_unlink_urb (struct urb *urb, int status)
+{
+ struct usb_hcd *hcd;
+ struct usb_device *udev = urb->dev;
+ int retval = -EIDRM;
+ unsigned long flags;
+
+ /* Prevent the device and bus from going away while
+ * the unlink is carried out. If they are already gone
+ * then urb->use_count must be 0, since disconnected
+ * devices can't have any active URBs.
+ */
+ spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
+ if (atomic_read(&urb->use_count) > 0) {
+ retval = 0;
+ usb_get_dev(udev);
+ }
+ spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
+ if (retval == 0) {
+ hcd = bus_to_hcd(urb->dev->bus);
+ retval = unlink1(hcd, urb, status);
+ if (retval == 0)
+ retval = -EINPROGRESS;
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&udev->dev, "hcd_unlink_urb %pK fail %d\n",
+ urb, retval);
+ usb_put_dev(udev);
+ }
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+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) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
+ usb_anchor_suspend_wakeups(anchor);
+ usb_unanchor_urb(urb);
+ if (likely(status == 0))
+ usb_led_activity(USB_LED_EVENT_HOST);
+
+ /* 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);
+ /*
+ * Order the write of urb->use_count above before the read
+ * of urb->reject below. Pairs with the memory barriers in
+ * usb_kill_urb() and usb_poison_urb().
+ */
+ smp_mb__after_atomic();
+
+ if (unlikely(atomic_read(&urb->reject)))
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
+}
+
+static void usb_giveback_urb_bh(unsigned long param)
+{
+ struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
+ struct list_head local_list;
+
+ spin_lock_irq(&bh->lock);
+ bh->running = true;
+ restart:
+ list_replace_init(&bh->head, &local_list);
+ spin_unlock_irq(&bh->lock);
+
+ while (!list_empty(&local_list)) {
+ struct urb *urb;
+
+ urb = list_entry(local_list.next, struct urb, urb_list);
+ list_del_init(&urb->urb_list);
+ bh->completing_ep = urb->ep;
+ __usb_hcd_giveback_urb(urb);
+ bh->completing_ep = NULL;
+ }
+
+ /* check if there are new URBs to giveback */
+ spin_lock_irq(&bh->lock);
+ if (!list_empty(&bh->head))
+ goto restart;
+ bh->running = false;
+ spin_unlock_irq(&bh->lock);
+}
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function. The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv). It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked. Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
+ */
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct giveback_urb_bh *bh;
+ bool running, high_prio_bh;
+
+ /* pass status to tasklet via unlinked */
+ if (likely(!urb->unlinked))
+ urb->unlinked = status;
+
+ if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
+ __usb_hcd_giveback_urb(urb);
+ return;
+ }
+
+ if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+ bh = &hcd->high_prio_bh;
+ high_prio_bh = true;
+ } else {
+ bh = &hcd->low_prio_bh;
+ high_prio_bh = false;
+ }
+
+ spin_lock(&bh->lock);
+ list_add_tail(&urb->urb_list, &bh->head);
+ running = bh->running;
+ spin_unlock(&bh->lock);
+
+ if (running)
+ ;
+ else if (high_prio_bh)
+ tasklet_hi_schedule(&bh->bh);
+ else
+ tasklet_schedule(&bh->bh);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely. The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
+ */
+void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+ struct urb *urb;
+
+ if (!ep)
+ return;
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+
+ /* No more submits can occur */
+ spin_lock_irq(&hcd_urb_list_lock);
+rescan:
+ list_for_each_entry_reverse(urb, &ep->urb_list, urb_list) {
+ int is_in;
+
+ if (urb->unlinked)
+ continue;
+ usb_get_urb (urb);
+ is_in = usb_urb_dir_in(urb);
+ spin_unlock(&hcd_urb_list_lock);
+
+ /* kick hcd */
+ unlink1(hcd, urb, -ESHUTDOWN);
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %pK ep%d%s%s\n",
+ urb, usb_endpoint_num(&ep->desc),
+ is_in ? "in" : "out",
+ ({ char *s;
+
+ switch (usb_endpoint_type(&ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ s = ""; break;
+ case USB_ENDPOINT_XFER_BULK:
+ s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ s = "-intr"; break;
+ default:
+ s = "-iso"; break;
+ };
+ s;
+ }));
+ usb_put_urb (urb);
+
+ /* list contents may have changed */
+ spin_lock(&hcd_urb_list_lock);
+ goto rescan;
+ }
+ spin_unlock_irq(&hcd_urb_list_lock);
+
+ /* Wait until the endpoint queue is completely empty */
+ while (!list_empty (&ep->urb_list)) {
+ spin_lock_irq(&hcd_urb_list_lock);
+
+ /* The list may have changed while we acquired the spinlock */
+ urb = NULL;
+ if (!list_empty (&ep->urb_list)) {
+ urb = list_entry (ep->urb_list.prev, struct urb,
+ urb_list);
+ usb_get_urb (urb);
+ }
+ spin_unlock_irq(&hcd_urb_list_lock);
+
+ if (urb) {
+ usb_kill_urb (urb);
+ usb_put_urb (urb);
+ }
+ }
+}
+
+/**
+ * usb_hcd_alloc_bandwidth - check whether a new bandwidth setting exceeds
+ * the bus bandwidth
+ * @udev: target &usb_device
+ * @new_config: new configuration to install
+ * @cur_alt: the current alternate interface setting
+ * @new_alt: alternate interface setting that is being installed
+ *
+ * To change configurations, pass in the new configuration in new_config,
+ * and pass NULL for cur_alt and new_alt.
+ *
+ * To reset a device's configuration (put the device in the ADDRESSED state),
+ * pass in NULL for new_config, cur_alt, and new_alt.
+ *
+ * To change alternate interface settings, pass in NULL for new_config,
+ * pass in the current alternate interface setting in cur_alt,
+ * and pass in the new alternate interface setting in new_alt.
+ *
+ * Return: An error if the requested bandwidth change exceeds the
+ * bus bandwidth or host controller internal resources.
+ */
+int usb_hcd_alloc_bandwidth(struct usb_device *udev,
+ struct usb_host_config *new_config,
+ struct usb_host_interface *cur_alt,
+ struct usb_host_interface *new_alt)
+{
+ int num_intfs, i, j;
+ struct usb_host_interface *alt = NULL;
+ int ret = 0;
+ struct usb_hcd *hcd;
+ struct usb_host_endpoint *ep;
+
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd->driver->check_bandwidth)
+ return 0;
+
+ /* Configuration is being removed - set configuration 0 */
+ if (!new_config && !cur_alt) {
+ for (i = 1; i < 16; ++i) {
+ ep = udev->ep_out[i];
+ if (ep)
+ hcd->driver->drop_endpoint(hcd, udev, ep);
+ ep = udev->ep_in[i];
+ if (ep)
+ hcd->driver->drop_endpoint(hcd, udev, ep);
+ }
+ hcd->driver->check_bandwidth(hcd, udev);
+ return 0;
+ }
+ /* Check if the HCD says there's enough bandwidth. Enable all endpoints
+ * each interface's alt setting 0 and ask the HCD to check the bandwidth
+ * of the bus. There will always be bandwidth for endpoint 0, so it's
+ * ok to exclude it.
+ */
+ if (new_config) {
+ num_intfs = new_config->desc.bNumInterfaces;
+ /* Remove endpoints (except endpoint 0, which is always on the
+ * schedule) from the old config from the schedule
+ */
+ for (i = 1; i < 16; ++i) {
+ ep = udev->ep_out[i];
+ if (ep) {
+ ret = hcd->driver->drop_endpoint(hcd, udev, ep);
+ if (ret < 0)
+ goto reset;
+ }
+ ep = udev->ep_in[i];
+ if (ep) {
+ ret = hcd->driver->drop_endpoint(hcd, udev, ep);
+ if (ret < 0)
+ goto reset;
+ }
+ }
+ for (i = 0; i < num_intfs; ++i) {
+ struct usb_host_interface *first_alt;
+ int iface_num;
+
+ first_alt = &new_config->intf_cache[i]->altsetting[0];
+ iface_num = first_alt->desc.bInterfaceNumber;
+ /* Set up endpoints for alternate interface setting 0 */
+ alt = usb_find_alt_setting(new_config, iface_num, 0);
+ if (!alt)
+ /* No alt setting 0? Pick the first setting. */
+ alt = first_alt;
+
+ for (j = 0; j < alt->desc.bNumEndpoints; j++) {
+ ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
+ if (ret < 0)
+ goto reset;
+ }
+ }
+ }
+ if (cur_alt && new_alt) {
+ struct usb_interface *iface = usb_ifnum_to_if(udev,
+ cur_alt->desc.bInterfaceNumber);
+
+ if (!iface)
+ return -EINVAL;
+ if (iface->resetting_device) {
+ /*
+ * The USB core just reset the device, so the xHCI host
+ * and the device will think alt setting 0 is installed.
+ * However, the USB core will pass in the alternate
+ * setting installed before the reset as cur_alt. Dig
+ * out the alternate setting 0 structure, or the first
+ * alternate setting if a broken device doesn't have alt
+ * setting 0.
+ */
+ cur_alt = usb_altnum_to_altsetting(iface, 0);
+ if (!cur_alt)
+ cur_alt = &iface->altsetting[0];
+ }
+
+ /* Drop all the endpoints in the current alt setting */
+ for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) {
+ ret = hcd->driver->drop_endpoint(hcd, udev,
+ &cur_alt->endpoint[i]);
+ if (ret < 0)
+ goto reset;
+ }
+ /* Add all the endpoints in the new alt setting */
+ for (i = 0; i < new_alt->desc.bNumEndpoints; i++) {
+ ret = hcd->driver->add_endpoint(hcd, udev,
+ &new_alt->endpoint[i]);
+ if (ret < 0)
+ goto reset;
+ }
+ }
+ ret = hcd->driver->check_bandwidth(hcd, udev);
+reset:
+ if (ret < 0)
+ hcd->driver->reset_bandwidth(hcd, udev);
+ return ret;
+}
+
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable(hcd, ep);
+}
+
+/**
+ * usb_hcd_reset_endpoint - reset host endpoint state
+ * @udev: USB device.
+ * @ep: the endpoint to reset.
+ *
+ * Resets any host endpoint state such as the toggle bit, sequence
+ * number and current window.
+ */
+void usb_hcd_reset_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (hcd->driver->endpoint_reset)
+ hcd->driver->endpoint_reset(hcd, ep);
+ else {
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
+
+ usb_settoggle(udev, epnum, is_out, 0);
+ if (is_control)
+ usb_settoggle(udev, epnum, !is_out, 0);
+ }
+}
+
+/**
+ * usb_alloc_streams - allocate bulk endpoint stream IDs.
+ * @interface: alternate setting that includes all endpoints.
+ * @eps: array of endpoints that need streams.
+ * @num_eps: number of endpoints in the array.
+ * @num_streams: number of streams to allocate.
+ * @mem_flags: flags hcd should use to allocate memory.
+ *
+ * Sets up a group of bulk endpoints to have @num_streams stream IDs available.
+ * Drivers may queue multiple transfers to different stream IDs, which may
+ * complete in a different order than they were queued.
+ *
+ * Return: On success, the number of allocated streams. On failure, a negative
+ * error code.
+ */
+int usb_alloc_streams(struct usb_interface *interface,
+ struct usb_host_endpoint **eps, unsigned int num_eps,
+ unsigned int num_streams, gfp_t mem_flags)
+{
+ struct usb_hcd *hcd;
+ struct usb_device *dev;
+ int i, ret;
+
+ dev = interface_to_usbdev(interface);
+ hcd = bus_to_hcd(dev->bus);
+ if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
+ return -EINVAL;
+ if (dev->speed < USB_SPEED_SUPER)
+ return -EINVAL;
+ if (dev->state < USB_STATE_CONFIGURED)
+ return -ENODEV;
+
+ for (i = 0; i < num_eps; i++) {
+ /* Streams only apply to bulk endpoints. */
+ if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
+ return -EINVAL;
+ /* Re-alloc is not allowed */
+ if (eps[i]->streams)
+ return -EINVAL;
+ }
+
+ ret = hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
+ num_streams, mem_flags);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num_eps; i++)
+ eps[i]->streams = ret;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_alloc_streams);
+
+/**
+ * usb_free_streams - free bulk endpoint stream IDs.
+ * @interface: alternate setting that includes all endpoints.
+ * @eps: array of endpoints to remove streams from.
+ * @num_eps: number of endpoints in the array.
+ * @mem_flags: flags hcd should use to allocate memory.
+ *
+ * Reverts a group of bulk endpoints back to not using stream IDs.
+ * Can fail if we are given bad arguments, or HCD is broken.
+ *
+ * Return: 0 on success. On failure, a negative error code.
+ */
+int usb_free_streams(struct usb_interface *interface,
+ struct usb_host_endpoint **eps, unsigned int num_eps,
+ gfp_t mem_flags)
+{
+ struct usb_hcd *hcd;
+ struct usb_device *dev;
+ int i, ret;
+
+ dev = interface_to_usbdev(interface);
+ hcd = bus_to_hcd(dev->bus);
+ if (dev->speed < USB_SPEED_SUPER)
+ return -EINVAL;
+
+ /* Double-free is not allowed */
+ for (i = 0; i < num_eps; i++)
+ if (!eps[i] || !eps[i]->streams)
+ return -EINVAL;
+
+ ret = hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num_eps; i++)
+ eps[i]->streams = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_free_streams);
+
+/* Protect against drivers that try to unlink URBs after the device
+ * is gone, by waiting until all unlinks for @udev are finished.
+ * Since we don't currently track URBs by device, simply wait until
+ * nothing is running in the locked region of usb_hcd_unlink_urb().
+ */
+void usb_hcd_synchronize_unlinks(struct usb_device *udev)
+{
+ spin_lock_irq(&hcd_urb_unlink_lock);
+ spin_unlock_irq(&hcd_urb_unlink_lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HCD_RH_RUNNING(hcd))
+ return -ESHUTDOWN;
+ return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
+{
+ struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
+ int status;
+ int old_state = hcd->state;
+
+ dev_dbg(&rhdev->dev, "bus %ssuspend, wakeup %d\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""),
+ rhdev->do_remote_wakeup);
+ if (HCD_DEAD(hcd)) {
+ dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "suspend");
+ return 0;
+ }
+
+ if (!hcd->driver->bus_suspend) {
+ status = -ENOENT;
+ } else {
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ hcd->state = HC_STATE_QUIESCING;
+ status = hcd->driver->bus_suspend(hcd);
+ }
+ if (status == 0) {
+ usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
+ hcd->state = HC_STATE_SUSPENDED;
+
+ if (!PMSG_IS_AUTO(msg))
+ usb_phy_roothub_suspend(hcd->self.sysdev,
+ hcd->phy_roothub);
+
+ /* Did we race with a root-hub wakeup event? */
+ if (rhdev->do_remote_wakeup) {
+ char buffer[6];
+
+ status = hcd->driver->hub_status_data(hcd, buffer);
+ if (status != 0) {
+ dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n");
+ hcd_bus_resume(rhdev, PMSG_AUTO_RESUME);
+ status = -EBUSY;
+ }
+ }
+ } else {
+ spin_lock_irq(&hcd_root_hub_lock);
+ if (!HCD_DEAD(hcd)) {
+ set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ hcd->state = old_state;
+ }
+ spin_unlock_irq(&hcd_root_hub_lock);
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
+ "suspend", status);
+ }
+ return status;
+}
+
+int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
+{
+ struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
+ int status;
+ int old_state = hcd->state;
+
+ dev_dbg(&rhdev->dev, "usb %sresume\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""));
+ if (HCD_DEAD(hcd)) {
+ dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume");
+ return 0;
+ }
+
+ if (!PMSG_IS_AUTO(msg)) {
+ status = usb_phy_roothub_resume(hcd->self.sysdev,
+ hcd->phy_roothub);
+ if (status)
+ return status;
+ }
+
+ if (!hcd->driver->bus_resume)
+ return -ENOENT;
+ if (HCD_RH_RUNNING(hcd))
+ return 0;
+
+ hcd->state = HC_STATE_RESUMING;
+ status = hcd->driver->bus_resume(hcd);
+ clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
+ if (status == 0) {
+ struct usb_device *udev;
+ int port1;
+
+ spin_lock_irq(&hcd_root_hub_lock);
+ if (!HCD_DEAD(hcd)) {
+ usb_set_device_state(rhdev, rhdev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
+ set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ hcd->state = HC_STATE_RUNNING;
+ }
+ spin_unlock_irq(&hcd_root_hub_lock);
+
+ /*
+ * Check whether any of the enabled ports on the root hub are
+ * unsuspended. If they are then a TRSMRCY delay is needed
+ * (this is what the USB-2 spec calls a "global resume").
+ * Otherwise we can skip the delay.
+ */
+ usb_hub_for_each_child(rhdev, port1, udev) {
+ if (udev->state != USB_STATE_NOTATTACHED &&
+ !udev->port_is_suspended) {
+ usleep_range(10000, 11000); /* TRSMRCY */
+ break;
+ }
+ }
+ } else {
+ hcd->state = old_state;
+ usb_phy_roothub_suspend(hcd->self.sysdev, hcd->phy_roothub);
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
+ "resume", status);
+ if (status != -ESHUTDOWN)
+ usb_hc_died(hcd);
+ }
+ return status;
+}
+
+/* Workqueue routine for root-hub remote wakeup */
+static void hcd_resume_work(struct work_struct *work)
+{
+ struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
+ struct usb_device *udev = hcd->self.root_hub;
+
+ usb_remote_wakeup(udev);
+}
+
+/**
+ * usb_hcd_resume_root_hub - called by HCD to resume its root hub
+ * @hcd: host controller for this root hub
+ *
+ * The USB host controller calls this function when its root hub is
+ * suspended (with the remote wakeup feature enabled) and a remote
+ * wakeup request is received. The routine submits a workqueue request
+ * to resume the root hub (that is, manage its downstream ports again).
+ */
+void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&hcd_root_hub_lock, flags);
+ if (hcd->rh_registered) {
+ pm_wakeup_event(&hcd->self.root_hub->dev, 0);
+ set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
+ queue_work(pm_wq, &hcd->wakeup_work);
+ }
+ spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
+
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_OTG
+
+/**
+ * usb_bus_start_enum - start immediate enumeration (for OTG)
+ * @bus: the bus (must use hcd framework)
+ * @port_num: 1-based number of port; usually bus->otg_port
+ * Context: in_interrupt()
+ *
+ * Starts enumeration, with an immediate reset followed later by
+ * hub_wq identifying and possibly configuring the device.
+ * This is needed by OTG controller drivers, where it helps meet
+ * HNP protocol timing requirements for starting a port reset.
+ *
+ * Return: 0 if successful.
+ */
+int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
+{
+ struct usb_hcd *hcd;
+ int status = -EOPNOTSUPP;
+
+ /* NOTE: since HNP can't start by grabbing the bus's address0_sem,
+ * boards with root hubs hooked up to internal devices (instead of
+ * just the OTG port) may need more attention to resetting...
+ */
+ hcd = bus_to_hcd(bus);
+ if (port_num && hcd->driver->start_port_reset)
+ status = hcd->driver->start_port_reset(hcd, port_num);
+
+ /* allocate hub_wq shortly after (first) root port reset finishes;
+ * it may issue others, until at least 50 msecs have passed.
+ */
+ if (status == 0)
+ mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_bus_start_enum);
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
+ * @irq: the IRQ being raised
+ * @__hcd: pointer to the HCD whose IRQ is being signaled
+ *
+ * If the controller isn't HALTed, calls the driver's irq handler.
+ * Checks whether the controller is now dead.
+ *
+ * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise.
+ */
+irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+{
+ struct usb_hcd *hcd = __hcd;
+ irqreturn_t rc;
+
+ if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
+ rc = IRQ_NONE;
+ else if (hcd->driver->irq(hcd) == IRQ_NONE)
+ rc = IRQ_NONE;
+ else
+ rc = IRQ_HANDLED;
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_irq);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hc_died - report abnormal shutdown of a host controller (bus glue)
+ * @hcd: pointer to the HCD representing the controller
+ *
+ * This is called by bus glue to report a USB host controller that died
+ * while operations may still have been pending. It's called automatically
+ * by the PCI glue, so only glue for non-PCI busses should need to call it.
+ *
+ * Only call this function with the primary HCD.
+ */
+void usb_hc_died (struct usb_hcd *hcd)
+{
+ unsigned long flags;
+
+ dev_err (hcd->self.controller, "HC died; cleaning up\n");
+
+ spin_lock_irqsave (&hcd_root_hub_lock, flags);
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ set_bit(HCD_FLAG_DEAD, &hcd->flags);
+ if (hcd->rh_registered) {
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+ /* make hub_wq clean up old urbs and devices */
+ usb_set_device_state (hcd->self.root_hub,
+ USB_STATE_NOTATTACHED);
+ usb_kick_hub_wq(hcd->self.root_hub);
+ }
+ if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
+ hcd = hcd->shared_hcd;
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ set_bit(HCD_FLAG_DEAD, &hcd->flags);
+ if (hcd->rh_registered) {
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+ /* make hub_wq clean up old urbs and devices */
+ usb_set_device_state(hcd->self.root_hub,
+ USB_STATE_NOTATTACHED);
+ usb_kick_hub_wq(hcd->self.root_hub);
+ }
+ }
+ spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+ /* Make sure that the other roothub is also deallocated. */
+}
+EXPORT_SYMBOL_GPL (usb_hc_died);
+
+/*-------------------------------------------------------------------------*/
+
+static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
+{
+
+ spin_lock_init(&bh->lock);
+ INIT_LIST_HEAD(&bh->head);
+ tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
+}
+
+struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
+ struct device *sysdev, struct device *dev, const char *bus_name,
+ struct usb_hcd *primary_hcd)
+{
+ struct usb_hcd *hcd;
+
+ hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
+ if (!hcd)
+ return NULL;
+ if (primary_hcd == NULL) {
+ hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex),
+ GFP_KERNEL);
+ if (!hcd->address0_mutex) {
+ kfree(hcd);
+ dev_dbg(dev, "hcd address0 mutex alloc failed\n");
+ return NULL;
+ }
+ mutex_init(hcd->address0_mutex);
+ hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
+ GFP_KERNEL);
+ if (!hcd->bandwidth_mutex) {
+ kfree(hcd->address0_mutex);
+ kfree(hcd);
+ dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
+ return NULL;
+ }
+ mutex_init(hcd->bandwidth_mutex);
+ dev_set_drvdata(dev, hcd);
+ } else {
+ mutex_lock(&usb_port_peer_mutex);
+ hcd->address0_mutex = primary_hcd->address0_mutex;
+ hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
+ hcd->primary_hcd = primary_hcd;
+ primary_hcd->primary_hcd = primary_hcd;
+ hcd->shared_hcd = primary_hcd;
+ primary_hcd->shared_hcd = hcd;
+ mutex_unlock(&usb_port_peer_mutex);
+ }
+
+ kref_init(&hcd->kref);
+
+ usb_bus_init(&hcd->self);
+ 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
+ INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
+#endif
+
+ hcd->driver = driver;
+ hcd->speed = driver->flags & HCD_MASK;
+ hcd->product_desc = (driver->product_desc) ? driver->product_desc :
+ "USB Host Controller";
+ return hcd;
+}
+EXPORT_SYMBOL_GPL(__usb_create_hcd);
+
+/**
+ * usb_create_shared_hcd - create and initialize an HCD structure
+ * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
+ * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
+ * PCI device. Only allocate certain resources for the primary HCD
+ * Context: !in_interrupt()
+ *
+ * Allocate a struct usb_hcd, with extra space at the end for the
+ * HC driver's private data. Initialize the generic members of the
+ * hcd structure.
+ *
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
+ */
+struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
+ struct device *dev, const char *bus_name,
+ struct usb_hcd *primary_hcd)
+{
+ return __usb_create_hcd(driver, dev, dev, bus_name, primary_hcd);
+}
+EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
+
+/**
+ * usb_create_hcd - create and initialize an HCD structure
+ * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
+ * Context: !in_interrupt()
+ *
+ * Allocate a struct usb_hcd, with extra space at the end for the
+ * HC driver's private data. Initialize the generic members of the
+ * hcd structure.
+ *
+ * Return: On success, a pointer to the created and initialized HCD
+ * structure. On failure (e.g. if memory is unavailable), %NULL.
+ */
+struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
+ struct device *dev, const char *bus_name)
+{
+ return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_create_hcd);
+
+/*
+ * Roothubs that share one PCI device must also share the bandwidth mutex.
+ * Don't deallocate the bandwidth_mutex until the last shared usb_hcd is
+ * deallocated.
+ *
+ * Make sure to deallocate the bandwidth_mutex only when the last HCD is
+ * freed. When hcd_release() is called for either hcd in a peer set,
+ * invalidate the peer's ->shared_hcd and ->primary_hcd pointers.
+ */
+static void hcd_release(struct kref *kref)
+{
+ struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
+
+ mutex_lock(&usb_port_peer_mutex);
+ if (hcd->shared_hcd) {
+ struct usb_hcd *peer = hcd->shared_hcd;
+
+ peer->shared_hcd = NULL;
+ peer->primary_hcd = NULL;
+ } else {
+ kfree(hcd->address0_mutex);
+ kfree(hcd->bandwidth_mutex);
+ }
+ mutex_unlock(&usb_port_peer_mutex);
+ kfree(hcd);
+}
+
+struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
+{
+ if (hcd)
+ kref_get (&hcd->kref);
+ return hcd;
+}
+EXPORT_SYMBOL_GPL(usb_get_hcd);
+
+void usb_put_hcd (struct usb_hcd *hcd)
+{
+ if (hcd)
+ kref_put (&hcd->kref, hcd_release);
+}
+EXPORT_SYMBOL_GPL(usb_put_hcd);
+
+int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
+{
+ if (!hcd->primary_hcd)
+ return 1;
+ return hcd == hcd->primary_hcd;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
+
+int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+ if (!hcd->driver->find_raw_port_number)
+ return port1;
+
+ return hcd->driver->find_raw_port_number(hcd, port1);
+}
+
+static int usb_hcd_request_irqs(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ int retval;
+
+ if (hcd->driver->irq) {
+
+ snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+ hcd->driver->description, hcd->self.busnum);
+ retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
+ hcd->irq_descr, hcd);
+ if (retval != 0) {
+ dev_err(hcd->self.controller,
+ "request interrupt %d failed\n",
+ irqnum);
+ return retval;
+ }
+ hcd->irq = irqnum;
+ dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
+ (hcd->driver->flags & HCD_MEMORY) ?
+ "io mem" : "io base",
+ (unsigned long long)hcd->rsrc_start);
+ } else {
+ hcd->irq = 0;
+ if (hcd->rsrc_start)
+ dev_info(hcd->self.controller, "%s 0x%08llx\n",
+ (hcd->driver->flags & HCD_MEMORY) ?
+ "io mem" : "io base",
+ (unsigned long long)hcd->rsrc_start);
+ }
+ return 0;
+}
+
+/*
+ * Before we free this root hub, flush in-flight peering attempts
+ * and disable peer lookups
+ */
+static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
+{
+ struct usb_device *rhdev;
+
+ mutex_lock(&usb_port_peer_mutex);
+ rhdev = hcd->self.root_hub;
+ hcd->self.root_hub = NULL;
+ mutex_unlock(&usb_port_peer_mutex);
+ usb_put_dev(rhdev);
+}
+
+/**
+ * usb_add_hcd - finish generic HCD structure initialization and register
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ *
+ * Finish the remaining parts of generic HCD initialization: allocate the
+ * buffers of consistent memory, register the bus, request the IRQ line,
+ * and call the driver's reset() and start() routines.
+ */
+int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ int retval;
+ struct usb_device *rhdev;
+
+ if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
+ hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
+ if (IS_ERR(hcd->phy_roothub))
+ return PTR_ERR(hcd->phy_roothub);
+
+ retval = usb_phy_roothub_init(hcd->phy_roothub);
+ if (retval)
+ return retval;
+
+ retval = usb_phy_roothub_power_on(hcd->phy_roothub);
+ if (retval)
+ goto err_usb_phy_roothub_power_on;
+ }
+
+ dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+
+ /* Keep old behaviour if authorized_default is not in [0, 1]. */
+ if (authorized_default < 0 || authorized_default > 1) {
+ if (hcd->wireless)
+ clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+ else
+ set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+ } else {
+ if (authorized_default)
+ set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+ else
+ clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
+ }
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* per default all interfaces are authorized */
+ set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
+
+ /* HC is in reset state, but accessible. Now do the one-time init,
+ * bottom up so that hcds can customize the root hubs before hub_wq
+ * starts talking to them. (Note, bus id is assigned early too.)
+ */
+ retval = hcd_buffer_create(hcd);
+ if (retval != 0) {
+ dev_dbg(hcd->self.sysdev, "pool alloc failed\n");
+ goto err_create_buf;
+ }
+
+ retval = usb_register_bus(&hcd->self);
+ if (retval < 0)
+ goto err_register_bus;
+
+ rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
+ if (rhdev == NULL) {
+ dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
+ retval = -ENOMEM;
+ goto err_allocate_root_hub;
+ }
+ mutex_lock(&usb_port_peer_mutex);
+ hcd->self.root_hub = rhdev;
+ mutex_unlock(&usb_port_peer_mutex);
+
+ rhdev->rx_lanes = 1;
+ rhdev->tx_lanes = 1;
+
+ switch (hcd->speed) {
+ case HCD_USB11:
+ rhdev->speed = USB_SPEED_FULL;
+ break;
+ case HCD_USB2:
+ rhdev->speed = USB_SPEED_HIGH;
+ break;
+ case HCD_USB25:
+ rhdev->speed = USB_SPEED_WIRELESS;
+ break;
+ case HCD_USB3:
+ rhdev->speed = USB_SPEED_SUPER;
+ break;
+ case HCD_USB32:
+ rhdev->rx_lanes = 2;
+ rhdev->tx_lanes = 2;
+ /* fall through */
+ case HCD_USB31:
+ rhdev->speed = USB_SPEED_SUPER_PLUS;
+ break;
+ default:
+ retval = -EINVAL;
+ goto err_set_rh_speed;
+ }
+
+ /* wakeup flag init defaults to "everything works" for root hubs,
+ * but drivers can override it in reset() if needed, along with
+ * recording the overall controller's system wakeup capability.
+ */
+ device_set_wakeup_capable(&rhdev->dev, 1);
+
+ /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
+ * registered. But since the controller can die at any time,
+ * let's initialize the flag before touching the hardware.
+ */
+ set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+
+ /* "reset" is misnamed; its role is now one-time init. the controller
+ * should already have been reset (and boot firmware kicked off etc).
+ */
+ if (hcd->driver->reset) {
+ retval = hcd->driver->reset(hcd);
+ if (retval < 0) {
+ dev_err(hcd->self.controller, "can't setup: %d\n",
+ retval);
+ goto err_hcd_driver_setup;
+ }
+ }
+ hcd->rh_pollable = 1;
+
+ /* 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))
+ dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+
+ /* initialize tasklets */
+ init_giveback_urb_bh(&hcd->high_prio_bh);
+ init_giveback_urb_bh(&hcd->low_prio_bh);
+
+ /* enable irqs just before we start the controller,
+ * if the BIOS provides legacy PCI irqs.
+ */
+ if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
+ retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
+ if (retval)
+ goto err_request_irq;
+ }
+
+ hcd->state = HC_STATE_RUNNING;
+ retval = hcd->driver->start(hcd);
+ if (retval < 0) {
+ dev_err(hcd->self.controller, "startup error %d\n", retval);
+ goto err_hcd_driver_start;
+ }
+
+ /* starting here, usbcore will pay attention to this root hub */
+ retval = register_root_hub(hcd);
+ if (retval != 0)
+ goto err_register_root_hub;
+
+ retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+ if (retval < 0) {
+ printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+ retval);
+ goto error_create_attr_group;
+ }
+ if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
+ usb_hcd_poll_rh_status(hcd);
+
+ return retval;
+
+error_create_attr_group:
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ if (HC_IS_RUNNING(hcd->state))
+ hcd->state = HC_STATE_QUIESCING;
+ spin_lock_irq(&hcd_root_hub_lock);
+ hcd->rh_registered = 0;
+ spin_unlock_irq(&hcd_root_hub_lock);
+
+#ifdef CONFIG_PM
+ cancel_work_sync(&hcd->wakeup_work);
+#endif
+ mutex_lock(&usb_bus_idr_lock);
+ usb_disconnect(&rhdev); /* Sets rhdev to NULL */
+ mutex_unlock(&usb_bus_idr_lock);
+err_register_root_hub:
+ hcd->rh_pollable = 0;
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ del_timer_sync(&hcd->rh_timer);
+ hcd->driver->stop(hcd);
+ hcd->state = HC_STATE_HALT;
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ del_timer_sync(&hcd->rh_timer);
+err_hcd_driver_start:
+ if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
+ free_irq(irqnum, hcd);
+err_request_irq:
+err_hcd_driver_setup:
+err_set_rh_speed:
+ usb_put_invalidate_rhdev(hcd);
+err_allocate_root_hub:
+ usb_deregister_bus(&hcd->self);
+err_register_bus:
+ hcd_buffer_destroy(hcd);
+err_create_buf:
+ usb_phy_roothub_power_off(hcd->phy_roothub);
+err_usb_phy_roothub_power_on:
+ usb_phy_roothub_exit(hcd->phy_roothub);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_add_hcd);
+
+/**
+ * usb_remove_hcd - shutdown processing for generic HCDs
+ * @hcd: the usb_hcd structure to remove
+ * Context: !in_interrupt()
+ *
+ * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() method.
+ */
+void usb_remove_hcd(struct usb_hcd *hcd)
+{
+ struct usb_device *rhdev = hcd->self.root_hub;
+
+ dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
+
+ usb_get_dev(rhdev);
+ sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ if (HC_IS_RUNNING (hcd->state))
+ hcd->state = HC_STATE_QUIESCING;
+
+ dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
+ spin_lock_irq (&hcd_root_hub_lock);
+ hcd->rh_registered = 0;
+ spin_unlock_irq (&hcd_root_hub_lock);
+
+#ifdef CONFIG_PM
+ cancel_work_sync(&hcd->wakeup_work);
+#endif
+
+ mutex_lock(&usb_bus_idr_lock);
+ usb_disconnect(&rhdev); /* Sets rhdev to NULL */
+ mutex_unlock(&usb_bus_idr_lock);
+
+ /*
+ * tasklet_kill() isn't needed here because:
+ * - driver's disconnect() called from usb_disconnect() should
+ * make sure its URBs are completed during the disconnect()
+ * callback
+ *
+ * - it is too late to run complete() here since driver may have
+ * been removed already now
+ */
+
+ /* Prevent any more root-hub status calls from the timer.
+ * The HCD might still restart the timer (if a port status change
+ * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
+ * the hub_status_data() callback.
+ */
+ hcd->rh_pollable = 0;
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ del_timer_sync(&hcd->rh_timer);
+
+ hcd->driver->stop(hcd);
+ hcd->state = HC_STATE_HALT;
+
+ /* In case the HCD restarted the timer, stop it again. */
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ del_timer_sync(&hcd->rh_timer);
+
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ if (hcd->irq > 0)
+ free_irq(hcd->irq, hcd);
+ }
+
+ usb_deregister_bus(&hcd->self);
+ hcd_buffer_destroy(hcd);
+
+ usb_phy_roothub_power_off(hcd->phy_roothub);
+ usb_phy_roothub_exit(hcd->phy_roothub);
+
+ usb_put_invalidate_rhdev(hcd);
+ hcd->flags = 0;
+}
+EXPORT_SYMBOL_GPL(usb_remove_hcd);
+
+void
+usb_hcd_platform_shutdown(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ /* No need for pm_runtime_put(), we're shutting down */
+ pm_runtime_get_sync(&dev->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
+
+/*-------------------------------------------------------------------------*/
+
+#if IS_ENABLED(CONFIG_USB_MON)
+
+const struct usb_mon_operations *mon_ops;
+
+/*
+ * The registration is unlocked.
+ * We do it this way because we do not want to lock in hot paths.
+ *
+ * Notice that the code is minimally error-proof. Because usbmon needs
+ * symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
+ */
+
+int usb_mon_register(const struct usb_mon_operations *ops)
+{
+
+ if (mon_ops)
+ return -EBUSY;
+
+ mon_ops = ops;
+ mb();
+ return 0;
+}
+EXPORT_SYMBOL_GPL (usb_mon_register);
+
+void usb_mon_deregister (void)
+{
+
+ if (mon_ops == NULL) {
+ printk(KERN_ERR "USB: monitor was not registered\n");
+ return;
+ }
+ mon_ops = NULL;
+ mb();
+}
+EXPORT_SYMBOL_GPL (usb_mon_deregister);
+
+#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
new file mode 100644
index 000000000..29cc2aa5a
--- /dev/null
+++ b/drivers/usb/core/hub.c
@@ -0,0 +1,6079 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB hub driver.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Gregory P. Smith
+ * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/completion.h>
+#include <linux/sched/mm.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/quirks.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/random.h>
+#include <linux/pm_qos.h>
+
+#include <linux/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "hub.h"
+#include "otg_whitelist.h"
+
+#define USB_VENDOR_GENESYS_LOGIC 0x05e3
+#define USB_VENDOR_SMSC 0x0424
+#define USB_PRODUCT_USB5534B 0x5534
+#define USB_VENDOR_CYPRESS 0x04b4
+#define USB_PRODUCT_CY7C65632 0x6570
+#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
+#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
+
+#define USB_TP_TRANSMISSION_DELAY 40 /* ns */
+#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */
+#define USB_PING_RESPONSE_TIME 400 /* 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. */
+static DEFINE_SPINLOCK(device_state_lock);
+
+/* workqueue to process hub events */
+static struct workqueue_struct *hub_wq;
+static void hub_event(struct work_struct *work);
+
+/* synchronize hub-port add/remove and peering operations */
+DEFINE_MUTEX(usb_port_peer_mutex);
+
+/* cycle leds on hubs that aren't blinking for attention */
+static bool blinkenlights;
+module_param(blinkenlights, bool, S_IRUGO);
+MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs");
+
+/*
+ * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about
+ * 10 seconds to send reply for the initial 64-byte descriptor request.
+ */
+/* define initial 64-byte descriptor request timeout in milliseconds */
+static int initial_descriptor_timeout = USB_CTRL_GET_TIMEOUT;
+module_param(initial_descriptor_timeout, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initial_descriptor_timeout,
+ "initial 64-byte descriptor request timeout in milliseconds "
+ "(default 5000 - 5.0 seconds)");
+
+/*
+ * As of 2.6.10 we introduce a new USB device initialization scheme which
+ * closely resembles the way Windows works. Hopefully it will be compatible
+ * with a wider range of devices than the old scheme. However some previously
+ * working devices may start giving rise to "device not accepting address"
+ * errors; if that happens the user can try the old scheme by adjusting the
+ * following module parameters.
+ *
+ * For maximum flexibility there are two boolean parameters to control the
+ * hub driver's behavior. On the first initialization attempt, if the
+ * "old_scheme_first" parameter is set then the old scheme will be used,
+ * otherwise the new scheme is used. If that fails and "use_both_schemes"
+ * is set, then the driver will make another attempt, using the other scheme.
+ */
+static bool old_scheme_first;
+module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(old_scheme_first,
+ "start with the old device initialization scheme");
+
+static bool use_both_schemes = 1;
+module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(use_both_schemes,
+ "try the other device initialization scheme if the "
+ "first one fails");
+
+/* Mutual exclusion for EHCI CF initialization. This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
+#define HUB_DEBOUNCE_TIMEOUT 2000
+#define HUB_DEBOUNCE_STEP 25
+#define HUB_DEBOUNCE_STABLE 100
+
+static void hub_release(struct kref *kref);
+static int usb_reset_and_verify_device(struct usb_device *udev);
+static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
+static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
+ u16 portstatus);
+
+static inline char *portspeed(struct usb_hub *hub, int portstatus)
+{
+ if (hub_is_superspeedplus(hub->hdev))
+ return "10.0 Gb/s";
+ if (hub_is_superspeed(hub->hdev))
+ return "5.0 Gb/s";
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ return "480 Mb/s";
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
+/* Note that hdev or one of its children must be locked! */
+struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
+{
+ if (!hdev || !hdev->actconfig || !hdev->maxchild)
+ return NULL;
+ return usb_get_intfdata(hdev->actconfig->interface[0]);
+}
+
+int usb_device_supports_lpm(struct usb_device *udev)
+{
+ /* Some devices have trouble with LPM */
+ if (udev->quirks & USB_QUIRK_NO_LPM)
+ return 0;
+
+ /* USB 2.1 (and greater) devices indicate LPM support through
+ * their USB 2.0 Extended Capabilities BOS descriptor.
+ */
+ if (udev->speed == USB_SPEED_HIGH || udev->speed == USB_SPEED_FULL) {
+ if (udev->bos->ext_cap &&
+ (USB_LPM_SUPPORT &
+ le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+ return 1;
+ return 0;
+ }
+
+ /*
+ * According to the USB 3.0 spec, all USB 3.0 devices must support LPM.
+ * However, there are some that don't, and they set the U1/U2 exit
+ * latencies to zero.
+ */
+ if (!udev->bos->ss_cap) {
+ dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n");
+ return 0;
+ }
+
+ if (udev->bos->ss_cap->bU1devExitLat == 0 &&
+ udev->bos->ss_cap->bU2DevExitLat == 0) {
+ if (udev->parent)
+ dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n");
+ else
+ dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n");
+ return 0;
+ }
+
+ if (!udev->parent || udev->parent->lpm_capable)
+ return 1;
+ return 0;
+}
+
+/*
+ * Set the Maximum Exit Latency (MEL) for the host to wakup up the path from
+ * U1/U2, send a PING to the device and receive a PING_RESPONSE.
+ * See USB 3.1 section C.1.5.2
+ */
+static void usb_set_lpm_mel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency)
+{
+ unsigned int total_mel;
+
+ /*
+ * tMEL1. time to transition path from host to device into U0.
+ * MEL for parent already contains the delay up to parent, so only add
+ * the exit latency for the last link (pick the slower exit latency),
+ * and the hub header decode latency. See USB 3.1 section C 2.2.1
+ * Store MEL in nanoseconds
+ */
+ total_mel = hub_lpm_params->mel +
+ max(udev_exit_latency, hub_exit_latency) * 1000 +
+ hub->descriptor->u.ss.bHubHdrDecLat * 100;
+
+ /*
+ * tMEL2. Time to submit PING packet. Sum of tTPTransmissionDelay for
+ * each link + wHubDelay for each hub. Add only for last link.
+ * tMEL4, the time for PING_RESPONSE to traverse upstream is similar.
+ * Multiply by 2 to include it as well.
+ */
+ total_mel += (__le16_to_cpu(hub->descriptor->u.ss.wHubDelay) +
+ USB_TP_TRANSMISSION_DELAY) * 2;
+
+ /*
+ * tMEL3, tPingResponse. Time taken by device to generate PING_RESPONSE
+ * after receiving PING. Also add 2100ns as stated in USB 3.1 C 1.5.2.4
+ * to cover the delay if the PING_RESPONSE is queued behind a Max Packet
+ * Size DP.
+ * Note these delays should be added only once for the entire path, so
+ * add them to the MEL of the device connected to the roothub.
+ */
+ if (!hub->hdev->parent)
+ total_mel += USB_PING_RESPONSE_TIME + 2100;
+
+ udev_lpm_params->mel = total_mel;
+}
+
+/*
+ * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
+ * a transition from either U1 or U2.
+ */
+static void usb_set_lpm_pel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency,
+ unsigned int port_to_port_exit_latency)
+{
+ unsigned int first_link_pel;
+ unsigned int hub_pel;
+
+ /*
+ * First, the device sends an LFPS to transition the link between the
+ * device and the parent hub into U0. The exit latency is the bigger of
+ * the device exit latency or the hub exit latency.
+ */
+ if (udev_exit_latency > hub_exit_latency)
+ first_link_pel = udev_exit_latency * 1000;
+ else
+ first_link_pel = hub_exit_latency * 1000;
+
+ /*
+ * When the hub starts to receive the LFPS, there is a slight delay for
+ * it to figure out that one of the ports is sending an LFPS. Then it
+ * will forward the LFPS to its upstream link. The exit latency is the
+ * delay, plus the PEL that we calculated for this hub.
+ */
+ hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
+
+ /*
+ * According to figure C-7 in the USB 3.0 spec, the PEL for this device
+ * is the greater of the two exit latencies.
+ */
+ if (first_link_pel > hub_pel)
+ udev_lpm_params->pel = first_link_pel;
+ else
+ udev_lpm_params->pel = hub_pel;
+}
+
+/*
+ * Set the System Exit Latency (SEL) to indicate the total worst-case time from
+ * when a device initiates a transition to U0, until when it will receive the
+ * first packet from the host controller.
+ *
+ * Section C.1.5.1 describes the four components to this:
+ * - t1: device PEL
+ * - t2: time for the ERDY to make it from the device to the host.
+ * - t3: a host-specific delay to process the ERDY.
+ * - t4: time for the packet to make it from the host to the device.
+ *
+ * t3 is specific to both the xHCI host and the platform the host is integrated
+ * into. The Intel HW folks have said it's negligible, FIXME if a different
+ * vendor says otherwise.
+ */
+static void usb_set_lpm_sel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params)
+{
+ struct usb_device *parent;
+ unsigned int num_hubs;
+ unsigned int total_sel;
+
+ /* t1 = device PEL */
+ total_sel = udev_lpm_params->pel;
+ /* How many external hubs are in between the device & the root port. */
+ for (parent = udev->parent, num_hubs = 0; parent->parent;
+ parent = parent->parent)
+ num_hubs++;
+ /* t2 = 2.1us + 250ns * (num_hubs - 1) */
+ if (num_hubs > 0)
+ total_sel += 2100 + 250 * (num_hubs - 1);
+
+ /* t4 = 250ns * num_hubs */
+ total_sel += 250 * num_hubs;
+
+ udev_lpm_params->sel = total_sel;
+}
+
+static void usb_set_lpm_parameters(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+ unsigned int port_to_port_delay;
+ unsigned int udev_u1_del;
+ unsigned int udev_u2_del;
+ unsigned int hub_u1_del;
+ unsigned int hub_u2_del;
+
+ if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
+ return;
+
+ hub = usb_hub_to_struct_hub(udev->parent);
+ /* It doesn't take time to transition the roothub into U0, since it
+ * doesn't have an upstream link.
+ */
+ if (!hub)
+ return;
+
+ udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
+ udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat);
+ hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
+ hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat);
+
+ usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del);
+
+ usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del);
+
+ /*
+ * Appendix C, section C.2.2.2, says that there is a slight delay from
+ * when the parent hub notices the downstream port is trying to
+ * transition to U0 to when the hub initiates a U0 transition on its
+ * upstream port. The section says the delays are tPort2PortU1EL and
+ * tPort2PortU2EL, but it doesn't define what they are.
+ *
+ * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
+ * about the same delays. Use the maximum delay calculations from those
+ * sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For
+ * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I
+ * assume the device exit latencies they are talking about are the hub
+ * exit latencies.
+ *
+ * What do we do if the U2 exit latency is less than the U1 exit
+ * latency? It's possible, although not likely...
+ */
+ port_to_port_delay = 1;
+
+ usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del,
+ port_to_port_delay);
+
+ if (hub_u2_del > hub_u1_del)
+ port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
+ else
+ port_to_port_delay = 1 + hub_u1_del;
+
+ usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del,
+ port_to_port_delay);
+
+ /* Now that we've got PEL, calculate SEL. */
+ usb_set_lpm_sel(udev, &udev->u1_params);
+ usb_set_lpm_sel(udev, &udev->u2_params);
+}
+
+/* USB 2.0 spec Section 11.24.4.5 */
+static int get_hub_descriptor(struct usb_device *hdev,
+ struct usb_hub_descriptor *desc)
+{
+ int i, ret, size;
+ unsigned dtype;
+
+ if (hub_is_superspeed(hdev)) {
+ dtype = USB_DT_SS_HUB;
+ size = USB_DT_SS_HUB_SIZE;
+ } else {
+ dtype = USB_DT_HUB;
+ size = sizeof(struct usb_hub_descriptor);
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+ dtype << 8, 0, desc, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (hub_is_superspeed(hdev)) {
+ if (ret == size)
+ return ret;
+ } else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) {
+ /* Make sure we have the DeviceRemovable field. */
+ size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1;
+ if (ret < size)
+ return -EMSGSIZE;
+ return ret;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.1
+ */
+static int clear_hub_feature(struct usb_device *hdev, int feature)
+{
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.2
+ */
+int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature)
+{
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
+ NULL, 0, 1000);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.13
+ */
+static int set_port_feature(struct usb_device *hdev, int port1, int feature)
+{
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
+ NULL, 0, 1000);
+}
+
+static char *to_led_name(int selector)
+{
+ switch (selector) {
+ case HUB_LED_AMBER:
+ return "amber";
+ case HUB_LED_GREEN:
+ return "green";
+ case HUB_LED_OFF:
+ return "off";
+ case HUB_LED_AUTO:
+ return "auto";
+ default:
+ return "??";
+ }
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7
+ * for info about using port indicators
+ */
+static void set_port_led(struct usb_hub *hub, int port1, int selector)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ int status;
+
+ status = set_port_feature(hub->hdev, (selector << 8) | port1,
+ USB_PORT_FEAT_INDICATOR);
+ dev_dbg(&port_dev->dev, "indicator %s status %d\n",
+ to_led_name(selector), status);
+}
+
+#define LED_CYCLE_PERIOD ((2*HZ)/3)
+
+static void led_work(struct work_struct *work)
+{
+ struct usb_hub *hub =
+ container_of(work, struct usb_hub, leds.work);
+ struct usb_device *hdev = hub->hdev;
+ unsigned i;
+ unsigned changed = 0;
+ int cursor = -1;
+
+ if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing)
+ return;
+
+ for (i = 0; i < hdev->maxchild; i++) {
+ unsigned selector, mode;
+
+ /* 30%-50% duty cycle */
+
+ switch (hub->indicator[i]) {
+ /* cycle marker */
+ case INDICATOR_CYCLE:
+ cursor = i;
+ selector = HUB_LED_AUTO;
+ mode = INDICATOR_AUTO;
+ break;
+ /* blinking green = sw attention */
+ case INDICATOR_GREEN_BLINK:
+ selector = HUB_LED_GREEN;
+ mode = INDICATOR_GREEN_BLINK_OFF;
+ break;
+ case INDICATOR_GREEN_BLINK_OFF:
+ selector = HUB_LED_OFF;
+ mode = INDICATOR_GREEN_BLINK;
+ break;
+ /* blinking amber = hw attention */
+ case INDICATOR_AMBER_BLINK:
+ selector = HUB_LED_AMBER;
+ mode = INDICATOR_AMBER_BLINK_OFF;
+ break;
+ case INDICATOR_AMBER_BLINK_OFF:
+ selector = HUB_LED_OFF;
+ mode = INDICATOR_AMBER_BLINK;
+ break;
+ /* blink green/amber = reserved */
+ case INDICATOR_ALT_BLINK:
+ selector = HUB_LED_GREEN;
+ mode = INDICATOR_ALT_BLINK_OFF;
+ break;
+ case INDICATOR_ALT_BLINK_OFF:
+ selector = HUB_LED_AMBER;
+ mode = INDICATOR_ALT_BLINK;
+ break;
+ default:
+ continue;
+ }
+ if (selector != HUB_LED_AUTO)
+ changed = 1;
+ set_port_led(hub, i + 1, selector);
+ hub->indicator[i] = mode;
+ }
+ if (!changed && blinkenlights) {
+ cursor++;
+ cursor %= hdev->maxchild;
+ set_port_led(hub, cursor + 1, HUB_LED_GREEN);
+ hub->indicator[cursor] = INDICATOR_CYCLE;
+ changed++;
+ }
+ if (changed)
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, LED_CYCLE_PERIOD);
+}
+
+/* use a short timeout for hub/port status fetches */
+#define USB_STS_TIMEOUT 1000
+#define USB_STS_RETRIES 5
+
+/*
+ * USB 2.0 spec Section 11.24.2.6
+ */
+static int get_hub_status(struct usb_device *hdev,
+ struct usb_hub_status *data)
+{
+ int i, status = -ETIMEDOUT;
+
+ for (i = 0; i < USB_STS_RETRIES &&
+ (status == -ETIMEDOUT || status == -EPIPE); i++) {
+ status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+ data, sizeof(*data), USB_STS_TIMEOUT);
+ }
+ return status;
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.7
+ * USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6
+ */
+static int get_port_status(struct usb_device *hdev, int port1,
+ void *data, u16 value, u16 length)
+{
+ int i, status = -ETIMEDOUT;
+
+ for (i = 0; i < USB_STS_RETRIES &&
+ (status == -ETIMEDOUT || status == -EPIPE); i++) {
+ status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
+ port1, data, length, USB_STS_TIMEOUT);
+ }
+ return status;
+}
+
+static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
+ u16 *status, u16 *change, u32 *ext_status)
+{
+ int ret;
+ int len = 4;
+
+ if (type != HUB_PORT_STATUS)
+ len = 8;
+
+ mutex_lock(&hub->status_mutex);
+ ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
+ if (ret < len) {
+ if (ret != -ENODEV)
+ dev_err(hub->intfdev,
+ "%s failed (err = %d)\n", __func__, ret);
+ if (ret >= 0)
+ ret = -EIO;
+ } else {
+ *status = le16_to_cpu(hub->status->port.wPortStatus);
+ *change = le16_to_cpu(hub->status->port.wPortChange);
+ if (type != HUB_PORT_STATUS && ext_status)
+ *ext_status = le32_to_cpu(
+ hub->status->port.dwExtPortStatus);
+ ret = 0;
+ }
+ mutex_unlock(&hub->status_mutex);
+ return ret;
+}
+
+static int hub_port_status(struct usb_hub *hub, int port1,
+ u16 *status, u16 *change)
+{
+ return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
+ status, change, NULL);
+}
+
+static void kick_hub_wq(struct usb_hub *hub)
+{
+ struct usb_interface *intf;
+
+ if (hub->disconnected || work_pending(&hub->events))
+ return;
+
+ /*
+ * Suppress autosuspend until the event is proceed.
+ *
+ * Be careful and make sure that the symmetric operation is
+ * always called. We are here only when there is no pending
+ * work for this hub. Therefore put the interface either when
+ * the new work is called or when it is canceled.
+ */
+ intf = to_usb_interface(hub->intfdev);
+ usb_autopm_get_interface_no_resume(intf);
+ kref_get(&hub->kref);
+
+ if (queue_work(hub_wq, &hub->events))
+ return;
+
+ /* the work has already been scheduled */
+ usb_autopm_put_interface_async(intf);
+ kref_put(&hub->kref, hub_release);
+}
+
+void usb_kick_hub_wq(struct usb_device *hdev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+
+ if (hub)
+ kick_hub_wq(hub);
+}
+
+/*
+ * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
+ * Notification, which indicates it had initiated remote wakeup.
+ *
+ * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
+ * device initiates resume, so the USB core will not receive notice of the
+ * resume through the normal hub interrupt URB.
+ */
+void usb_wakeup_notification(struct usb_device *hdev,
+ unsigned int portnum)
+{
+ struct usb_hub *hub;
+ struct usb_port *port_dev;
+
+ if (!hdev)
+ return;
+
+ hub = usb_hub_to_struct_hub(hdev);
+ if (hub) {
+ port_dev = hub->ports[portnum - 1];
+ if (port_dev && port_dev->child)
+ pm_wakeup_event(&port_dev->child->dev, 0);
+
+ set_bit(portnum, hub->wakeup_bits);
+ kick_hub_wq(hub);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_wakeup_notification);
+
+/* completion function, fires on port status changes and various faults */
+static void hub_irq(struct urb *urb)
+{
+ struct usb_hub *hub = urb->context;
+ int status = urb->status;
+ unsigned i;
+ unsigned long bits;
+
+ switch (status) {
+ case -ENOENT: /* synchronous unlink */
+ case -ECONNRESET: /* async unlink */
+ case -ESHUTDOWN: /* hardware going away */
+ return;
+
+ default: /* presumably an error */
+ /* Cause a hub reset after 10 consecutive errors */
+ dev_dbg(hub->intfdev, "transfer --> %d\n", status);
+ if ((++hub->nerrors < 10) || hub->error)
+ goto resubmit;
+ hub->error = status;
+ /* FALL THROUGH */
+
+ /* let hub_wq handle things */
+ case 0: /* we got data: port status changed */
+ bits = 0;
+ for (i = 0; i < urb->actual_length; ++i)
+ bits |= ((unsigned long) ((*hub->buffer)[i]))
+ << (i*8);
+ hub->event_bits[0] = bits;
+ break;
+ }
+
+ hub->nerrors = 0;
+
+ /* Something happened, let hub_wq figure it out */
+ kick_hub_wq(hub);
+
+resubmit:
+ if (hub->quiescing)
+ return;
+
+ status = usb_submit_urb(hub->urb, GFP_ATOMIC);
+ if (status != 0 && status != -ENODEV && status != -EPERM)
+ dev_err(hub->intfdev, "resubmit --> %d\n", status);
+}
+
+/* USB 2.0 spec Section 11.24.2.3 */
+static inline int
+hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt)
+{
+ /* Need to clear both directions for control ep */
+ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) {
+ int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
+ devinfo ^ 0x8000, tt, NULL, 0, 1000);
+ if (status)
+ return status;
+ }
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
+ tt, NULL, 0, 1000);
+}
+
+/*
+ * enumeration blocks hub_wq for a long time. we use keventd instead, since
+ * long blocking there is the exception, not the rule. accordingly, HCDs
+ * talking to TTs must queue control transfers (not just bulk and iso), so
+ * both can talk to the same hub concurrently.
+ */
+static void hub_tt_work(struct work_struct *work)
+{
+ struct usb_hub *hub =
+ container_of(work, struct usb_hub, tt.clear_work);
+ unsigned long flags;
+
+ spin_lock_irqsave(&hub->tt.lock, flags);
+ while (!list_empty(&hub->tt.clear_list)) {
+ struct list_head *next;
+ struct usb_tt_clear *clear;
+ struct usb_device *hdev = hub->hdev;
+ const struct hc_driver *drv;
+ int status;
+
+ next = hub->tt.clear_list.next;
+ clear = list_entry(next, struct usb_tt_clear, clear_list);
+ list_del(&clear->clear_list);
+
+ /* drop lock so HCD can concurrently report other TT errors */
+ spin_unlock_irqrestore(&hub->tt.lock, flags);
+ status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt);
+ if (status && status != -ENODEV)
+ dev_err(&hdev->dev,
+ "clear tt %d (%04x) error %d\n",
+ clear->tt, clear->devinfo, status);
+
+ /* Tell the HCD, even if the operation failed */
+ drv = clear->hcd->driver;
+ if (drv->clear_tt_buffer_complete)
+ (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep);
+
+ kfree(clear);
+ spin_lock_irqsave(&hub->tt.lock, flags);
+ }
+ spin_unlock_irqrestore(&hub->tt.lock, flags);
+}
+
+/**
+ * usb_hub_set_port_power - control hub port's power state
+ * @hdev: USB device belonging to the usb hub
+ * @hub: target hub
+ * @port1: port index
+ * @set: expected status
+ *
+ * call this function to control port's power via setting or
+ * clearing the port's PORT_POWER feature.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
+ int port1, bool set)
+{
+ int ret;
+
+ if (set)
+ ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+ else
+ ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+
+ if (ret)
+ return ret;
+
+ if (set)
+ set_bit(port1, hub->power_bits);
+ else
+ clear_bit(port1, hub->power_bits);
+ return 0;
+}
+
+/**
+ * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
+ * @urb: an URB associated with the failed or incomplete split transaction
+ *
+ * High speed HCDs use this to tell the hub driver that some split control or
+ * bulk transaction failed in a way that requires clearing internal state of
+ * a transaction translator. This is normally detected (and reported) from
+ * interrupt context.
+ *
+ * It may not be possible for that hub to handle additional full (or low)
+ * speed transactions until that state is fully cleared out.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+int usb_hub_clear_tt_buffer(struct urb *urb)
+{
+ struct usb_device *udev = urb->dev;
+ int pipe = urb->pipe;
+ struct usb_tt *tt = udev->tt;
+ unsigned long flags;
+ struct usb_tt_clear *clear;
+
+ /* we've got to cope with an arbitrary number of pending TT clears,
+ * since each TT has "at least two" buffers that can need it (and
+ * there can be many TTs per hub). even if they're uncommon.
+ */
+ clear = kmalloc(sizeof *clear, GFP_ATOMIC);
+ if (clear == NULL) {
+ dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
+ /* FIXME recover somehow ... RESET_TT? */
+ return -ENOMEM;
+ }
+
+ /* info that CLEAR_TT_BUFFER needs */
+ clear->tt = tt->multi ? udev->ttport : 1;
+ clear->devinfo = usb_pipeendpoint (pipe);
+ clear->devinfo |= udev->devnum << 4;
+ clear->devinfo |= usb_pipecontrol(pipe)
+ ? (USB_ENDPOINT_XFER_CONTROL << 11)
+ : (USB_ENDPOINT_XFER_BULK << 11);
+ if (usb_pipein(pipe))
+ clear->devinfo |= 1 << 15;
+
+ /* info for completion callback */
+ clear->hcd = bus_to_hcd(udev->bus);
+ clear->ep = urb->ep;
+
+ /* tell keventd to clear state for this TT */
+ spin_lock_irqsave(&tt->lock, flags);
+ list_add_tail(&clear->clear_list, &tt->clear_list);
+ schedule_work(&tt->clear_work);
+ spin_unlock_irqrestore(&tt->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
+
+static void hub_power_on(struct usb_hub *hub, bool do_delay)
+{
+ int port1;
+
+ /* Enable power on each port. Some hubs have reserved values
+ * of LPSM (> 2) in their descriptors, even though they are
+ * USB 2.0 hubs. Some hubs do not implement port-power switching
+ * but only emulate it. In all cases, the ports won't work
+ * unless we send these messages to the hub.
+ */
+ if (hub_is_port_power_switchable(hub))
+ dev_dbg(hub->intfdev, "enabling power on all ports\n");
+ else
+ dev_dbg(hub->intfdev, "trying to enable port power on "
+ "non-switchable hub\n");
+ for (port1 = 1; port1 <= hub->hdev->maxchild; port1++)
+ if (test_bit(port1, hub->power_bits))
+ set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+ else
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_POWER);
+ if (do_delay)
+ msleep(hub_power_on_good_delay(hub));
+}
+
+static int hub_hub_status(struct usb_hub *hub,
+ u16 *status, u16 *change)
+{
+ int ret;
+
+ mutex_lock(&hub->status_mutex);
+ ret = get_hub_status(hub->hdev, &hub->status->hub);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ dev_err(hub->intfdev,
+ "%s failed (err = %d)\n", __func__, ret);
+ } else {
+ *status = le16_to_cpu(hub->status->hub.wHubStatus);
+ *change = le16_to_cpu(hub->status->hub.wHubChange);
+ ret = 0;
+ }
+ mutex_unlock(&hub->status_mutex);
+ return ret;
+}
+
+static int hub_set_port_link_state(struct usb_hub *hub, int port1,
+ unsigned int link_status)
+{
+ return set_port_feature(hub->hdev,
+ port1 | (link_status << 3),
+ USB_PORT_FEAT_LINK_STATE);
+}
+
+/*
+ * Disable a port and mark a logical connect-change event, so that some
+ * time later hub_wq will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+{
+ dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n");
+ hub_port_disable(hub, port1, 1);
+
+ /* FIXME let caller ask to power down the port:
+ * - some devices won't enumerate without a VBUS power cycle
+ * - SRP saves power that way
+ * - ... new call, TBD ...
+ * That's easy if this hub can switch power per-port, and
+ * hub_wq reactivates the port later (timer, SRP, etc).
+ * Powerdown must be optional, because of reset/DFU.
+ */
+
+ set_bit(port1, hub->change_bits);
+ kick_hub_wq(hub);
+}
+
+/**
+ * usb_remove_device - disable a device's port on its parent hub
+ * @udev: device to be disabled and removed
+ * Context: @udev locked, must be able to sleep.
+ *
+ * After @udev's port has been disabled, hub_wq is notified and it will
+ * see that the device has been disconnected. When the device is
+ * physically unplugged and something is plugged in, the events will
+ * be received and processed normally.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+int usb_remove_device(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+ struct usb_interface *intf;
+ int ret;
+
+ if (!udev->parent) /* Can't remove a root hub */
+ return -EINVAL;
+ hub = usb_hub_to_struct_hub(udev->parent);
+ intf = to_usb_interface(hub->intfdev);
+
+ ret = usb_autopm_get_interface(intf);
+ if (ret < 0)
+ return ret;
+
+ set_bit(udev->portnum, hub->removed_bits);
+ hub_port_logical_disconnect(hub, udev->portnum);
+ usb_autopm_put_interface(intf);
+ return 0;
+}
+
+enum hub_activation_type {
+ HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */
+ HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
+};
+
+static void hub_init_func2(struct work_struct *ws);
+static void hub_init_func3(struct work_struct *ws);
+
+static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
+{
+ struct usb_device *hdev = hub->hdev;
+ struct usb_hcd *hcd;
+ int ret;
+ int port1;
+ int status;
+ bool need_debounce_delay = false;
+ unsigned delay;
+
+ /* Continue a partial initialization */
+ if (type == HUB_INIT2 || type == HUB_INIT3) {
+ device_lock(&hdev->dev);
+
+ /* Was the hub disconnected while we were waiting? */
+ if (hub->disconnected)
+ goto disconnected;
+ if (type == HUB_INIT2)
+ goto init2;
+ goto init3;
+ }
+ kref_get(&hub->kref);
+
+ /* The superspeed hub except for root hub has to use Hub Depth
+ * value as an offset into the route string to locate the bits
+ * it uses to determine the downstream port number. So hub driver
+ * should send a set hub depth request to superspeed hub after
+ * the superspeed hub is set configuration in initialization or
+ * reset procedure.
+ *
+ * After a resume, port power should still be on.
+ * For any other type of activation, turn it on.
+ */
+ if (type != HUB_RESUME) {
+ if (hdev->parent && hub_is_superspeed(hdev)) {
+ ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ HUB_SET_DEPTH, USB_RT_HUB,
+ hdev->level - 1, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (ret < 0)
+ dev_err(hub->intfdev,
+ "set hub depth failed\n");
+ }
+
+ /* Speed up system boot by using a delayed_work for the
+ * hub's initial power-up delays. This is pretty awkward
+ * and the implementation looks like a home-brewed sort of
+ * setjmp/longjmp, but it saves at least 100 ms for each
+ * root hub (assuming usbcore is compiled into the kernel
+ * rather than as a module). It adds up.
+ *
+ * This can't be done for HUB_RESUME or HUB_RESET_RESUME
+ * because for those activation types the ports have to be
+ * operational when we return. In theory this could be done
+ * for HUB_POST_RESET, but it's easier not to.
+ */
+ if (type == HUB_INIT) {
+ delay = hub_power_on_good_delay(hub);
+
+ hub_power_on(hub, false);
+ INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->init_work,
+ msecs_to_jiffies(delay));
+
+ /* Suppress autosuspend until init is done */
+ usb_autopm_get_interface_no_resume(
+ to_usb_interface(hub->intfdev));
+ return; /* Continues at init2: below */
+ } else if (type == HUB_RESET_RESUME) {
+ /* The internal host controller state for the hub device
+ * may be gone after a host power loss on system resume.
+ * Update the device's info so the HW knows it's a hub.
+ */
+ hcd = bus_to_hcd(hdev->bus);
+ if (hcd->driver->update_hub_device) {
+ 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");
+ }
+ }
+ hub_power_on(hub, true);
+ } else {
+ hub_power_on(hub, true);
+ }
+ /* Give some time on remote wakeup to let links to transit to U0 */
+ } else if (hub_is_superspeed(hub->hdev))
+ msleep(20);
+
+ init2:
+
+ /*
+ * Check each port and set hub->change_bits to let hub_wq know
+ * which ports need attention.
+ */
+ for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ u16 portstatus, portchange;
+
+ portstatus = portchange = 0;
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (status)
+ goto abort;
+
+ if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
+ dev_dbg(&port_dev->dev, "status %04x change %04x\n",
+ portstatus, portchange);
+
+ /*
+ * After anything other than HUB_RESUME (i.e., initialization
+ * or any sort of reset), every port should be disabled.
+ * Unconnected ports should likewise be disabled (paranoia),
+ * and so should ports for which we have no usb_device.
+ */
+ if ((portstatus & USB_PORT_STAT_ENABLE) && (
+ type != HUB_RESUME ||
+ !(portstatus & USB_PORT_STAT_CONNECTION) ||
+ !udev ||
+ udev->state == USB_STATE_NOTATTACHED)) {
+ /*
+ * USB3 protocol ports will automatically transition
+ * to Enabled state when detect an USB3.0 device attach.
+ * Do not disable USB3 protocol ports, just pretend
+ * power was lost
+ */
+ portstatus &= ~USB_PORT_STAT_ENABLE;
+ if (!hub_is_superspeed(hdev))
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_ENABLE);
+ }
+
+ /* Make sure a warm-reset request is handled by port_event */
+ if (type == HUB_RESUME &&
+ hub_port_warm_reset_required(hub, port1, portstatus))
+ set_bit(port1, hub->event_bits);
+
+ /*
+ * Add debounce if USB3 link is in polling/link training state.
+ * Link will automatically transition to Enabled state after
+ * link training completes.
+ */
+ if (hub_is_superspeed(hdev) &&
+ ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_POLLING))
+ need_debounce_delay = true;
+
+ /* Clear status-change flags; we'll debounce later */
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ need_debounce_delay = true;
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ need_debounce_delay = true;
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+ }
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ need_debounce_delay = true;
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_RESET);
+ }
+ if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
+ hub_is_superspeed(hub->hdev)) {
+ need_debounce_delay = true;
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ }
+ /* We can forget about a "removed" device when there's a
+ * physical disconnect or the connect status changes.
+ */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
+ (portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_bit(port1, hub->removed_bits);
+
+ if (!udev || udev->state == USB_STATE_NOTATTACHED) {
+ /* Tell hub_wq to disconnect the device or
+ * check for a new connection or over current condition.
+ * Based on USB2.0 Spec Section 11.12.5,
+ * C_PORT_OVER_CURRENT could be set while
+ * 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);
+
+ } else if (portstatus & USB_PORT_STAT_ENABLE) {
+ bool port_resumed = (portstatus &
+ USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_U0;
+ /* The power session apparently survived the resume.
+ * If there was an overcurrent or suspend change
+ * (i.e., remote wakeup request), have hub_wq
+ * take care of it. Look at the port link state
+ * for USB 3.0 hubs, since they don't have a suspend
+ * change bit, and they don't set the port link change
+ * bit on device-initiated resume.
+ */
+ if (portchange || (hub_is_superspeed(hub->hdev) &&
+ port_resumed))
+ set_bit(port1, hub->event_bits);
+
+ } else if (udev->persist_enabled) {
+#ifdef CONFIG_PM
+ udev->reset_resume = 1;
+#endif
+ /* Don't set the change_bits when the device
+ * was powered off.
+ */
+ if (test_bit(port1, hub->power_bits))
+ set_bit(port1, hub->change_bits);
+
+ } else {
+ /* The power session is gone; tell hub_wq */
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ set_bit(port1, hub->change_bits);
+ }
+ }
+
+ /* If no port-status-change flags were set, we don't need any
+ * debouncing. If flags were set we can try to debounce the
+ * ports all at once right now, instead of letting hub_wq do them
+ * one at a time later on.
+ *
+ * If any port-status changes do occur during this delay, hub_wq
+ * will see them later and handle them normally.
+ */
+ if (need_debounce_delay) {
+ delay = HUB_DEBOUNCE_STABLE;
+
+ /* Don't do a long sleep inside a workqueue routine */
+ if (type == HUB_INIT2) {
+ INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->init_work,
+ msecs_to_jiffies(delay));
+ device_unlock(&hdev->dev);
+ return; /* Continues at init3: below */
+ } else {
+ msleep(delay);
+ }
+ }
+ init3:
+ hub->quiescing = 0;
+
+ status = usb_submit_urb(hub->urb, GFP_NOIO);
+ if (status < 0)
+ dev_err(hub->intfdev, "activate --> %d\n", status);
+ if (hub->has_indicators && blinkenlights)
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, LED_CYCLE_PERIOD);
+
+ /* Scan all ports that need attention */
+ kick_hub_wq(hub);
+ abort:
+ if (type == HUB_INIT2 || type == HUB_INIT3) {
+ /* Allow autosuspend if it was suppressed */
+ disconnected:
+ usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
+ device_unlock(&hdev->dev);
+ }
+
+ kref_put(&hub->kref, hub_release);
+}
+
+/* Implement the continuations for the delays above */
+static void hub_init_func2(struct work_struct *ws)
+{
+ struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
+
+ hub_activate(hub, HUB_INIT2);
+}
+
+static void hub_init_func3(struct work_struct *ws)
+{
+ struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
+
+ hub_activate(hub, HUB_INIT3);
+}
+
+enum hub_quiescing_type {
+ HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND
+};
+
+static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
+{
+ struct usb_device *hdev = hub->hdev;
+ int i;
+
+ /* hub_wq and related activity won't re-trigger */
+ hub->quiescing = 1;
+
+ if (type != HUB_SUSPEND) {
+ /* Disconnect all the children */
+ for (i = 0; i < hdev->maxchild; ++i) {
+ if (hub->ports[i]->child)
+ usb_disconnect(&hub->ports[i]->child);
+ }
+ }
+
+ /* Stop hub_wq and related activity */
+ usb_kill_urb(hub->urb);
+ if (hub->has_indicators)
+ cancel_delayed_work_sync(&hub->leds);
+ if (hub->tt.hub)
+ flush_work(&hub->tt.clear_work);
+}
+
+static void hub_pm_barrier_for_all_ports(struct usb_hub *hub)
+{
+ int i;
+
+ for (i = 0; i < hub->hdev->maxchild; ++i)
+ pm_runtime_barrier(&hub->ports[i]->dev);
+}
+
+/* caller has locked the hub device */
+static int hub_pre_reset(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ hub_quiesce(hub, HUB_PRE_RESET);
+ hub->in_reset = 1;
+ hub_pm_barrier_for_all_ports(hub);
+ return 0;
+}
+
+/* caller has locked the hub device */
+static int hub_post_reset(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ hub->in_reset = 0;
+ hub_pm_barrier_for_all_ports(hub);
+ hub_activate(hub, HUB_POST_RESET);
+ return 0;
+}
+
+static int hub_configure(struct usb_hub *hub,
+ struct usb_endpoint_descriptor *endpoint)
+{
+ struct usb_hcd *hcd;
+ struct usb_device *hdev = hub->hdev;
+ struct device *hub_dev = hub->intfdev;
+ u16 hubstatus, hubchange;
+ u16 wHubCharacteristics;
+ unsigned int pipe;
+ int maxp, ret, i;
+ char *message = "out of memory";
+ unsigned unit_load;
+ unsigned full_load;
+ unsigned maxchild;
+
+ hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
+ if (!hub->buffer) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
+ if (!hub->status) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ mutex_init(&hub->status_mutex);
+
+ hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+ if (!hub->descriptor) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* Request the entire hub descriptor.
+ * hub->descriptor can handle USB_MAXCHILDREN ports,
+ * but a (non-SS) hub can/will return fewer bytes here.
+ */
+ ret = get_hub_descriptor(hdev, hub->descriptor);
+ if (ret < 0) {
+ message = "can't read hub descriptor";
+ goto fail;
+ }
+
+ maxchild = USB_MAXCHILDREN;
+ if (hub_is_superspeed(hdev))
+ maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS);
+
+ if (hub->descriptor->bNbrPorts > maxchild) {
+ message = "hub has too many ports!";
+ ret = -ENODEV;
+ goto fail;
+ } else if (hub->descriptor->bNbrPorts == 0) {
+ message = "hub doesn't have any ports!";
+ ret = -ENODEV;
+ 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");
+
+ hub->ports = kcalloc(maxchild, sizeof(struct usb_port *), GFP_KERNEL);
+ if (!hub->ports) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+ if (hub_is_superspeed(hdev)) {
+ unit_load = 150;
+ full_load = 900;
+ } else {
+ unit_load = 100;
+ full_load = 500;
+ }
+
+ /* FIXME for USB 3.0, skip for now */
+ if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
+ !(hub_is_superspeed(hdev))) {
+ char portstr[USB_MAXCHILDREN + 1];
+
+ for (i = 0; i < maxchild; i++)
+ portstr[i] = hub->descriptor->u.hs.DeviceRemovable
+ [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+ ? 'F' : 'R';
+ portstr[maxchild] = 0;
+ dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
+ } else
+ dev_dbg(hub_dev, "standalone hub\n");
+
+ switch (wHubCharacteristics & HUB_CHAR_LPSM) {
+ case HUB_CHAR_COMMON_LPSM:
+ dev_dbg(hub_dev, "ganged power switching\n");
+ break;
+ case HUB_CHAR_INDV_PORT_LPSM:
+ dev_dbg(hub_dev, "individual port power switching\n");
+ break;
+ case HUB_CHAR_NO_LPSM:
+ case HUB_CHAR_LPSM:
+ dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
+ break;
+ }
+
+ switch (wHubCharacteristics & HUB_CHAR_OCPM) {
+ case HUB_CHAR_COMMON_OCPM:
+ dev_dbg(hub_dev, "global over-current protection\n");
+ break;
+ case HUB_CHAR_INDV_PORT_OCPM:
+ dev_dbg(hub_dev, "individual port over-current protection\n");
+ break;
+ case HUB_CHAR_NO_OCPM:
+ case HUB_CHAR_OCPM:
+ dev_dbg(hub_dev, "no over-current protection\n");
+ break;
+ }
+
+ spin_lock_init(&hub->tt.lock);
+ INIT_LIST_HEAD(&hub->tt.clear_list);
+ INIT_WORK(&hub->tt.clear_work, hub_tt_work);
+ switch (hdev->descriptor.bDeviceProtocol) {
+ case USB_HUB_PR_FS:
+ break;
+ case USB_HUB_PR_HS_SINGLE_TT:
+ dev_dbg(hub_dev, "Single TT\n");
+ hub->tt.hub = hdev;
+ break;
+ case USB_HUB_PR_HS_MULTI_TT:
+ ret = usb_set_interface(hdev, 0, 1);
+ if (ret == 0) {
+ dev_dbg(hub_dev, "TT per port\n");
+ hub->tt.multi = 1;
+ } else
+ dev_err(hub_dev, "Using single TT (err %d)\n",
+ ret);
+ hub->tt.hub = hdev;
+ break;
+ case USB_HUB_PR_SS:
+ /* USB 3.0 hubs don't have a TT */
+ break;
+ default:
+ dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
+ hdev->descriptor.bDeviceProtocol);
+ break;
+ }
+
+ /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
+ switch (wHubCharacteristics & HUB_CHAR_TTTT) {
+ case HUB_TTTT_8_BITS:
+ if (hdev->descriptor.bDeviceProtocol != 0) {
+ hub->tt.think_time = 666;
+ dev_dbg(hub_dev, "TT requires at most %d "
+ "FS bit times (%d ns)\n",
+ 8, hub->tt.think_time);
+ }
+ break;
+ case HUB_TTTT_16_BITS:
+ hub->tt.think_time = 666 * 2;
+ dev_dbg(hub_dev, "TT requires at most %d "
+ "FS bit times (%d ns)\n",
+ 16, hub->tt.think_time);
+ break;
+ case HUB_TTTT_24_BITS:
+ hub->tt.think_time = 666 * 3;
+ dev_dbg(hub_dev, "TT requires at most %d "
+ "FS bit times (%d ns)\n",
+ 24, hub->tt.think_time);
+ break;
+ case HUB_TTTT_32_BITS:
+ hub->tt.think_time = 666 * 4;
+ dev_dbg(hub_dev, "TT requires at most %d "
+ "FS bit times (%d ns)\n",
+ 32, hub->tt.think_time);
+ break;
+ }
+
+ /* probe() zeroes hub->indicator[] */
+ if (wHubCharacteristics & HUB_CHAR_PORTIND) {
+ hub->has_indicators = 1;
+ dev_dbg(hub_dev, "Port indicators are supported\n");
+ }
+
+ dev_dbg(hub_dev, "power on to power good time: %dms\n",
+ hub->descriptor->bPwrOn2PwrGood * 2);
+
+ /* power budgeting mostly matters with bus-powered hubs,
+ * and battery-powered root hubs (may provide just 8 mA).
+ */
+ ret = usb_get_std_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
+ if (ret) {
+ message = "can't get hub status";
+ goto fail;
+ }
+ hcd = bus_to_hcd(hdev->bus);
+ if (hdev == hdev->bus->root_hub) {
+ if (hcd->power_budget > 0)
+ hdev->bus_mA = hcd->power_budget;
+ else
+ hdev->bus_mA = full_load * maxchild;
+ if (hdev->bus_mA >= full_load)
+ hub->mA_per_port = full_load;
+ else {
+ hub->mA_per_port = hdev->bus_mA;
+ hub->limited_power = 1;
+ }
+ } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ int remaining = hdev->bus_mA -
+ hub->descriptor->bHubContrCurrent;
+
+ dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
+ hub->descriptor->bHubContrCurrent);
+ hub->limited_power = 1;
+
+ if (remaining < maxchild * unit_load)
+ dev_warn(hub_dev,
+ "insufficient power available "
+ "to use all downstream ports\n");
+ hub->mA_per_port = unit_load; /* 7.2.1 */
+
+ } else { /* Self-powered external hub */
+ /* FIXME: What about battery-powered external hubs that
+ * provide less current per port? */
+ hub->mA_per_port = full_load;
+ }
+ if (hub->mA_per_port < full_load)
+ dev_dbg(hub_dev, "%umA bus power budget for each child\n",
+ hub->mA_per_port);
+
+ ret = hub_hub_status(hub, &hubstatus, &hubchange);
+ if (ret < 0) {
+ message = "can't get hub status";
+ goto fail;
+ }
+
+ /* local power status reports aren't always correct */
+ if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
+ dev_dbg(hub_dev, "local power source is %s\n",
+ (hubstatus & HUB_STATUS_LOCAL_POWER)
+ ? "lost (inactive)" : "good");
+
+ if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
+ dev_dbg(hub_dev, "%sover-current condition exists\n",
+ (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+
+ /* set up the interrupt endpoint
+ * We use the EP's maxpacket size instead of (PORTS+1+7)/8
+ * bytes as USB2.0[11.12.3] says because some hubs are known
+ * to send more data (and thus cause overflow). For root hubs,
+ * maxpktsize is defined in hcd.c's fake endpoint descriptors
+ * to be big enough for at least USB_MAXCHILDREN ports. */
+ pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
+
+ if (maxp > sizeof(*hub->buffer))
+ maxp = sizeof(*hub->buffer);
+
+ hub->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hub->urb) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
+ hub, endpoint->bInterval);
+
+ /* maybe cycle the hub leds */
+ if (hub->has_indicators && blinkenlights)
+ hub->indicator[0] = INDICATOR_CYCLE;
+
+ mutex_lock(&usb_port_peer_mutex);
+ for (i = 0; i < maxchild; i++) {
+ ret = usb_hub_create_port_device(hub, i + 1);
+ if (ret < 0) {
+ dev_err(hub->intfdev,
+ "couldn't create port%d device.\n", i + 1);
+ break;
+ }
+ }
+ hdev->maxchild = i;
+ for (i = 0; i < hdev->maxchild; i++) {
+ struct usb_port *port_dev = hub->ports[i];
+
+ pm_runtime_put(&port_dev->dev);
+ }
+
+ mutex_unlock(&usb_port_peer_mutex);
+ if (ret < 0)
+ goto fail;
+
+ /* Update the HCD's internal representation of this hub before hub_wq
+ * starts getting port status changes for devices under the hub.
+ */
+ if (hcd->driver->update_hub_device) {
+ ret = hcd->driver->update_hub_device(hcd, hdev,
+ &hub->tt, GFP_KERNEL);
+ if (ret < 0) {
+ message = "can't update HCD hub info";
+ goto fail;
+ }
+ }
+
+ usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
+
+ hub_activate(hub, HUB_INIT);
+ return 0;
+
+fail:
+ dev_err(hub_dev, "config failed, %s (err %d)\n",
+ message, ret);
+ /* hub_disconnect() frees urb and descriptor */
+ return ret;
+}
+
+static void hub_release(struct kref *kref)
+{
+ struct usb_hub *hub = container_of(kref, struct usb_hub, kref);
+
+ usb_put_dev(hub->hdev);
+ usb_put_intf(to_usb_interface(hub->intfdev));
+ kfree(hub);
+}
+
+static unsigned highspeed_hubs;
+
+static void hub_disconnect(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+ struct usb_device *hdev = interface_to_usbdev(intf);
+ int port1;
+
+ /*
+ * Stop adding new hub events. We do not want to block here and thus
+ * will not try to remove any pending work item.
+ */
+ hub->disconnected = 1;
+
+ /* Disconnect all children and quiesce the hub */
+ hub->error = 0;
+ hub_quiesce(hub, HUB_DISCONNECT);
+
+ mutex_lock(&usb_port_peer_mutex);
+
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+ spin_lock_irq(&device_state_lock);
+ port1 = hdev->maxchild;
+ hdev->maxchild = 0;
+ usb_set_intfdata(intf, NULL);
+ spin_unlock_irq(&device_state_lock);
+
+ for (; port1 > 0; --port1)
+ usb_hub_remove_port_device(hub, port1);
+
+ mutex_unlock(&usb_port_peer_mutex);
+
+ if (hub->hdev->speed == USB_SPEED_HIGH)
+ highspeed_hubs--;
+
+ usb_free_urb(hub->urb);
+ kfree(hub->ports);
+ kfree(hub->descriptor);
+ kfree(hub->status);
+ kfree(hub->buffer);
+
+ pm_suspend_ignore_children(&intf->dev, false);
+
+ if (hub->quirk_disable_autosuspend)
+ usb_autopm_put_interface(intf);
+
+ kref_put(&hub->kref, hub_release);
+}
+
+static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
+{
+ /* Some hubs have a subclass of 1, which AFAICT according to the */
+ /* specs is not defined, but it works */
+ if (desc->desc.bInterfaceSubClass != 0 &&
+ desc->desc.bInterfaceSubClass != 1)
+ return false;
+
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (desc->desc.bNumEndpoints != 1)
+ return false;
+
+ /* If the first endpoint is not interrupt IN, we'd better punt! */
+ if (!usb_endpoint_is_int_in(&desc->endpoint[0].desc))
+ return false;
+
+ return true;
+}
+
+static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_host_interface *desc;
+ struct usb_device *hdev;
+ struct usb_hub *hub;
+
+ desc = intf->cur_altsetting;
+ hdev = interface_to_usbdev(intf);
+
+ /*
+ * Set default autosuspend delay as 0 to speedup bus suspend,
+ * based on the below considerations:
+ *
+ * - Unlike other drivers, the hub driver does not rely on the
+ * autosuspend delay to provide enough time to handle a wakeup
+ * event, and the submitted status URB is just to check future
+ * change on hub downstream ports, so it is safe to do it.
+ *
+ * - The patch might cause one or more auto supend/resume for
+ * below very rare devices when they are plugged into hub
+ * first time:
+ *
+ * devices having trouble initializing, and disconnect
+ * themselves from the bus and then reconnect a second
+ * or so later
+ *
+ * devices just for downloading firmware, and disconnects
+ * themselves after completing it
+ *
+ * For these quite rare devices, their drivers may change the
+ * autosuspend delay of their parent hub in the probe() to one
+ * appropriate value to avoid the subtle problem if someone
+ * does care it.
+ *
+ * - The patch may cause one or more auto suspend/resume on
+ * hub during running 'lsusb', but it is probably too
+ * infrequent to worry about.
+ *
+ * - Change autosuspend delay of hub can avoid unnecessary auto
+ * suspend timer for hub, also may decrease power consumption
+ * of USB bus.
+ *
+ * - If user has indicated to prevent autosuspend by passing
+ * usbcore.autosuspend = -1 then keep autosuspend disabled.
+ */
+#ifdef CONFIG_PM
+ if (hdev->dev.power.autosuspend_delay >= 0)
+ pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
+#endif
+
+ /*
+ * Hubs have proper suspend/resume support, except for root hubs
+ * where the controller driver doesn't have bus_suspend and
+ * bus_resume methods.
+ */
+ if (hdev->parent) { /* normal device */
+ usb_enable_autosuspend(hdev);
+ } else { /* root hub */
+ const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver;
+
+ if (drv->bus_suspend && drv->bus_resume)
+ usb_enable_autosuspend(hdev);
+ }
+
+ if (hdev->level == MAX_TOPO_LEVEL) {
+ dev_err(&intf->dev,
+ "Unsupported bus topology: hub nested too deep\n");
+ return -E2BIG;
+ }
+
+#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
+ if (hdev->parent) {
+ dev_warn(&intf->dev, "ignoring external hub\n");
+ return -ENODEV;
+ }
+#endif
+
+ if (!hub_descriptor_is_sane(desc)) {
+ dev_err(&intf->dev, "bad descriptor, ignoring hub\n");
+ return -EIO;
+ }
+
+ /* We found a hub */
+ dev_info(&intf->dev, "USB hub found\n");
+
+ hub = kzalloc(sizeof(*hub), GFP_KERNEL);
+ if (!hub)
+ return -ENOMEM;
+
+ kref_init(&hub->kref);
+ hub->intfdev = &intf->dev;
+ hub->hdev = hdev;
+ INIT_DELAYED_WORK(&hub->leds, led_work);
+ INIT_DELAYED_WORK(&hub->init_work, NULL);
+ INIT_WORK(&hub->events, hub_event);
+ usb_get_intf(intf);
+ usb_get_dev(hdev);
+
+ usb_set_intfdata(intf, hub);
+ intf->needs_remote_wakeup = 1;
+ pm_suspend_ignore_children(&intf->dev, true);
+
+ if (hdev->speed == USB_SPEED_HIGH)
+ highspeed_hubs++;
+
+ if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
+ hub->quirk_check_port_auto_suspend = 1;
+
+ if (id->driver_info & HUB_QUIRK_DISABLE_AUTOSUSPEND) {
+ hub->quirk_disable_autosuspend = 1;
+ usb_autopm_get_interface_no_resume(intf);
+ }
+
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
+ return 0;
+
+ hub_disconnect(intf);
+ return -ENODEV;
+}
+
+static int
+hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
+{
+ struct usb_device *hdev = interface_to_usbdev(intf);
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+
+ /* assert ifno == 0 (part of hub spec) */
+ switch (code) {
+ case USBDEVFS_HUB_PORTINFO: {
+ struct usbdevfs_hub_portinfo *info = user_data;
+ int i;
+
+ spin_lock_irq(&device_state_lock);
+ if (hdev->devnum <= 0)
+ info->nports = 0;
+ else {
+ info->nports = hdev->maxchild;
+ for (i = 0; i < info->nports; i++) {
+ if (hub->ports[i]->child == NULL)
+ info->port[i] = 0;
+ else
+ info->port[i] =
+ hub->ports[i]->child->devnum;
+ }
+ }
+ spin_unlock_irq(&device_state_lock);
+
+ return info->nports + 1;
+ }
+
+ default:
+ return -ENOSYS;
+ }
+}
+
+/*
+ * Allow user programs to claim ports on a hub. When a device is attached
+ * to one of these "claimed" ports, the program will "own" the device.
+ */
+static int find_port_owner(struct usb_device *hdev, unsigned port1,
+ struct usb_dev_state ***ppowner)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+
+ if (hdev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (port1 == 0 || port1 > hdev->maxchild)
+ return -EINVAL;
+
+ /* Devices not managed by the hub driver
+ * will always have maxchild equal to 0.
+ */
+ *ppowner = &(hub->ports[port1 - 1]->port_owner);
+ return 0;
+}
+
+/* In the following three functions, the caller must hold hdev's lock */
+int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
+ struct usb_dev_state *owner)
+{
+ int rc;
+ struct usb_dev_state **powner;
+
+ rc = find_port_owner(hdev, port1, &powner);
+ if (rc)
+ return rc;
+ if (*powner)
+ return -EBUSY;
+ *powner = owner;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hub_claim_port);
+
+int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
+ struct usb_dev_state *owner)
+{
+ int rc;
+ struct usb_dev_state **powner;
+
+ rc = find_port_owner(hdev, port1, &powner);
+ if (rc)
+ return rc;
+ if (*powner != owner)
+ return -ENOENT;
+ *powner = NULL;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hub_release_port);
+
+void usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ int n;
+
+ for (n = 0; n < hdev->maxchild; n++) {
+ if (hub->ports[n]->port_owner == owner)
+ hub->ports[n]->port_owner = NULL;
+ }
+
+}
+
+/* The caller must hold udev's lock */
+bool usb_device_is_owned(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+
+ if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
+ return false;
+ hub = usb_hub_to_struct_hub(udev->parent);
+ return !!hub->ports[udev->portnum - 1]->port_owner;
+}
+
+static void recursively_mark_NOTATTACHED(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev);
+ int i;
+
+ for (i = 0; i < udev->maxchild; ++i) {
+ if (hub->ports[i]->child)
+ recursively_mark_NOTATTACHED(hub->ports[i]->child);
+ }
+ if (udev->state == USB_STATE_SUSPENDED)
+ udev->active_duration -= jiffies;
+ udev->state = USB_STATE_NOTATTACHED;
+}
+
+/**
+ * usb_set_device_state - change a device's current state (usbcore, hcds)
+ * @udev: pointer to device whose state should be changed
+ * @new_state: new state value to be stored
+ *
+ * udev->state is _not_ fully protected by the device lock. Although
+ * most transitions are made only while holding the lock, the state can
+ * can change to USB_STATE_NOTATTACHED at almost any time. This
+ * is so that devices can be marked as disconnected as soon as possible,
+ * without having to wait for any semaphores to be released. As a result,
+ * all changes to any device's state must be protected by the
+ * device_state_lock spinlock.
+ *
+ * Once a device has been added to the device tree, all changes to its state
+ * should be made using this routine. The state should _not_ be set directly.
+ *
+ * If udev->state is already USB_STATE_NOTATTACHED then no change is made.
+ * Otherwise udev->state is set to new_state, and if new_state is
+ * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set
+ * to USB_STATE_NOTATTACHED.
+ */
+void usb_set_device_state(struct usb_device *udev,
+ enum usb_device_state new_state)
+{
+ unsigned long flags;
+ int wakeup = -1;
+
+ spin_lock_irqsave(&device_state_lock, flags);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ ; /* do nothing */
+ else if (new_state != USB_STATE_NOTATTACHED) {
+
+ /* root hub wakeup capabilities are managed out-of-band
+ * and may involve silicon errata ... ignore them here.
+ */
+ if (udev->parent) {
+ if (udev->state == USB_STATE_SUSPENDED
+ || new_state == USB_STATE_SUSPENDED)
+ ; /* No change to wakeup settings */
+ else if (new_state == USB_STATE_CONFIGURED)
+ wakeup = (udev->quirks &
+ USB_QUIRK_IGNORE_REMOTE_WAKEUP) ? 0 :
+ udev->actconfig->desc.bmAttributes &
+ USB_CONFIG_ATT_WAKEUP;
+ else
+ wakeup = 0;
+ }
+ if (udev->state == USB_STATE_SUSPENDED &&
+ new_state != USB_STATE_SUSPENDED)
+ udev->active_duration -= jiffies;
+ else if (new_state == USB_STATE_SUSPENDED &&
+ udev->state != USB_STATE_SUSPENDED)
+ udev->active_duration += jiffies;
+ udev->state = new_state;
+ } else
+ recursively_mark_NOTATTACHED(udev);
+ spin_unlock_irqrestore(&device_state_lock, flags);
+ if (wakeup >= 0)
+ device_set_wakeup_capable(&udev->dev, wakeup);
+}
+EXPORT_SYMBOL_GPL(usb_set_device_state);
+
+/*
+ * Choose a device number.
+ *
+ * Device numbers are used as filenames in usbfs. On USB-1.1 and
+ * USB-2.0 buses they are also used as device addresses, however on
+ * USB-3.0 buses the address is assigned by the controller hardware
+ * and it usually is not the same as the device number.
+ *
+ * WUSB devices are simple: they have no hubs behind, so the mapping
+ * device <-> virtual port number becomes 1:1. Why? to simplify the
+ * life of the device connection logic in
+ * drivers/usb/wusbcore/devconnect.c. When we do the initial secret
+ * handshake we need to assign a temporary address in the unauthorized
+ * space. For simplicity we use the first virtual port number found to
+ * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()]
+ * and that becomes it's address [X < 128] or its unauthorized address
+ * [X | 0x80].
+ *
+ * We add 1 as an offset to the one-based USB-stack port number
+ * (zero-based wusb virtual port index) for two reasons: (a) dev addr
+ * 0 is reserved by USB for default address; (b) Linux's USB stack
+ * uses always #1 for the root hub of the controller. So USB stack's
+ * port #1, which is wusb virtual-port #0 has address #2.
+ *
+ * Devices connected under xHCI are not as simple. The host controller
+ * supports virtualization, so the hardware assigns device addresses and
+ * the HCD must setup data structures before issuing a set address
+ * command to the hardware.
+ */
+static void choose_devnum(struct usb_device *udev)
+{
+ int devnum;
+ struct usb_bus *bus = udev->bus;
+
+ /* be safe when more hub events are proceed in parallel */
+ mutex_lock(&bus->devnum_next_mutex);
+ if (udev->wusb) {
+ devnum = udev->portnum + 1;
+ BUG_ON(test_bit(devnum, bus->devmap.devicemap));
+ } else {
+ /* Try to allocate the next devnum beginning at
+ * bus->devnum_next. */
+ devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
+ bus->devnum_next);
+ if (devnum >= 128)
+ devnum = find_next_zero_bit(bus->devmap.devicemap,
+ 128, 1);
+ bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);
+ }
+ if (devnum < 128) {
+ set_bit(devnum, bus->devmap.devicemap);
+ udev->devnum = devnum;
+ }
+ mutex_unlock(&bus->devnum_next_mutex);
+}
+
+static void release_devnum(struct usb_device *udev)
+{
+ if (udev->devnum > 0) {
+ clear_bit(udev->devnum, udev->bus->devmap.devicemap);
+ udev->devnum = -1;
+ }
+}
+
+static void update_devnum(struct usb_device *udev, int devnum)
+{
+ /* The address for a WUSB device is managed by wusbcore. */
+ if (!udev->wusb)
+ udev->devnum = devnum;
+}
+
+static void hub_free_dev(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ /* Root hubs aren't real devices, so don't free HCD resources */
+ if (hcd->driver->free_dev && udev->parent)
+ hcd->driver->free_dev(hcd, udev);
+}
+
+static void hub_disconnect_children(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev);
+ int i;
+
+ /* Free up all the children before we remove this device */
+ for (i = 0; i < udev->maxchild; i++) {
+ if (hub->ports[i]->child)
+ usb_disconnect(&hub->ports[i]->child);
+ }
+}
+
+/**
+ * usb_disconnect - disconnect a device (usbcore-internal)
+ * @pdev: pointer to device being disconnected
+ * Context: !in_interrupt ()
+ *
+ * Something got disconnected. Get rid of it and all of its children.
+ *
+ * If *pdev is a normal device then the parent hub must already be locked.
+ * If *pdev is a root hub then the caller must hold the usb_bus_idr_lock,
+ * which protects the set of root hubs as well as the list of buses.
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ */
+void usb_disconnect(struct usb_device **pdev)
+{
+ struct usb_port *port_dev = NULL;
+ struct usb_device *udev = *pdev;
+ struct usb_hub *hub = NULL;
+ int port1 = 1;
+
+ /* mark the device as inactive, so any further urb submissions for
+ * this device (and any of its children) will fail immediately.
+ * this quiesces everything except pending urbs.
+ */
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ dev_info(&udev->dev, "USB disconnect, device number %d\n",
+ udev->devnum);
+
+ /*
+ * Ensure that the pm runtime code knows that the USB device
+ * is in the process of being disconnected.
+ */
+ pm_runtime_barrier(&udev->dev);
+
+ usb_lock_device(udev);
+
+ hub_disconnect_children(udev);
+
+ /* deallocate hcd/hardware state ... nuking all pending urbs and
+ * cleaning up all state associated with the current configuration
+ * so that the hardware is now fully quiesced.
+ */
+ dev_dbg(&udev->dev, "unregistering device\n");
+ usb_disable_device(udev, 0);
+ usb_hcd_synchronize_unlinks(udev);
+
+ if (udev->parent) {
+ port1 = udev->portnum;
+ hub = usb_hub_to_struct_hub(udev->parent);
+ port_dev = hub->ports[port1 - 1];
+
+ sysfs_remove_link(&udev->dev.kobj, "port");
+ sysfs_remove_link(&port_dev->dev.kobj, "device");
+
+ /*
+ * As usb_port_runtime_resume() de-references udev, make
+ * sure no resumes occur during removal
+ */
+ if (!test_and_set_bit(port1, hub->child_usage_bits))
+ pm_runtime_get_sync(&port_dev->dev);
+ }
+
+ usb_remove_ep_devs(&udev->ep0);
+ usb_unlock_device(udev);
+
+ /* Unregister the device. The device driver is responsible
+ * for de-configuring the device and invoking the remove-device
+ * notifier chain (used by usbfs and possibly others).
+ */
+ device_del(&udev->dev);
+
+ /* Free the device number and delete the parent's children[]
+ * (or root_hub) pointer.
+ */
+ release_devnum(udev);
+
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+ spin_lock_irq(&device_state_lock);
+ *pdev = NULL;
+ spin_unlock_irq(&device_state_lock);
+
+ if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits))
+ pm_runtime_put(&port_dev->dev);
+
+ hub_free_dev(udev);
+
+ put_device(&udev->dev);
+}
+
+#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+static void show_string(struct usb_device *udev, char *id, char *string)
+{
+ if (!string)
+ return;
+ dev_info(&udev->dev, "%s: %s\n", id, string);
+}
+
+static void announce_device(struct usb_device *udev)
+{
+ u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
+
+ dev_info(&udev->dev,
+ "New USB device found, idVendor=%04x, idProduct=%04x, bcdDevice=%2x.%02x\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ bcdDevice >> 8, bcdDevice & 0xff);
+ dev_info(&udev->dev,
+ "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
+}
+#else
+static inline void announce_device(struct usb_device *udev) { }
+#endif
+
+
+/**
+ * usb_enumerate_device_otg - FIXME (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * Finish enumeration for On-The-Go devices
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+static int usb_enumerate_device_otg(struct usb_device *udev)
+{
+ int err = 0;
+
+#ifdef CONFIG_USB_OTG
+ /*
+ * OTG-aware devices on OTG-capable root hubs may be able to use SRP,
+ * to wake us after we've powered off VBUS; and HNP, switching roles
+ * "host" to "peripheral". The OTG descriptor helps figure this out.
+ */
+ if (!udev->bus->is_b_host
+ && udev->config
+ && udev->parent == udev->bus->root_hub) {
+ struct usb_otg_descriptor *desc = NULL;
+ struct usb_bus *bus = udev->bus;
+ unsigned port1 = udev->portnum;
+
+ /* descriptor may appear anywhere in config */
+ err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
+ le16_to_cpu(udev->config[0].desc.wTotalLength),
+ USB_DT_OTG, (void **) &desc, sizeof(*desc));
+ if (err || !(desc->bmAttributes & USB_OTG_HNP))
+ return 0;
+
+ dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n",
+ (port1 == bus->otg_port) ? "" : "non-");
+
+ /* enable HNP before suspend, it's simpler */
+ if (port1 == bus->otg_port) {
+ bus->b_hnp_enable = 1;
+ err = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, 0,
+ USB_DEVICE_B_HNP_ENABLE,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
+ /*
+ * OTG MESSAGE: report errors here,
+ * customize to match your product.
+ */
+ dev_err(&udev->dev, "can't set HNP mode: %d\n",
+ err);
+ bus->b_hnp_enable = 0;
+ }
+ } else if (desc->bLength == sizeof
+ (struct usb_otg_descriptor)) {
+ /* Set a_alt_hnp_support for legacy otg device */
+ err = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, 0,
+ USB_DEVICE_A_ALT_HNP_SUPPORT,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (err < 0)
+ dev_err(&udev->dev,
+ "set a_alt_hnp_support failed: %d\n",
+ err);
+ }
+ }
+#endif
+ return err;
+}
+
+
+/**
+ * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
+ */
+static int usb_enumerate_device(struct usb_device *udev)
+{
+ int err;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (udev->config == NULL) {
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ if (err != -ENODEV)
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ return err;
+ }
+ }
+
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+
+ err = usb_enumerate_device_otg(udev);
+ if (err < 0)
+ return err;
+
+ if (IS_ENABLED(CONFIG_USB_OTG_WHITELIST) && hcd->tpl_support &&
+ !is_targeted(udev)) {
+ /* Maybe it can talk to us, though we can't talk to it.
+ * (Includes HNP test device.)
+ */
+ if (IS_ENABLED(CONFIG_USB_OTG) && (udev->bus->b_hnp_enable
+ || udev->bus->is_b_host)) {
+ err = usb_port_suspend(udev, PMSG_AUTO_SUSPEND);
+ if (err < 0)
+ dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ }
+ return -ENOTSUPP;
+ }
+
+ usb_detect_interface_quirks(udev);
+
+ return 0;
+}
+
+static void set_usb_port_removable(struct usb_device *udev)
+{
+ struct usb_device *hdev = udev->parent;
+ struct usb_hub *hub;
+ u8 port = udev->portnum;
+ u16 wHubCharacteristics;
+ bool removable = true;
+
+ if (!hdev)
+ return;
+
+ hub = usb_hub_to_struct_hub(udev->parent);
+
+ /*
+ * If the platform firmware has provided information about a port,
+ * use that to determine whether it's removable.
+ */
+ switch (hub->ports[udev->portnum - 1]->connect_type) {
+ case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+ udev->removable = USB_DEVICE_REMOVABLE;
+ return;
+ case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+ case USB_PORT_NOT_USED:
+ udev->removable = USB_DEVICE_FIXED;
+ return;
+ default:
+ break;
+ }
+
+ /*
+ * Otherwise, check whether the hub knows whether a port is removable
+ * or not
+ */
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+ return;
+
+ if (hub_is_superspeed(hdev)) {
+ if (le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable)
+ & (1 << port))
+ removable = false;
+ } else {
+ if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
+ removable = false;
+ }
+
+ if (removable)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+
+}
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been detected but not fully
+ * enumerated. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_idr_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ *
+ * Return: Whether the device is configured properly or not. Zero if the
+ * interface was registered with the driver core; else a negative errno
+ * value.
+ *
+ */
+int usb_new_device(struct usb_device *udev)
+{
+ int err;
+
+ if (udev->parent) {
+ /* Initialize non-root-hub device wakeup to disabled;
+ * device (un)configuration controls wakeup capable
+ * sysfs power/wakeup controls wakeup enabled/disabled
+ */
+ device_init_wakeup(&udev->dev, 0);
+ }
+
+ /* Tell the runtime-PM framework the device is active */
+ pm_runtime_set_active(&udev->dev);
+ pm_runtime_get_noresume(&udev->dev);
+ pm_runtime_use_autosuspend(&udev->dev);
+ pm_runtime_enable(&udev->dev);
+
+ /* By default, forbid autosuspend for all devices. It will be
+ * allowed for hubs during binding.
+ */
+ usb_disable_autosuspend(udev);
+
+ err = usb_enumerate_device(udev); /* Read descriptors */
+ if (err < 0)
+ goto fail;
+ dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
+ udev->devnum, udev->bus->busnum,
+ (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+ /* export the usbdev device-node for libusb */
+ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
+ (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+
+ /* Tell the world! */
+ announce_device(udev);
+
+ if (udev->serial)
+ add_device_randomness(udev->serial, strlen(udev->serial));
+ if (udev->product)
+ add_device_randomness(udev->product, strlen(udev->product));
+ if (udev->manufacturer)
+ add_device_randomness(udev->manufacturer,
+ strlen(udev->manufacturer));
+
+ device_enable_async_suspend(&udev->dev);
+
+ /* check whether the hub or firmware marks this port as non-removable */
+ if (udev->parent)
+ set_usb_port_removable(udev);
+
+ /* Register the device. The device driver is responsible
+ * for configuring the device and invoking the add-device
+ * notifier chain (used by usbfs and possibly others).
+ */
+ err = device_add(&udev->dev);
+ if (err) {
+ dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ goto fail;
+ }
+
+ /* Create link files between child device and usb port device. */
+ if (udev->parent) {
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+ int port1 = udev->portnum;
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+
+ err = sysfs_create_link(&udev->dev.kobj,
+ &port_dev->dev.kobj, "port");
+ if (err)
+ goto fail;
+
+ err = sysfs_create_link(&port_dev->dev.kobj,
+ &udev->dev.kobj, "device");
+ if (err) {
+ sysfs_remove_link(&udev->dev.kobj, "port");
+ goto fail;
+ }
+
+ if (!test_and_set_bit(port1, hub->child_usage_bits))
+ pm_runtime_get_sync(&port_dev->dev);
+ }
+
+ (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
+ usb_mark_last_busy(udev);
+ pm_runtime_put_sync_autosuspend(&udev->dev);
+ return err;
+
+fail:
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ pm_runtime_disable(&udev->dev);
+ pm_runtime_set_suspended(&udev->dev);
+ return err;
+}
+
+
+/**
+ * usb_deauthorize_device - deauthorize a device (usbcore-internal)
+ * @usb_dev: USB device
+ *
+ * Move the USB device to a very basic state where interfaces are disabled
+ * and the device is in fact unconfigured and unusable.
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ *
+ * Return: 0.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 0)
+ goto out_unauthorized;
+
+ usb_dev->authorized = 0;
+ usb_set_configuration(usb_dev, -1);
+
+out_unauthorized:
+ usb_unlock_device(usb_dev);
+ return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+ int result = 0, c;
+
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 1)
+ goto out_authorized;
+
+ result = usb_autoresume_device(usb_dev);
+ if (result < 0) {
+ dev_err(&usb_dev->dev,
+ "can't autoresume for authorization: %d\n", result);
+ goto error_autoresume;
+ }
+
+ if (usb_dev->wusb) {
+ result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+ if (result < 0) {
+ dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+ "authorization: %d\n", result);
+ goto error_device_descriptor;
+ }
+ }
+
+ usb_dev->authorized = 1;
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = usb_choose_configuration(usb_dev);
+ if (c >= 0) {
+ result = usb_set_configuration(usb_dev, c);
+ if (result) {
+ dev_err(&usb_dev->dev,
+ "can't set config #%d, error %d\n", c, result);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+ dev_info(&usb_dev->dev, "authorized to connect\n");
+
+error_device_descriptor:
+ usb_autosuspend_device(usb_dev);
+error_autoresume:
+out_authorized:
+ usb_unlock_device(usb_dev); /* complements locktree */
+ return result;
+}
+
+/*
+ * Return 1 if port speed is SuperSpeedPlus, 0 otherwise
+ * check it from the link protocol field of the current speed ID attribute.
+ * current speed ID is got from ext port status request. Sublink speed attribute
+ * table is returned with the hub BOS SSP device capability descriptor
+ */
+static int port_speed_is_ssp(struct usb_device *hdev, int speed_id)
+{
+ int ssa_count;
+ u32 ss_attr;
+ int i;
+ struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
+
+ if (!ssp_cap)
+ return 0;
+
+ ssa_count = le32_to_cpu(ssp_cap->bmAttributes) &
+ USB_SSP_SUBLINK_SPEED_ATTRIBS;
+
+ for (i = 0; i <= ssa_count; i++) {
+ ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
+ if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID))
+ return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP);
+ }
+ return 0;
+}
+
+/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
+static unsigned hub_is_wusb(struct usb_hub *hub)
+{
+ struct usb_hcd *hcd;
+ if (hub->hdev->parent != NULL) /* not a root hub? */
+ return 0;
+ hcd = bus_to_hcd(hub->hdev->bus);
+ return hcd->wireless;
+}
+
+
+#define PORT_RESET_TRIES 5
+#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 HUB_ROOT_RESET_TIME 60 /* times are in msec */
+#define HUB_SHORT_RESET_TIME 10
+#define HUB_BH_RESET_TIME 50
+#define HUB_LONG_RESET_TIME 200
+#define HUB_RESET_TIMEOUT 800
+
+/*
+ * "New scheme" enumeration causes an extra state transition to be
+ * exposed to an xhci host and causes USB3 devices to receive control
+ * commands in the default state. This has been seen to cause
+ * enumeration failures, so disable this enumeration scheme for USB3
+ * devices.
+ */
+static bool use_new_scheme(struct usb_device *udev, int retry,
+ struct usb_port *port_dev)
+{
+ int old_scheme_first_port =
+ port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME;
+
+ if (udev->speed >= USB_SPEED_SUPER)
+ return false;
+
+ return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first);
+}
+
+/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
+ * Port worm reset is required to recover
+ */
+static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
+ u16 portstatus)
+{
+ u16 link_state;
+
+ if (!hub_is_superspeed(hub->hdev))
+ return false;
+
+ if (test_bit(port1, hub->warm_reset_bits))
+ return true;
+
+ link_state = portstatus & USB_PORT_STAT_LINK_STATE;
+ return link_state == USB_SS_PORT_LS_SS_INACTIVE
+ || link_state == USB_SS_PORT_LS_COMP_MOD;
+}
+
+static int hub_port_wait_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay, bool warm)
+{
+ int delay_time, ret;
+ u16 portstatus;
+ u16 portchange;
+ u32 ext_portstatus = 0;
+
+ for (delay_time = 0;
+ delay_time < HUB_RESET_TIMEOUT;
+ delay_time += delay) {
+ /* wait to give the device a chance to reset */
+ msleep(delay);
+
+ /* read and decode port status */
+ if (hub_is_superspeedplus(hub->hdev))
+ ret = hub_ext_port_status(hub, port1,
+ HUB_EXT_PORT_STATUS,
+ &portstatus, &portchange,
+ &ext_portstatus);
+ else
+ ret = hub_port_status(hub, port1, &portstatus,
+ &portchange);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The port state is unknown until the reset completes.
+ *
+ * On top of that, some chips may require additional time
+ * to re-establish a connection after the reset is complete,
+ * so also wait for the connection to be re-established.
+ */
+ if (!(portstatus & USB_PORT_STAT_RESET) &&
+ (portstatus & USB_PORT_STAT_CONNECTION))
+ break;
+
+ /* switch to the long delay after two short delay failures */
+ if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
+ delay = HUB_LONG_RESET_TIME;
+
+ dev_dbg(&hub->ports[port1 - 1]->dev,
+ "not %sreset yet, waiting %dms\n",
+ warm ? "warm " : "", delay);
+ }
+
+ if ((portstatus & USB_PORT_STAT_RESET))
+ return -EBUSY;
+
+ if (hub_port_warm_reset_required(hub, port1, portstatus))
+ return -ENOTCONN;
+
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return -ENOTCONN;
+
+ /* Retry if connect change is set but status is still connected.
+ * A USB 3.0 connection may bounce if multiple warm resets were issued,
+ * but the device may have successfully re-connected. Ignore it.
+ */
+ if (!hub_is_superspeed(hub->hdev) &&
+ (portchange & USB_PORT_STAT_C_CONNECTION)) {
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ return -EAGAIN;
+ }
+
+ if (!(portstatus & USB_PORT_STAT_ENABLE))
+ return -EBUSY;
+
+ if (!udev)
+ return 0;
+
+ if (hub_is_superspeedplus(hub->hdev)) {
+ /* extended portstatus Rx and Tx lane count are zero based */
+ udev->rx_lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
+ udev->tx_lanes = USB_EXT_PORT_TX_LANES(ext_portstatus) + 1;
+ } else {
+ udev->rx_lanes = 1;
+ udev->tx_lanes = 1;
+ }
+ if (hub_is_wusb(hub))
+ udev->speed = USB_SPEED_WIRELESS;
+ else if (hub_is_superspeedplus(hub->hdev) &&
+ port_speed_is_ssp(hub->hdev, ext_portstatus &
+ USB_EXT_PORT_STAT_RX_SPEED_ID))
+ udev->speed = USB_SPEED_SUPER_PLUS;
+ else if (hub_is_superspeed(hub->hdev))
+ udev->speed = USB_SPEED_SUPER;
+ else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ udev->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ udev->speed = USB_SPEED_LOW;
+ else
+ udev->speed = USB_SPEED_FULL;
+ return 0;
+}
+
+/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
+static int hub_port_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay, bool warm)
+{
+ int i, status;
+ u16 portchange, portstatus;
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ int reset_recovery_time;
+
+ if (!hub_is_superspeed(hub->hdev)) {
+ if (warm) {
+ dev_err(hub->intfdev, "only USB3 hub support "
+ "warm reset\n");
+ return -EINVAL;
+ }
+ /* Block EHCI CF initialization during the port reset.
+ * Some companion controllers don't like it when they mix.
+ */
+ down_read(&ehci_cf_port_reset_rwsem);
+ } else if (!warm) {
+ /*
+ * If the caller hasn't explicitly requested a warm reset,
+ * double check and see if one is needed.
+ */
+ if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
+ if (hub_port_warm_reset_required(hub, port1,
+ portstatus))
+ warm = true;
+ }
+ clear_bit(port1, hub->warm_reset_bits);
+
+ /* Reset the port */
+ for (i = 0; i < PORT_RESET_TRIES; i++) {
+ status = set_port_feature(hub->hdev, port1, (warm ?
+ USB_PORT_FEAT_BH_PORT_RESET :
+ USB_PORT_FEAT_RESET));
+ if (status == -ENODEV) {
+ ; /* The hub is gone */
+ } else if (status) {
+ dev_err(&port_dev->dev,
+ "cannot %sreset (err = %d)\n",
+ warm ? "warm " : "", status);
+ } else {
+ status = hub_port_wait_reset(hub, port1, udev, delay,
+ warm);
+ if (status && status != -ENOTCONN && status != -ENODEV)
+ dev_dbg(hub->intfdev,
+ "port_wait_reset: err = %d\n",
+ status);
+ }
+
+ /* Check for disconnect or reset */
+ if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_RESET);
+
+ if (!hub_is_superspeed(hub->hdev))
+ goto done;
+
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+
+ if (udev)
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+
+ /*
+ * If a USB 3.0 device migrates from reset to an error
+ * state, re-issue the warm reset.
+ */
+ if (hub_port_status(hub, port1,
+ &portstatus, &portchange) < 0)
+ goto done;
+
+ if (!hub_port_warm_reset_required(hub, port1,
+ portstatus))
+ goto done;
+
+ /*
+ * If the port is in SS.Inactive or Compliance Mode, the
+ * hot or warm reset failed. Try another warm reset.
+ */
+ if (!warm) {
+ dev_dbg(&port_dev->dev,
+ "hot reset failed, warm reset\n");
+ warm = true;
+ }
+ }
+
+ dev_dbg(&port_dev->dev,
+ "not enabled, trying %sreset again...\n",
+ warm ? "warm " : "");
+ delay = HUB_LONG_RESET_TIME;
+ }
+
+ dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
+
+done:
+ if (status == 0) {
+ if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
+ usleep_range(10000, 12000);
+ else {
+ /* TRSTRCY = 10 ms; plus some extra */
+ reset_recovery_time = 10 + 40;
+
+ /* Hub needs extra delay after resetting its port. */
+ if (hub->hdev->quirks & USB_QUIRK_HUB_SLOW_RESET)
+ reset_recovery_time += 100;
+
+ msleep(reset_recovery_time);
+ }
+
+ if (udev) {
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ update_devnum(udev, 0);
+ /* The xHC may think the device is already reset,
+ * so ignore the status.
+ */
+ if (hcd->driver->reset_device)
+ hcd->driver->reset_device(hcd, udev);
+
+ usb_set_device_state(udev, USB_STATE_DEFAULT);
+ }
+ } else {
+ if (udev)
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ }
+
+ if (!hub_is_superspeed(hub->hdev))
+ up_read(&ehci_cf_port_reset_rwsem);
+
+ return status;
+}
+
+/* Check if a port is power on */
+static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
+{
+ int ret = 0;
+
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portstatus & USB_SS_PORT_STAT_POWER)
+ ret = 1;
+ } else {
+ if (portstatus & USB_PORT_STAT_POWER)
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static void usb_lock_port(struct usb_port *port_dev)
+ __acquires(&port_dev->status_lock)
+{
+ mutex_lock(&port_dev->status_lock);
+ __acquire(&port_dev->status_lock);
+}
+
+static void usb_unlock_port(struct usb_port *port_dev)
+ __releases(&port_dev->status_lock)
+{
+ mutex_unlock(&port_dev->status_lock);
+ __release(&port_dev->status_lock);
+}
+
+#ifdef CONFIG_PM
+
+/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
+static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
+{
+ int ret = 0;
+
+ if (hub_is_superspeed(hub->hdev)) {
+ if ((portstatus & USB_PORT_STAT_LINK_STATE)
+ == USB_SS_PORT_LS_U3)
+ ret = 1;
+ } else {
+ if (portstatus & USB_PORT_STAT_SUSPEND)
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/* Determine whether the device on a port is ready for a normal resume,
+ * is ready for a reset-resume, or should be disconnected.
+ */
+static int check_port_resume_type(struct usb_device *udev,
+ struct usb_hub *hub, int port1,
+ int status, u16 portchange, u16 portstatus)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ int retries = 3;
+
+ retry:
+ /* Is a warm reset needed to recover the connection? */
+ if (status == 0 && udev->reset_resume
+ && hub_port_warm_reset_required(hub, port1, portstatus)) {
+ /* pass */;
+ }
+ /* Is the device still present? */
+ else if (status || port_is_suspended(hub, portstatus) ||
+ !port_is_power_on(hub, portstatus)) {
+ if (status >= 0)
+ status = -ENODEV;
+ } else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
+ if (retries--) {
+ usleep_range(200, 300);
+ status = hub_port_status(hub, port1, &portstatus,
+ &portchange);
+ goto retry;
+ }
+ status = -ENODEV;
+ }
+
+ /* Can't do a normal resume if the port isn't enabled,
+ * so try a reset-resume instead.
+ */
+ else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) {
+ if (udev->persist_enabled)
+ udev->reset_resume = 1;
+ else
+ status = -ENODEV;
+ }
+
+ if (status) {
+ dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n",
+ portchange, portstatus, status);
+ } else if (udev->reset_resume) {
+
+ /* Late port handoff can set status-change bits */
+ if (portchange & USB_PORT_STAT_C_CONNECTION)
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ if (portchange & USB_PORT_STAT_C_ENABLE)
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+
+ /*
+ * Whatever made this reset-resume necessary may have
+ * turned on the port1 bit in hub->change_bits. But after
+ * a successful reset-resume we want the bit to be clear;
+ * if it was on it would indicate that something happened
+ * following the reset-resume.
+ */
+ clear_bit(port1, hub->change_bits);
+ }
+
+ return status;
+}
+
+int usb_disable_ltm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ /* Check if the roothub and device supports LTM. */
+ if (!usb_device_supports_ltm(hcd->self.root_hub) ||
+ !usb_device_supports_ltm(udev))
+ return 0;
+
+ /* Clear Feature LTM Enable can only be sent if the device is
+ * configured.
+ */
+ if (!udev->actconfig)
+ return 0;
+
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+EXPORT_SYMBOL_GPL(usb_disable_ltm);
+
+void usb_enable_ltm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ /* Check if the roothub and device supports LTM. */
+ if (!usb_device_supports_ltm(hcd->self.root_hub) ||
+ !usb_device_supports_ltm(udev))
+ return;
+
+ /* Set Feature LTM Enable can only be sent if the device is
+ * configured.
+ */
+ if (!udev->actconfig)
+ return;
+
+ usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+EXPORT_SYMBOL_GPL(usb_enable_ltm);
+
+/*
+ * usb_enable_remote_wakeup - enable remote wakeup for a device
+ * @udev: target device
+ *
+ * For USB-2 devices: Set the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * enable remote wake for the first interface. FIXME if the interface
+ * association descriptor shows there's more than one function.
+ */
+static int usb_enable_remote_wakeup(struct usb_device *udev)
+{
+ if (udev->speed < USB_SPEED_SUPER)
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ else
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
+ USB_INTRF_FUNC_SUSPEND,
+ USB_INTRF_FUNC_SUSPEND_RW |
+ USB_INTRF_FUNC_SUSPEND_LP,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * usb_disable_remote_wakeup - disable remote wakeup for a device
+ * @udev: target device
+ *
+ * For USB-2 devices: Clear the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * disable remote wake for the first interface. FIXME if the interface
+ * association descriptor shows there's more than one function.
+ */
+static int usb_disable_remote_wakeup(struct usb_device *udev)
+{
+ if (udev->speed < USB_SPEED_SUPER)
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ else
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
+ USB_INTRF_FUNC_SUSPEND, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
+/* Count of wakeup-enabled devices at or below udev */
+static unsigned wakeup_enabled_descendants(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev);
+
+ return udev->do_remote_wakeup +
+ (hub ? hub->wakeup_enabled_descendants : 0);
+}
+
+/*
+ * usb_port_suspend - suspend a usb device's upstream port
+ * @udev: device that's no longer in active use, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * Suspends a USB device that isn't in active use, conserving power.
+ * Devices may wake out of a suspend, if anything important happens,
+ * using the remote wakeup mechanism. They may also be taken out of
+ * suspend by the host, using usb_port_resume(). It's also routine
+ * to disconnect devices while they are suspended.
+ *
+ * This only affects the USB hardware for a device; its interfaces
+ * (and, for hubs, child devices) must already have been suspended.
+ *
+ * Selective port suspend reduces power; most suspended devices draw
+ * less than 500 uA. It's also used in OTG, along with remote wakeup.
+ * All devices below the suspended port are also suspended.
+ *
+ * Devices leave suspend state when the host wakes them up. Some devices
+ * also support "remote wakeup", where the device can activate the USB
+ * tree above them to deliver data, such as a keypress or packet. In
+ * some cases, this wakes the USB host.
+ *
+ * Suspending OTG devices may trigger HNP, if that's been enabled
+ * between a pair of dual-role devices. That will change roles, such
+ * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
+ *
+ * Devices on USB hub ports have only one "suspend" state, corresponding
+ * to ACPI D2, "may cause the device to lose some context".
+ * State transitions include:
+ *
+ * - suspend, resume ... when the VBUS power link stays live
+ * - suspend, disconnect ... VBUS lost
+ *
+ * Once VBUS drop breaks the circuit, the port it's using has to go through
+ * normal re-enumeration procedures, starting with enabling VBUS power.
+ * Other than re-initializing the hub (plug/unplug, except for root hubs),
+ * Linux (2.6) currently has NO mechanisms to initiate that: no hub_wq
+ * timer, no SRP, no requests through sysfs.
+ *
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices may not get
+ * suspended until their bus goes into global suspend (i.e., the root
+ * hub is suspended). Nevertheless, we change @udev->state to
+ * USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
+ * upstream port setting is stored in @udev->port_is_suspended.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+ struct usb_port *port_dev = hub->ports[udev->portnum - 1];
+ int port1 = udev->portnum;
+ int status;
+ bool really_suspend = true;
+
+ usb_lock_port(port_dev);
+
+ /* enable remote wakeup when appropriate; this lets the device
+ * wake up the upstream hub (including maybe the root hub).
+ *
+ * NOTE: OTG devices may issue remote wakeup (or SRP) even when
+ * we don't explicitly enable it here.
+ */
+ if (udev->do_remote_wakeup) {
+ status = usb_enable_remote_wakeup(udev);
+ if (status) {
+ dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
+ status);
+ /* bail if autosuspend is requested */
+ if (PMSG_IS_AUTO(msg))
+ goto err_wakeup;
+ }
+ }
+
+ /* disable USB2 hardware LPM */
+ usb_disable_usb2_hardware_lpm(udev);
+
+ if (usb_disable_ltm(udev)) {
+ dev_err(&udev->dev, "Failed to disable LTM before suspend\n");
+ status = -ENOMEM;
+ if (PMSG_IS_AUTO(msg))
+ goto err_ltm;
+ }
+
+ /* see 7.1.7.6 */
+ if (hub_is_superspeed(hub->hdev))
+ status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
+
+ /*
+ * For system suspend, we do not need to enable the suspend feature
+ * on individual USB-2 ports. The devices will automatically go
+ * into suspend a few ms after the root hub stops sending packets.
+ * The USB 2.0 spec calls this "global suspend".
+ *
+ * However, many USB hubs have a bug: They don't relay wakeup requests
+ * from a downstream port if the port's suspend feature isn't on.
+ * Therefore we will turn on the suspend feature if udev or any of its
+ * descendants is enabled for remote wakeup.
+ */
+ else if (PMSG_IS_AUTO(msg) || wakeup_enabled_descendants(udev) > 0)
+ status = set_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_SUSPEND);
+ else {
+ really_suspend = false;
+ status = 0;
+ }
+ if (status) {
+ dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
+
+ /* Try to enable USB3 LTM again */
+ usb_enable_ltm(udev);
+ err_ltm:
+ /* Try to enable USB2 hardware LPM again */
+ usb_enable_usb2_hardware_lpm(udev);
+
+ if (udev->do_remote_wakeup)
+ (void) usb_disable_remote_wakeup(udev);
+ err_wakeup:
+
+ /* System sleep transitions should never fail */
+ if (!PMSG_IS_AUTO(msg))
+ status = 0;
+ } else {
+ dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""),
+ udev->do_remote_wakeup);
+ if (really_suspend) {
+ udev->port_is_suspended = 1;
+
+ /* device has up to 10 msec to fully suspend */
+ msleep(10);
+ }
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ }
+
+ if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled
+ && test_and_clear_bit(port1, hub->child_usage_bits))
+ pm_runtime_put_sync(&port_dev->dev);
+
+ usb_mark_last_busy(hub->hdev);
+
+ usb_unlock_port(port_dev);
+ return status;
+}
+
+/*
+ * If the USB "suspend" state is in use (rather than "global suspend"),
+ * many devices will be individually taken out of suspend state using
+ * special "resume" signaling. This routine kicks in shortly after
+ * hardware resume signaling is finished, either because of selective
+ * resume (by host) or remote wakeup (by device) ... now see what changed
+ * in the tree that's rooted at this device.
+ *
+ * If @udev->reset_resume is set then the device is reset before the
+ * status check is done.
+ */
+static int finish_port_resume(struct usb_device *udev)
+{
+ int status = 0;
+ u16 devstatus = 0;
+
+ /* caller owns the udev device lock */
+ dev_dbg(&udev->dev, "%s\n",
+ udev->reset_resume ? "finish reset-resume" : "finish resume");
+
+ /* usb ch9 identifies four variants of SUSPENDED, based on what
+ * state the device resumes to. Linux currently won't see the
+ * first two on the host side; they'd be inside hub_port_init()
+ * during many timeouts, but hub_wq can't suspend until later.
+ */
+ usb_set_device_state(udev, udev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
+
+ /* 10.5.4.5 says not to reset a suspended port if the attached
+ * device is enabled for remote wakeup. Hence the reset
+ * operation is carried out here, after the port has been
+ * resumed.
+ */
+ if (udev->reset_resume) {
+ /*
+ * If the device morphs or switches modes when it is reset,
+ * we don't want to perform a reset-resume. We'll fail the
+ * resume, which will cause a logical disconnect, and then
+ * the device will be rediscovered.
+ */
+ retry_reset_resume:
+ if (udev->quirks & USB_QUIRK_RESET)
+ status = -ENODEV;
+ else
+ status = usb_reset_and_verify_device(udev);
+ }
+
+ /* 10.5.4.5 says be sure devices in the tree are still there.
+ * For now let's assume the device didn't go crazy on resume,
+ * and device drivers will know about any resume quirks.
+ */
+ if (status == 0) {
+ devstatus = 0;
+ 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) {
+ dev_dbg(&udev->dev, "retry with reset-resume\n");
+ udev->reset_resume = 1;
+ goto retry_reset_resume;
+ }
+ }
+
+ if (status) {
+ dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
+ status);
+ /*
+ * There are a few quirky devices which violate the standard
+ * by claiming to have remote wakeup enabled after a reset,
+ * which crash if the feature is cleared, hence check for
+ * udev->reset_resume
+ */
+ } else if (udev->actconfig && !udev->reset_resume) {
+ if (udev->speed < USB_SPEED_SUPER) {
+ if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
+ status = usb_disable_remote_wakeup(udev);
+ } else {
+ 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))
+ status = usb_disable_remote_wakeup(udev);
+ }
+
+ if (status)
+ dev_dbg(&udev->dev,
+ "disable remote wakeup, status %d\n",
+ status);
+ status = 0;
+ }
+ return status;
+}
+
+/*
+ * There are some SS USB devices which take longer time for link training.
+ * XHCI specs 4.19.4 says that when Link training is successful, port
+ * sets CCS bit to 1. So if SW reads port status before successful link
+ * training, then it will not find device to be present.
+ * USB Analyzer log with such buggy devices show that in some cases
+ * device switch on the RX termination after long delay of host enabling
+ * the VBUS. In few other cases it has been seen that device fails to
+ * negotiate link training in first attempt. It has been
+ * reported till now that few devices take as long as 2000 ms to train
+ * the link after host enabling its VBUS and termination. Following
+ * routine implements a 2000 ms timeout for link training. If in a case
+ * link trains before timeout, loop will exit earlier.
+ *
+ * There are also some 2.0 hard drive based devices and 3.0 thumb
+ * drives that, when plugged into a 2.0 only port, take a long
+ * time to set CCS after VBUS enable.
+ *
+ * FIXME: If a device was connected before suspend, but was removed
+ * while system was asleep, then the loop in the following routine will
+ * only exit at timeout.
+ *
+ * This routine should only be called when persist is enabled.
+ */
+static int wait_for_connected(struct usb_device *udev,
+ struct usb_hub *hub, int *port1,
+ u16 *portchange, u16 *portstatus)
+{
+ int status = 0, delay_ms = 0;
+
+ while (delay_ms < 2000) {
+ if (status || *portstatus & USB_PORT_STAT_CONNECTION)
+ break;
+ if (!port_is_power_on(hub, *portstatus)) {
+ status = -ENODEV;
+ break;
+ }
+ msleep(20);
+ delay_ms += 20;
+ status = hub_port_status(hub, *port1, portstatus, portchange);
+ }
+ dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
+ return status;
+}
+
+/*
+ * usb_port_resume - re-activate a suspended usb device's upstream port
+ * @udev: device to re-activate, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * This will re-activate the suspended device, increasing power usage
+ * while letting drivers communicate again with its endpoints.
+ * USB resume explicitly guarantees that the power session between
+ * the host and the device is the same as it was when the device
+ * suspended.
+ *
+ * If @udev->reset_resume is set then this routine won't check that the
+ * port is still enabled. Furthermore, finish_port_resume() above will
+ * reset @udev. The end result is that a broken power session can be
+ * recovered and @udev will appear to persist across a loss of VBUS power.
+ *
+ * For example, if a host controller doesn't maintain VBUS suspend current
+ * during a system sleep or is reset when the system wakes up, all the USB
+ * power sessions below it will be broken. This is especially troublesome
+ * for mass-storage devices containing mounted filesystems, since the
+ * device will appear to have disconnected and all the memory mappings
+ * to it will be lost. Using the USB_PERSIST facility, the device can be
+ * made to appear as if it had not disconnected.
+ *
+ * This facility can be dangerous. Although usb_reset_and_verify_device() makes
+ * every effort to insure that the same device is present after the
+ * reset as before, it cannot provide a 100% guarantee. Furthermore it's
+ * quite possible for a device to remain unaltered but its media to be
+ * changed. If the user replaces a flash memory card while the system is
+ * asleep, he will have only himself to blame when the filesystem on the
+ * new card is corrupted and the system crashes.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_port_resume(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+ struct usb_port *port_dev = hub->ports[udev->portnum - 1];
+ int port1 = udev->portnum;
+ int status;
+ u16 portchange, portstatus;
+
+ if (!test_and_set_bit(port1, hub->child_usage_bits)) {
+ status = pm_runtime_get_sync(&port_dev->dev);
+ if (status < 0) {
+ dev_dbg(&udev->dev, "can't resume usb port, status %d\n",
+ status);
+ return status;
+ }
+ }
+
+ usb_lock_port(port_dev);
+
+ /* Skip the initial Clear-Suspend step for a remote wakeup */
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (status == 0 && !port_is_suspended(hub, portstatus)) {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ pm_wakeup_event(&udev->dev, 0);
+ goto SuspendCleared;
+ }
+
+ /* see 7.1.7.7; affects power usage, but not budgeting */
+ if (hub_is_superspeed(hub->hdev))
+ status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0);
+ else
+ status = usb_clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_SUSPEND);
+ if (status) {
+ dev_dbg(&port_dev->dev, "can't resume, status %d\n", status);
+ } else {
+ /* drive resume for USB_RESUME_TIMEOUT msec */
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""));
+ msleep(USB_RESUME_TIMEOUT);
+
+ /* Virtual root hubs can trigger on GET_PORT_STATUS to
+ * stop resume signaling. Then finish the resume
+ * sequence.
+ */
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ }
+
+ SuspendCleared:
+ if (status == 0) {
+ udev->port_is_suspended = 0;
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ } else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
+ }
+
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ }
+
+ if (udev->persist_enabled)
+ status = wait_for_connected(udev, hub, &port1, &portchange,
+ &portstatus);
+
+ status = check_port_resume_type(udev,
+ hub, port1, status, portchange, portstatus);
+ if (status == 0)
+ status = finish_port_resume(udev);
+ if (status < 0) {
+ dev_dbg(&udev->dev, "can't resume, status %d\n", status);
+ hub_port_logical_disconnect(hub, port1);
+ } else {
+ /* Try to enable USB2 hardware LPM */
+ usb_enable_usb2_hardware_lpm(udev);
+
+ /* Try to enable USB3 LTM */
+ usb_enable_ltm(udev);
+ }
+
+ usb_unlock_port(port_dev);
+
+ return status;
+}
+
+int usb_remote_wakeup(struct usb_device *udev)
+{
+ int status = 0;
+
+ usb_lock_device(udev);
+ if (udev->state == USB_STATE_SUSPENDED) {
+ dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
+ status = usb_autoresume_device(udev);
+ if (status == 0) {
+ /* Let the drivers do their thing, then... */
+ usb_autosuspend_device(udev);
+ }
+ }
+ usb_unlock_device(udev);
+ return status;
+}
+
+/* Returns 1 if there was a remote wakeup and a connect status change. */
+static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+ u16 portstatus, u16 portchange)
+ __must_hold(&port_dev->status_lock)
+{
+ struct usb_port *port_dev = hub->ports[port - 1];
+ struct usb_device *hdev;
+ struct usb_device *udev;
+ int connect_change = 0;
+ u16 link_state;
+ int ret;
+
+ hdev = hub->hdev;
+ udev = port_dev->child;
+ if (!hub_is_superspeed(hdev)) {
+ if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+ return 0;
+ usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+ } else {
+ link_state = portstatus & USB_PORT_STAT_LINK_STATE;
+ if (!udev || udev->state != USB_STATE_SUSPENDED ||
+ (link_state != USB_SS_PORT_LS_U0 &&
+ link_state != USB_SS_PORT_LS_U1 &&
+ link_state != USB_SS_PORT_LS_U2))
+ return 0;
+ }
+
+ if (udev) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+
+ usb_unlock_port(port_dev);
+ ret = usb_remote_wakeup(udev);
+ usb_lock_port(port_dev);
+ if (ret < 0)
+ connect_change = 1;
+ } else {
+ ret = -ENODEV;
+ hub_port_disable(hub, port, 1);
+ }
+ dev_dbg(&port_dev->dev, "resume, status %d\n", ret);
+ return connect_change;
+}
+
+static int check_ports_changed(struct usb_hub *hub)
+{
+ int port1;
+
+ for (port1 = 1; port1 <= hub->hdev->maxchild; ++port1) {
+ u16 portstatus, portchange;
+ int status;
+
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (!status && portchange)
+ return 1;
+ }
+ return 0;
+}
+
+static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+ struct usb_device *hdev = hub->hdev;
+ unsigned port1;
+ int status;
+
+ /*
+ * Warn if children aren't already suspended.
+ * Also, add up the number of wakeup-enabled descendants.
+ */
+ hub->wakeup_enabled_descendants = 0;
+ for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+
+ if (udev && udev->can_submit) {
+ dev_warn(&port_dev->dev, "device %s not suspended yet\n",
+ dev_name(&udev->dev));
+ if (PMSG_IS_AUTO(msg))
+ return -EBUSY;
+ }
+ if (udev)
+ hub->wakeup_enabled_descendants +=
+ wakeup_enabled_descendants(udev);
+ }
+
+ if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
+ /* check if there are changes pending on hub ports */
+ if (check_ports_changed(hub)) {
+ if (PMSG_IS_AUTO(msg))
+ return -EBUSY;
+ pm_wakeup_event(&hdev->dev, 2000);
+ }
+ }
+
+ if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
+ /* Enable hub to send remote wakeup for all ports. */
+ for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+ status = set_port_feature(hdev,
+ port1 |
+ USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
+ USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
+ USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
+ USB_PORT_FEAT_REMOTE_WAKE_MASK);
+ }
+ }
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+
+ /* stop hub_wq and related activity */
+ hub_quiesce(hub, HUB_SUSPEND);
+ return 0;
+}
+
+/* Report wakeup requests from the ports of a resuming root hub */
+static void report_wakeup_requests(struct usb_hub *hub)
+{
+ struct usb_device *hdev = hub->hdev;
+ struct usb_device *udev;
+ struct usb_hcd *hcd;
+ unsigned long resuming_ports;
+ int i;
+
+ if (hdev->parent)
+ return; /* Not a root hub */
+
+ hcd = bus_to_hcd(hdev->bus);
+ if (hcd->driver->get_resuming_ports) {
+
+ /*
+ * The get_resuming_ports() method returns a bitmap (origin 0)
+ * of ports which have started wakeup signaling but have not
+ * yet finished resuming. During system resume we will
+ * resume all the enabled ports, regardless of any wakeup
+ * signals, which means the wakeup requests would be lost.
+ * To prevent this, report them to the PM core here.
+ */
+ resuming_ports = hcd->driver->get_resuming_ports(hcd);
+ for (i = 0; i < hdev->maxchild; ++i) {
+ if (test_bit(i, &resuming_ports)) {
+ udev = hub->ports[i]->child;
+ if (udev)
+ pm_wakeup_event(&udev->dev, 0);
+ }
+ }
+ }
+}
+
+static int hub_resume(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_activate(hub, HUB_RESUME);
+
+ /*
+ * This should be called only for system resume, not runtime resume.
+ * We can't tell the difference here, so some wakeup requests will be
+ * reported at the wrong time or more than once. This shouldn't
+ * matter much, so long as they do get reported.
+ */
+ report_wakeup_requests(hub);
+ return 0;
+}
+
+static int hub_reset_resume(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_activate(hub, HUB_RESET_RESUME);
+ return 0;
+}
+
+/**
+ * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
+ * @rhdev: struct usb_device for the root hub
+ *
+ * The USB host controller driver calls this function when its root hub
+ * is resumed and Vbus power has been interrupted or the controller
+ * has been reset. The routine marks @rhdev as having lost power.
+ * When the hub driver is resumed it will take notice and carry out
+ * power-session recovery for all the "USB-PERSIST"-enabled child devices;
+ * the others will be disconnected.
+ */
+void usb_root_hub_lost_power(struct usb_device *rhdev)
+{
+ dev_notice(&rhdev->dev, "root hub lost power or was reset\n");
+ rhdev->reset_resume = 1;
+}
+EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
+static const char * const usb3_lpm_names[] = {
+ "U0",
+ "U1",
+ "U2",
+ "U3",
+};
+
+/*
+ * Send a Set SEL control transfer to the device, prior to enabling
+ * device-initiated U1 or U2. This lets the device know the exit latencies from
+ * the time the device initiates a U1 or U2 exit, to the time it will receive a
+ * packet from the host.
+ *
+ * This function will fail if the SEL or PEL values for udev are greater than
+ * the maximum allowed values for the link state to be enabled.
+ */
+static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
+{
+ struct usb_set_sel_req *sel_values;
+ unsigned long long u1_sel;
+ unsigned long long u1_pel;
+ unsigned long long u2_sel;
+ unsigned long long u2_pel;
+ int ret;
+
+ if (udev->state != USB_STATE_CONFIGURED)
+ return 0;
+
+ /* Convert SEL and PEL stored in ns to us */
+ u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+ u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+
+ /*
+ * Make sure that the calculated SEL and PEL values for the link
+ * state we're enabling aren't bigger than the max SEL/PEL
+ * value that will fit in the SET SEL control transfer.
+ * Otherwise the device would get an incorrect idea of the exit
+ * latency for the link state, and could start a device-initiated
+ * U1/U2 when the exit latencies are too high.
+ */
+ if ((state == USB3_LPM_U1 &&
+ (u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
+ u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
+ (state == USB3_LPM_U2 &&
+ (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
+ u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
+ dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n",
+ usb3_lpm_names[state], u1_sel, u1_pel);
+ return -EINVAL;
+ }
+
+ /*
+ * If we're enabling device-initiated LPM for one link state,
+ * but the other link state has a too high SEL or PEL value,
+ * just set those values to the max in the Set SEL request.
+ */
+ if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ /*
+ * usb_enable_lpm() can be called as part of a failed device reset,
+ * which may be initiated by an error path of a mass storage driver.
+ * Therefore, use GFP_NOIO.
+ */
+ sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
+ if (!sel_values)
+ return -ENOMEM;
+
+ sel_values->u1_sel = u1_sel;
+ sel_values->u1_pel = u1_pel;
+ sel_values->u2_sel = cpu_to_le16(u2_sel);
+ sel_values->u2_pel = cpu_to_le16(u2_pel);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_SEL,
+ USB_RECIP_DEVICE,
+ 0, 0,
+ sel_values, sizeof *(sel_values),
+ USB_CTRL_SET_TIMEOUT);
+ kfree(sel_values);
+ return ret;
+}
+
+/*
+ * Enable or disable device-initiated U1 or U2 transitions.
+ */
+static int usb_set_device_initiated_lpm(struct usb_device *udev,
+ enum usb3_link_state state, bool enable)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_DEVICE_U1_ENABLE;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_DEVICE_U2_ENABLE;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
+ __func__, enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ if (udev->state != USB_STATE_CONFIGURED) {
+ dev_dbg(&udev->dev, "%s: Can't %s %s state "
+ "for unconfigured device.\n",
+ __func__, enable ? "enable" : "disable",
+ usb3_lpm_names[state]);
+ return 0;
+ }
+
+ if (enable) {
+ /*
+ * Now send the control transfer to enable device-initiated LPM
+ * for either U1 or U2.
+ */
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ }
+ if (ret < 0) {
+ dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
+ enable ? "Enable" : "Disable",
+ usb3_lpm_names[state]);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static int usb_set_lpm_timeout(struct usb_device *udev,
+ enum usb3_link_state state, int timeout)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_PORT_FEAT_U1_TIMEOUT;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_PORT_FEAT_U2_TIMEOUT;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
+ timeout != USB3_LPM_DEVICE_INITIATED) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
+ "which is a reserved value.\n",
+ usb3_lpm_names[state], timeout);
+ return -EINVAL;
+ }
+
+ ret = set_port_feature(udev->parent,
+ USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
+ feature);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
+ "error code %i\n", usb3_lpm_names[state],
+ timeout, ret);
+ return -EBUSY;
+ }
+ if (state == USB3_LPM_U1)
+ udev->u1_params.timeout = timeout;
+ else
+ udev->u2_params.timeout = timeout;
+ return 0;
+}
+
+/*
+ * Don't allow device intiated U1/U2 if the system exit latency + one bus
+ * interval is greater than the minimum service interval of any active
+ * periodic endpoint. See USB 3.2 section 9.4.9
+ */
+static bool usb_device_may_initiate_lpm(struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ unsigned int sel; /* us */
+ int i, j;
+
+ if (state == USB3_LPM_U1)
+ sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ else if (state == USB3_LPM_U2)
+ sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ else
+ return false;
+
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf;
+ struct usb_endpoint_descriptor *desc;
+ unsigned int interval;
+
+ intf = udev->actconfig->interface[i];
+ if (!intf)
+ continue;
+
+ for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++) {
+ desc = &intf->cur_altsetting->endpoint[j].desc;
+
+ if (usb_endpoint_xfer_int(desc) ||
+ usb_endpoint_xfer_isoc(desc)) {
+ interval = (1 << (desc->bInterval - 1)) * 125;
+ if (sel + 125 > interval)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*
+ * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
+ * U1/U2 entry.
+ *
+ * We will attempt to enable U1 or U2, but there are no guarantees that the
+ * control transfers to set the hub timeout or enable device-initiated U1/U2
+ * will be successful.
+ *
+ * If the control transfer to enable device-initiated U1/U2 entry fails, then
+ * hub-initiated U1/U2 will be disabled.
+ *
+ * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
+ * driver know about it. If that call fails, it should be harmless, and just
+ * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
+ */
+static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ int timeout, ret;
+ __u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
+ __le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
+
+ /* If the device says it doesn't have *any* exit latency to come out of
+ * U1 or U2, it's probably lying. Assume it doesn't implement that link
+ * state.
+ */
+ if ((state == USB3_LPM_U1 && u1_mel == 0) ||
+ (state == USB3_LPM_U2 && u2_mel == 0))
+ return;
+
+ /*
+ * First, let the device know about the exit latencies
+ * associated with the link state we're about to enable.
+ */
+ ret = usb_req_set_sel(udev, state);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n",
+ usb3_lpm_names[state]);
+ return;
+ }
+
+ /* We allow the host controller to set the U1/U2 timeout internally
+ * first, so that it can change its schedule to account for the
+ * additional latency to send data to a device in a lower power
+ * link state.
+ */
+ timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
+
+ /* xHCI host controller doesn't want to enable this LPM state. */
+ if (timeout == 0)
+ return;
+
+ if (timeout < 0) {
+ dev_warn(&udev->dev, "Could not enable %s link state, "
+ "xHCI error %i.\n", usb3_lpm_names[state],
+ timeout);
+ return;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, timeout)) {
+ /* If we can't set the parent hub U1/U2 timeout,
+ * device-initiated LPM won't be allowed either, so let the xHCI
+ * host know that this link state won't be enabled.
+ */
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+ return;
+ }
+
+ /* Only a configured device will accept the Set Feature
+ * U1/U2_ENABLE
+ */
+ if (udev->actconfig &&
+ usb_device_may_initiate_lpm(udev, state)) {
+ if (usb_set_device_initiated_lpm(udev, state, true)) {
+ /*
+ * Request to enable device initiated U1/U2 failed,
+ * better to turn off lpm in this case.
+ */
+ usb_set_lpm_timeout(udev, state, 0);
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+ return;
+ }
+ }
+
+ if (state == USB3_LPM_U1)
+ udev->usb3_lpm_u1_enabled = 1;
+ else if (state == USB3_LPM_U2)
+ udev->usb3_lpm_u2_enabled = 1;
+}
+/*
+ * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
+ * U1/U2 entry.
+ *
+ * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
+ * If zero is returned, the parent will not allow the link to go into U1/U2.
+ *
+ * If zero is returned, device-initiated U1/U2 entry may still be enabled, but
+ * it won't have an effect on the bus link state because the parent hub will
+ * still disallow device-initiated U1/U2 entry.
+ *
+ * If zero is returned, the xHCI host controller may still think U1/U2 entry is
+ * possible. The result will be slightly more bus bandwidth will be taken up
+ * (to account for U1/U2 exit latency), but it should be harmless.
+ */
+static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ switch (state) {
+ case USB3_LPM_U1:
+ case USB3_LPM_U2:
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, 0))
+ return -EBUSY;
+
+ usb_set_device_initiated_lpm(udev, state, false);
+
+ if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
+ dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
+ "bus schedule bandwidth may be impacted.\n",
+ usb3_lpm_names[state]);
+
+ /* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM
+ * is disabled. Hub will disallows link to enter U1/U2 as well,
+ * even device is initiating LPM. Hence LPM is disabled if hub LPM
+ * timeout set to 0, no matter device-initiated LPM is disabled or
+ * not.
+ */
+ if (state == USB3_LPM_U1)
+ udev->usb3_lpm_u1_enabled = 0;
+ else if (state == USB3_LPM_U2)
+ udev->usb3_lpm_u2_enabled = 0;
+
+ return 0;
+}
+
+/*
+ * Disable hub-initiated and device-initiated U1 and U2 entry.
+ * Caller must own the bandwidth_mutex.
+ *
+ * This will call usb_enable_lpm() on failure, which will decrement
+ * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
+ */
+int usb_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ if (!udev || !udev->parent ||
+ udev->speed < USB_SPEED_SUPER ||
+ !udev->lpm_capable ||
+ udev->state < USB_STATE_DEFAULT)
+ return 0;
+
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
+ return 0;
+
+ udev->lpm_disable_count++;
+ if ((udev->u1_params.timeout == 0 && udev->u2_params.timeout == 0))
+ return 0;
+
+ /* If LPM is enabled, attempt to disable it. */
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
+ goto enable_lpm;
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
+ goto enable_lpm;
+
+ return 0;
+
+enable_lpm:
+ usb_enable_lpm(udev);
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret;
+
+ if (!hcd)
+ return -EINVAL;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ ret = usb_disable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+/*
+ * Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The
+ * xHCI host policy may prevent U1 or U2 from being enabled.
+ *
+ * Other callers may have disabled link PM, so U1 and U2 entry will be disabled
+ * until the lpm_disable_count drops to zero. Caller must own the
+ * bandwidth_mutex.
+ */
+void usb_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+ struct usb_hub *hub;
+ struct usb_port *port_dev;
+
+ if (!udev || !udev->parent ||
+ udev->speed < USB_SPEED_SUPER ||
+ !udev->lpm_capable ||
+ udev->state < USB_STATE_DEFAULT)
+ return;
+
+ udev->lpm_disable_count--;
+ hcd = bus_to_hcd(udev->bus);
+ /* Double check that we can both enable and disable LPM.
+ * Device must be configured to accept set feature U1/U2 timeout.
+ */
+ if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
+ !hcd->driver->disable_usb3_lpm_timeout)
+ return;
+
+ if (udev->lpm_disable_count > 0)
+ return;
+
+ hub = usb_hub_to_struct_hub(udev->parent);
+ if (!hub)
+ return;
+
+ port_dev = hub->ports[udev->portnum - 1];
+
+ if (port_dev->usb3_lpm_u1_permit)
+ usb_enable_link_state(hcd, udev, USB3_LPM_U1);
+
+ if (port_dev->usb3_lpm_u2_permit)
+ usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+}
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
+void usb_unlocked_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!hcd)
+ return;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ usb_enable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+/* usb3 devices use U3 for disabled, make sure remote wakeup is disabled */
+static void hub_usb3_port_prepare_disable(struct usb_hub *hub,
+ struct usb_port *port_dev)
+{
+ struct usb_device *udev = port_dev->child;
+ int ret;
+
+ if (udev && udev->port_is_suspended && udev->do_remote_wakeup) {
+ ret = hub_set_port_link_state(hub, port_dev->portnum,
+ USB_SS_PORT_LS_U0);
+ if (!ret) {
+ msleep(USB_RESUME_TIMEOUT);
+ ret = usb_disable_remote_wakeup(udev);
+ }
+ if (ret)
+ dev_warn(&udev->dev,
+ "Port disable: can't disable remote wake\n");
+ udev->do_remote_wakeup = 0;
+ }
+}
+
+#else /* CONFIG_PM */
+
+#define hub_suspend NULL
+#define hub_resume NULL
+#define hub_reset_resume NULL
+
+static inline void hub_usb3_port_prepare_disable(struct usb_hub *hub,
+ struct usb_port *port_dev) { }
+
+int usb_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+void usb_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+void usb_unlocked_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+int usb_disable_ltm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_ltm);
+
+void usb_enable_ltm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_ltm);
+
+static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+ u16 portstatus, u16 portchange)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*
+ * USB-3 does not have a similar link state as USB-2 that will avoid negotiating
+ * a connection with a plugged-in cable but will signal the host when the cable
+ * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
+ */
+static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *hdev = hub->hdev;
+ int ret = 0;
+
+ if (!hub->error) {
+ if (hub_is_superspeed(hub->hdev)) {
+ hub_usb3_port_prepare_disable(hub, port_dev);
+ ret = hub_set_port_link_state(hub, port_dev->portnum,
+ USB_SS_PORT_LS_U3);
+ } else {
+ ret = usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_ENABLE);
+ }
+ }
+ if (port_dev->child && set_state)
+ usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
+ if (ret && ret != -ENODEV)
+ dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
+ 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:
+ *
+ * Between connect detection and reset signaling there must be a delay
+ * of 100ms at least for debounce and power-settling. The corresponding
+ * timer shall restart whenever the downstream port detects a disconnect.
+ *
+ * Apparently there are some bluetooth and irda-dongles and a number of
+ * low-speed devices for which this debounce period may last over a second.
+ * Not covered by the spec - but easy to deal with.
+ *
+ * This implementation uses a 1500ms total debounce timeout; if the
+ * connection isn't stable by then it returns -ETIMEDOUT. It checks
+ * every 25ms for transient disconnects. When the port status has been
+ * unchanged for 100ms it returns the port status.
+ */
+int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)
+{
+ int ret;
+ u16 portchange, portstatus;
+ unsigned connection = 0xffff;
+ int total_time, stable_time = 0;
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+
+ for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
+ ret = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (ret < 0)
+ return ret;
+
+ if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
+ if (!must_be_connected ||
+ (connection == USB_PORT_STAT_CONNECTION))
+ stable_time += HUB_DEBOUNCE_STEP;
+ if (stable_time >= HUB_DEBOUNCE_STABLE)
+ break;
+ } else {
+ stable_time = 0;
+ connection = portstatus & USB_PORT_STAT_CONNECTION;
+ }
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ }
+
+ if (total_time >= HUB_DEBOUNCE_TIMEOUT)
+ break;
+ msleep(HUB_DEBOUNCE_STEP);
+ }
+
+ dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n",
+ total_time, stable_time, portstatus);
+
+ if (stable_time < HUB_DEBOUNCE_STABLE)
+ return -ETIMEDOUT;
+ return portstatus;
+}
+
+void usb_ep0_reinit(struct usb_device *udev)
+{
+ usb_disable_endpoint(udev, 0 + USB_DIR_IN, true);
+ usb_disable_endpoint(udev, 0 + USB_DIR_OUT, true);
+ usb_enable_endpoint(udev, &udev->ep0, true);
+}
+EXPORT_SYMBOL_GPL(usb_ep0_reinit);
+
+#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
+#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
+
+static int hub_set_address(struct usb_device *udev, int devnum)
+{
+ int retval;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ /*
+ * The host controller will choose the device address,
+ * instead of the core having chosen it earlier
+ */
+ if (!hcd->driver->address_device && devnum <= 1)
+ return -EINVAL;
+ if (udev->state == USB_STATE_ADDRESS)
+ return 0;
+ if (udev->state != USB_STATE_DEFAULT)
+ return -EINVAL;
+ if (hcd->driver->address_device)
+ retval = hcd->driver->address_device(hcd, udev);
+ else
+ retval = usb_control_msg(udev, usb_sndaddr0pipe(),
+ USB_REQ_SET_ADDRESS, 0, devnum, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (retval == 0) {
+ update_devnum(udev, devnum);
+ /* Device now using proper address. */
+ usb_set_device_state(udev, USB_STATE_ADDRESS);
+ usb_ep0_reinit(udev);
+ }
+ return retval;
+}
+
+/*
+ * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM
+ * when they're plugged into a USB 2.0 port, but they don't work when LPM is
+ * enabled.
+ *
+ * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the
+ * device says it supports the new USB 2.0 Link PM errata by setting the BESL
+ * support bit in the BOS descriptor.
+ */
+static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+ int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
+
+ if (!udev->usb2_hw_lpm_capable || !udev->bos)
+ return;
+
+ if (hub)
+ connect_type = hub->ports[udev->portnum - 1]->connect_type;
+
+ if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) ||
+ connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+ udev->usb2_hw_lpm_allowed = 1;
+ usb_enable_usb2_hardware_lpm(udev);
+ }
+}
+
+static int hub_enable_device(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!hcd->driver->enable_device)
+ return 0;
+ if (udev->state == USB_STATE_ADDRESS)
+ return 0;
+ if (udev->state != USB_STATE_DEFAULT)
+ return -EINVAL;
+
+ return hcd->driver->enable_device(hcd, udev);
+}
+
+/* Reset device, (re)assign address, get device descriptor.
+ * Device connection must be stable, no more debouncing needed.
+ * Returns device in USB_STATE_ADDRESS, except on error.
+ *
+ * If this is called for an already-existing device (as part of
+ * usb_reset_and_verify_device), the caller must own the device lock and
+ * the port lock. For a newly detected device that is not accessible
+ * through any global pointers, it's not necessary to lock the device,
+ * but it is still necessary to lock the port.
+ */
+static int
+hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
+ int retry_counter)
+{
+ struct usb_device *hdev = hub->hdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ int retries, operations, retval, i;
+ unsigned delay = HUB_SHORT_RESET_TIME;
+ enum usb_device_speed oldspeed = udev->speed;
+ const char *speed;
+ int devnum = udev->devnum;
+ const char *driver_name;
+
+ /* root hub ports have a slightly longer reset period
+ * (from USB 2.0 spec, section 7.1.7.5)
+ */
+ if (!hdev->parent) {
+ delay = HUB_ROOT_RESET_TIME;
+ if (port1 == hdev->bus->otg_port)
+ hdev->bus->b_hnp_enable = 0;
+ }
+
+ /* Some low speed devices have problems with the quick delay, so */
+ /* be a bit pessimistic with those devices. RHbug #23670 */
+ if (oldspeed == USB_SPEED_LOW)
+ delay = HUB_LONG_RESET_TIME;
+
+ /* Reset the device; full speed may morph to high speed */
+ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
+ retval = hub_port_reset(hub, port1, udev, delay, false);
+ if (retval < 0) /* error or disconnect */
+ goto fail;
+ /* success, speed is known */
+
+ retval = -ENODEV;
+
+ /* Don't allow speed changes at reset, except usb 3.0 to faster */
+ if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
+ !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
+ dev_dbg(&udev->dev, "device reset changed speed!\n");
+ goto fail;
+ }
+ oldspeed = udev->speed;
+
+ /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
+ * it's fixed size except for full speed devices.
+ * For Wireless USB devices, ep0 max packet is always 512 (tho
+ * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
+ */
+ switch (udev->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER:
+ case USB_SPEED_WIRELESS: /* fixed at 512 */
+ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
+ break;
+ case USB_SPEED_HIGH: /* fixed at 64 */
+ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
+ break;
+ case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
+ /* to determine the ep0 maxpacket size, try to read
+ * the device descriptor to get bMaxPacketSize0 and
+ * then correct our initial guess.
+ */
+ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
+ break;
+ case USB_SPEED_LOW: /* fixed at 8 */
+ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
+ break;
+ default:
+ goto fail;
+ }
+
+ if (udev->speed == USB_SPEED_WIRELESS)
+ speed = "variable speed Wireless";
+ else
+ speed = usb_speed_string(udev->speed);
+
+ /*
+ * The controller driver may be NULL if the controller device
+ * is the middle device between platform device and roothub.
+ * This middle device may not need a device driver due to
+ * all hardware control can be at platform device driver, this
+ * platform device is usually a dual-role USB controller device.
+ */
+ if (udev->bus->controller->driver)
+ driver_name = udev->bus->controller->driver->name;
+ else
+ driver_name = udev->bus->sysdev->driver->name;
+
+ if (udev->speed < USB_SPEED_SUPER)
+ dev_info(&udev->dev,
+ "%s %s USB device number %d using %s\n",
+ (udev->config) ? "reset" : "new", speed,
+ devnum, driver_name);
+
+ /* Set up TT records, if needed */
+ if (hdev->tt) {
+ udev->tt = hdev->tt;
+ udev->ttport = hdev->ttport;
+ } else if (udev->speed != USB_SPEED_HIGH
+ && hdev->speed == USB_SPEED_HIGH) {
+ if (!hub->tt.hub) {
+ dev_err(&udev->dev, "parent hub has no TT\n");
+ retval = -EINVAL;
+ goto fail;
+ }
+ udev->tt = &hub->tt;
+ udev->ttport = port1;
+ }
+
+ /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
+ * Because device hardware and firmware is sometimes buggy in
+ * this area, and this is how Linux has done it for ages.
+ * Change it cautiously.
+ *
+ * NOTE: If use_new_scheme() is true we will start by issuing
+ * a 64-byte GET_DESCRIPTOR request. This is what Windows does,
+ * so it may help with some non-standards-compliant devices.
+ * Otherwise we start with SET_ADDRESS and then try to read the
+ * first 8 bytes of the device descriptor to get the ep0 maxpacket
+ * value.
+ */
+ for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
+ bool did_new_scheme = false;
+
+ if (use_new_scheme(udev, retry_counter, port_dev)) {
+ struct usb_device_descriptor *buf;
+ int r = 0;
+
+ did_new_scheme = true;
+ retval = hub_enable_device(udev);
+ if (retval < 0) {
+ dev_err(&udev->dev,
+ "hub failed to enable device, error %d\n",
+ retval);
+ goto fail;
+ }
+
+#define GET_DESCRIPTOR_BUFSIZE 64
+ buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
+ if (!buf) {
+ retval = -ENOMEM;
+ continue;
+ }
+
+ /* Retry on all errors; some devices are flakey.
+ * 255 is for WUSB devices, we actually need to use
+ * 512 (WUSB1.0[4.8.1]).
+ */
+ for (operations = 0; operations < 3; ++operations) {
+ buf->bMaxPacketSize0 = 0;
+ r = usb_control_msg(udev, usb_rcvaddr0pipe(),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ USB_DT_DEVICE << 8, 0,
+ buf, GET_DESCRIPTOR_BUFSIZE,
+ initial_descriptor_timeout);
+ switch (buf->bMaxPacketSize0) {
+ case 8: case 16: case 32: case 64: case 255:
+ if (buf->bDescriptorType ==
+ USB_DT_DEVICE) {
+ r = 0;
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ if (r == 0)
+ r = -EPROTO;
+ break;
+ }
+ /*
+ * Some devices time out if they are powered on
+ * when already connected. They need a second
+ * reset. But only on the first attempt,
+ * lest we get into a time out/reset loop
+ */
+ if (r == 0 || (r == -ETIMEDOUT &&
+ retries == 0 &&
+ udev->speed > USB_SPEED_FULL))
+ break;
+ }
+ udev->descriptor.bMaxPacketSize0 =
+ buf->bMaxPacketSize0;
+ kfree(buf);
+
+ retval = hub_port_reset(hub, port1, udev, delay, false);
+ if (retval < 0) /* error or disconnect */
+ goto fail;
+ if (oldspeed != udev->speed) {
+ dev_dbg(&udev->dev,
+ "device reset changed speed!\n");
+ retval = -ENODEV;
+ goto fail;
+ }
+ if (r) {
+ if (r != -ENODEV)
+ dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+ r);
+ retval = -EMSGSIZE;
+ continue;
+ }
+#undef GET_DESCRIPTOR_BUFSIZE
+ }
+
+ /*
+ * If device is WUSB, we already assigned an
+ * unauthorized address in the Connect Ack sequence;
+ * authorization will assign the final address.
+ */
+ if (udev->wusb == 0) {
+ for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
+ retval = hub_set_address(udev, devnum);
+ if (retval >= 0)
+ break;
+ msleep(200);
+ }
+ if (retval < 0) {
+ if (retval != -ENODEV)
+ dev_err(&udev->dev, "device not accepting address %d, error %d\n",
+ devnum, retval);
+ goto fail;
+ }
+ if (udev->speed >= USB_SPEED_SUPER) {
+ devnum = udev->devnum;
+ dev_info(&udev->dev,
+ "%s SuperSpeed%s%s USB device number %d using %s\n",
+ (udev->config) ? "reset" : "new",
+ (udev->speed == USB_SPEED_SUPER_PLUS) ?
+ "Plus Gen 2" : " Gen 1",
+ (udev->rx_lanes == 2 && udev->tx_lanes == 2) ?
+ "x2" : "",
+ devnum, driver_name);
+ }
+
+ /* cope with hardware quirkiness:
+ * - let SET_ADDRESS settle, some device hardware wants it
+ * - read ep0 maxpacket even for high and low speed,
+ */
+ msleep(10);
+ /* use_new_scheme() checks the speed which may have
+ * changed since the initial look so we cache the result
+ * in did_new_scheme
+ */
+ if (did_new_scheme)
+ break;
+ }
+
+ retval = usb_get_device_descriptor(udev, 8);
+ if (retval < 8) {
+ if (retval != -ENODEV)
+ dev_err(&udev->dev,
+ "device descriptor read/8, error %d\n",
+ retval);
+ 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;
+ }
+ }
+ if (retval)
+ goto fail;
+
+ /*
+ * Some superspeed devices have finished the link training process
+ * and attached to a superspeed hub port, but the device descriptor
+ * got from those devices show they aren't superspeed devices. Warm
+ * reset the port attached by the devices can fix them.
+ */
+ if ((udev->speed >= USB_SPEED_SUPER) &&
+ (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
+ dev_err(&udev->dev, "got a wrong device descriptor, "
+ "warm reset device\n");
+ hub_port_reset(hub, port1, udev,
+ HUB_BH_RESET_TIME, true);
+ retval = -EINVAL;
+ goto fail;
+ }
+
+ if (udev->descriptor.bMaxPacketSize0 == 0xff ||
+ udev->speed >= USB_SPEED_SUPER)
+ i = 512;
+ else
+ i = udev->descriptor.bMaxPacketSize0;
+ if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
+ if (udev->speed == USB_SPEED_LOW ||
+ !(i == 8 || i == 16 || i == 32 || i == 64)) {
+ dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
+ retval = -EMSGSIZE;
+ goto fail;
+ }
+ if (udev->speed == USB_SPEED_FULL)
+ dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
+ else
+ dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
+ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
+ usb_ep0_reinit(udev);
+ }
+
+ retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
+ if (retval < (signed)sizeof(udev->descriptor)) {
+ if (retval != -ENODEV)
+ dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+ retval);
+ if (retval >= 0)
+ retval = -ENOMSG;
+ goto fail;
+ }
+
+ usb_detect_quirks(udev);
+
+ if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
+ retval = usb_get_bos_descriptor(udev);
+ if (!retval) {
+ udev->lpm_capable = usb_device_supports_lpm(udev);
+ usb_set_lpm_parameters(udev);
+ }
+ }
+
+ retval = 0;
+ /* notify HCD that we have a device connected and addressed */
+ if (hcd->driver->update_device)
+ hcd->driver->update_device(hcd, udev);
+ hub_set_initial_usb2_lpm_policy(udev);
+fail:
+ if (retval) {
+ hub_port_disable(hub, port1, 0);
+ update_devnum(udev, devnum); /* for disconnect processing */
+ }
+ return retval;
+}
+
+static void
+check_highspeed(struct usb_hub *hub, struct usb_device *udev, int port1)
+{
+ struct usb_qualifier_descriptor *qual;
+ int status;
+
+ if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER)
+ return;
+
+ qual = kmalloc(sizeof *qual, GFP_KERNEL);
+ if (qual == NULL)
+ return;
+
+ status = usb_get_descriptor(udev, USB_DT_DEVICE_QUALIFIER, 0,
+ qual, sizeof *qual);
+ if (status == sizeof *qual) {
+ dev_info(&udev->dev, "not running at top speed; "
+ "connect to a high speed hub\n");
+ /* hub LEDs are probably harder to miss than syslog */
+ if (hub->has_indicators) {
+ hub->indicator[port1-1] = INDICATOR_GREEN_BLINK;
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, 0);
+ }
+ }
+ kfree(qual);
+}
+
+static unsigned
+hub_power_remaining(struct usb_hub *hub)
+{
+ struct usb_device *hdev = hub->hdev;
+ int remaining;
+ int port1;
+
+ if (!hub->limited_power)
+ return 0;
+
+ remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
+ for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ unsigned unit_load;
+ int delta;
+
+ if (!udev)
+ continue;
+ if (hub_is_superspeed(udev))
+ unit_load = 150;
+ else
+ unit_load = 100;
+
+ /*
+ * Unconfigured devices may not use more than one unit load,
+ * or 8mA for OTG ports
+ */
+ if (udev->actconfig)
+ delta = usb_get_max_power(udev, udev->actconfig);
+ else if (port1 != udev->bus->otg_port || hdev->parent)
+ delta = unit_load;
+ else
+ delta = 8;
+ if (delta > hub->mA_per_port)
+ dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n",
+ delta, hub->mA_per_port);
+ remaining -= delta;
+ }
+ if (remaining < 0) {
+ dev_warn(hub->intfdev, "%dmA over power budget!\n",
+ -remaining);
+ remaining = 0;
+ }
+ return remaining;
+}
+
+static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
+ u16 portchange)
+{
+ int status = -ENODEV;
+ int i;
+ unsigned unit_load;
+ struct usb_device *hdev = hub->hdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ static int unreliable_port = -1;
+ bool retry_locked;
+
+ /* Disconnect any existing devices under this port */
+ if (udev) {
+ if (hcd->usb_phy && !hdev->parent)
+ usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
+ usb_disconnect(&port_dev->child);
+ }
+
+ /* We can forget about a "removed" device when there's a physical
+ * disconnect or the connect status changes.
+ */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
+ (portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_bit(port1, hub->removed_bits);
+
+ if (portchange & (USB_PORT_STAT_C_CONNECTION |
+ USB_PORT_STAT_C_ENABLE)) {
+ status = hub_port_debounce_be_stable(hub, port1);
+ if (status < 0) {
+ if (status != -ENODEV &&
+ port1 != unreliable_port &&
+ printk_ratelimit())
+ dev_err(&port_dev->dev, "connect-debounce failed\n");
+ portstatus &= ~USB_PORT_STAT_CONNECTION;
+ unreliable_port = port1;
+ } else {
+ portstatus = status;
+ }
+ }
+
+ /* Return now if debouncing failed or nothing is connected or
+ * the device was "removed".
+ */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
+ test_bit(port1, hub->removed_bits)) {
+
+ /*
+ * maybe switch power back on (e.g. root hub was reset)
+ * but only if the port isn't owned by someone else.
+ */
+ if (hub_is_port_power_switchable(hub)
+ && !port_is_power_on(hub, portstatus)
+ && !port_dev->port_owner)
+ set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ goto done;
+ return;
+ }
+ if (hub_is_superspeed(hub->hdev))
+ unit_load = 150;
+ else
+ unit_load = 100;
+
+ status = 0;
+
+ for (i = 0; i < SET_CONFIG_TRIES; i++) {
+ usb_lock_port(port_dev);
+ mutex_lock(hcd->address0_mutex);
+ retry_locked = true;
+
+ /* reallocate for each attempt, since references
+ * to the previous one can escape in various ways
+ */
+ udev = usb_alloc_dev(hdev, hdev->bus, port1);
+ if (!udev) {
+ dev_err(&port_dev->dev,
+ "couldn't allocate usb_device\n");
+ mutex_unlock(hcd->address0_mutex);
+ usb_unlock_port(port_dev);
+ goto done;
+ }
+
+ usb_set_device_state(udev, USB_STATE_POWERED);
+ udev->bus_mA = hub->mA_per_port;
+ udev->level = hdev->level + 1;
+ udev->wusb = hub_is_wusb(hub);
+
+ /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
+ if (hub_is_superspeed(hub->hdev))
+ udev->speed = USB_SPEED_SUPER;
+ else
+ udev->speed = USB_SPEED_UNKNOWN;
+
+ choose_devnum(udev);
+ if (udev->devnum <= 0) {
+ status = -ENOTCONN; /* Don't retry */
+ goto loop;
+ }
+
+ /* reset (non-USB 3.0 devices) and get descriptor */
+ status = hub_port_init(hub, udev, port1, i);
+ if (status < 0)
+ goto loop;
+
+ mutex_unlock(hcd->address0_mutex);
+ usb_unlock_port(port_dev);
+ retry_locked = false;
+
+ if (udev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(2000);
+
+ /* consecutive bus-powered hubs aren't reliable; they can
+ * violate the voltage drop budget. if the new child has
+ * a "powered" LED, users should notice we didn't enable it
+ * (without reading syslog), even without per-port LEDs
+ * on the parent.
+ */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
+ && udev->bus_mA <= unit_load) {
+ u16 devstat;
+
+ status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0,
+ &devstat);
+ if (status) {
+ dev_dbg(&udev->dev, "get status %d ?\n", status);
+ goto loop_disable;
+ }
+ if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ dev_err(&udev->dev,
+ "can't connect bus-powered hub "
+ "to this port\n");
+ if (hub->has_indicators) {
+ hub->indicator[port1-1] =
+ INDICATOR_AMBER_BLINK;
+ queue_delayed_work(
+ system_power_efficient_wq,
+ &hub->leds, 0);
+ }
+ status = -ENOTCONN; /* Don't retry */
+ goto loop_disable;
+ }
+ }
+
+ /* check for devices running slower than they could */
+ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
+ && udev->speed == USB_SPEED_FULL
+ && highspeed_hubs != 0)
+ check_highspeed(hub, udev, port1);
+
+ /* Store the parent's children[] pointer. At this point
+ * udev becomes globally accessible, although presumably
+ * no one will look at it until hdev is unlocked.
+ */
+ status = 0;
+
+ mutex_lock(&usb_port_peer_mutex);
+
+ /* We mustn't add new devices if the parent hub has
+ * been disconnected; we would race with the
+ * recursively_mark_NOTATTACHED() routine.
+ */
+ spin_lock_irq(&device_state_lock);
+ if (hdev->state == USB_STATE_NOTATTACHED)
+ status = -ENOTCONN;
+ else
+ port_dev->child = udev;
+ spin_unlock_irq(&device_state_lock);
+ mutex_unlock(&usb_port_peer_mutex);
+
+ /* Run it through the hoops (find a driver, etc) */
+ if (!status) {
+ status = usb_new_device(udev);
+ if (status) {
+ mutex_lock(&usb_port_peer_mutex);
+ spin_lock_irq(&device_state_lock);
+ port_dev->child = NULL;
+ spin_unlock_irq(&device_state_lock);
+ mutex_unlock(&usb_port_peer_mutex);
+ } else {
+ if (hcd->usb_phy && !hdev->parent)
+ usb_phy_notify_connect(hcd->usb_phy,
+ udev->speed);
+ }
+ }
+
+ if (status)
+ goto loop_disable;
+
+ status = hub_power_remaining(hub);
+ if (status)
+ dev_dbg(hub->intfdev, "%dmA power budget left\n", status);
+
+ return;
+
+loop_disable:
+ hub_port_disable(hub, port1, 1);
+loop:
+ usb_ep0_reinit(udev);
+ release_devnum(udev);
+ hub_free_dev(udev);
+ if (retry_locked) {
+ mutex_unlock(hcd->address0_mutex);
+ usb_unlock_port(port_dev);
+ }
+ 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 ||
+ !(hcd->driver->port_handed_over)(hcd, port1)) {
+ if (status != -ENOTCONN && status != -ENODEV)
+ dev_err(&port_dev->dev,
+ "unable to enumerate USB device\n");
+ }
+
+done:
+ hub_port_disable(hub, port1, 1);
+ if (hcd->driver->relinquish_port && !hub->hdev->parent) {
+ if (status != -ENOTCONN && status != -ENODEV)
+ hcd->driver->relinquish_port(hcd, port1);
+ }
+}
+
+/* Handle physical or logical connection change events.
+ * This routine is called when:
+ * a port connection-change occurs;
+ * a port enable-change occurs (often caused by EMI);
+ * usb_reset_and_verify_device() encounters changed descriptors (as from
+ * a firmware download)
+ * caller already locked the hub
+ */
+static void hub_port_connect_change(struct usb_hub *hub, int port1,
+ u16 portstatus, u16 portchange)
+ __must_hold(&port_dev->status_lock)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ int status = -ENODEV;
+
+ dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
+ portchange, portspeed(hub, portstatus));
+
+ if (hub->has_indicators) {
+ set_port_led(hub, port1, HUB_LED_AUTO);
+ hub->indicator[port1-1] = INDICATOR_AUTO;
+ }
+
+#ifdef CONFIG_USB_OTG
+ /* during HNP, don't repeat the debounce */
+ if (hub->hdev->bus->is_b_host)
+ portchange &= ~(USB_PORT_STAT_C_CONNECTION |
+ USB_PORT_STAT_C_ENABLE);
+#endif
+
+ /* Try to resuscitate an existing device */
+ if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
+ udev->state != USB_STATE_NOTATTACHED) {
+ if (portstatus & USB_PORT_STAT_ENABLE) {
+ status = 0; /* Nothing to do */
+#ifdef CONFIG_PM
+ } else if (udev->state == USB_STATE_SUSPENDED &&
+ udev->persist_enabled) {
+ /* For a suspended device, treat this as a
+ * remote wakeup event.
+ */
+ usb_unlock_port(port_dev);
+ status = usb_remote_wakeup(udev);
+ usb_lock_port(port_dev);
+#endif
+ } else {
+ /* Don't resuscitate */;
+ }
+ }
+ clear_bit(port1, hub->change_bits);
+
+ /* successfully revalidated the connection */
+ if (status == 0)
+ return;
+
+ usb_unlock_port(port_dev);
+ hub_port_connect(hub, port1, portstatus, portchange);
+ usb_lock_port(port_dev);
+}
+
+static void port_event(struct usb_hub *hub, int port1)
+ __must_hold(&port_dev->status_lock)
+{
+ int connect_change;
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_device *udev = port_dev->child;
+ struct usb_device *hdev = hub->hdev;
+ u16 portstatus, portchange;
+
+ connect_change = test_bit(port1, hub->change_bits);
+ clear_bit(port1, hub->event_bits);
+ clear_bit(port1, hub->wakeup_bits);
+
+ if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)
+ return;
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
+ connect_change = 1;
+ }
+
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ if (!connect_change)
+ dev_dbg(&port_dev->dev, "enable change, status %08x\n",
+ portstatus);
+ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
+
+ /*
+ * EM interference sometimes causes badly shielded USB devices
+ * to be shutdown by the hub, this hack enables them again.
+ * Works at least with mouse driver.
+ */
+ if (!(portstatus & USB_PORT_STAT_ENABLE)
+ && !connect_change && udev) {
+ dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n");
+ connect_change = 1;
+ }
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ u16 status = 0, unused;
+ port_dev->over_current_count++;
+
+ dev_dbg(&port_dev->dev, "over-current change #%u\n",
+ port_dev->over_current_count);
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ msleep(100); /* Cool down */
+ hub_power_on(hub, true);
+ hub_port_status(hub, port1, &status, &unused);
+ if (status & USB_PORT_STAT_OVERCURRENT)
+ dev_err(&port_dev->dev, "over-current condition\n");
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ dev_dbg(&port_dev->dev, "reset change\n");
+ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET);
+ }
+ if ((portchange & USB_PORT_STAT_C_BH_RESET)
+ && hub_is_superspeed(hdev)) {
+ dev_dbg(&port_dev->dev, "warm reset change\n");
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ }
+ if (portchange & USB_PORT_STAT_C_LINK_STATE) {
+ dev_dbg(&port_dev->dev, "link state change\n");
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ }
+ if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
+ dev_warn(&port_dev->dev, "config error\n");
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
+ }
+
+ /* skip port actions that require the port to be powered on */
+ if (!pm_runtime_active(&port_dev->dev))
+ return;
+
+ if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
+ connect_change = 1;
+
+ /*
+ * Warm reset a USB3 protocol port if it's in
+ * SS.Inactive state.
+ */
+ if (hub_port_warm_reset_required(hub, port1, portstatus)) {
+ dev_dbg(&port_dev->dev, "do warm reset\n");
+ if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
+ || udev->state == USB_STATE_NOTATTACHED) {
+ if (hub_port_reset(hub, port1, NULL,
+ HUB_BH_RESET_TIME, true) < 0)
+ hub_port_disable(hub, port1, 1);
+ } else {
+ usb_unlock_port(port_dev);
+ usb_lock_device(udev);
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+ usb_lock_port(port_dev);
+ connect_change = 0;
+ }
+ }
+
+ if (connect_change)
+ hub_port_connect_change(hub, port1, portstatus, portchange);
+}
+
+static void hub_event(struct work_struct *work)
+{
+ struct usb_device *hdev;
+ struct usb_interface *intf;
+ struct usb_hub *hub;
+ struct device *hub_dev;
+ u16 hubstatus;
+ u16 hubchange;
+ int i, ret;
+
+ hub = container_of(work, struct usb_hub, events);
+ hdev = hub->hdev;
+ hub_dev = hub->intfdev;
+ intf = to_usb_interface(hub_dev);
+
+ dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
+ hdev->state, hdev->maxchild,
+ /* NOTE: expects max 15 ports... */
+ (u16) hub->change_bits[0],
+ (u16) hub->event_bits[0]);
+
+ /* Lock the device, then check to see if we were
+ * disconnected while waiting for the lock to succeed. */
+ usb_lock_device(hdev);
+ if (unlikely(hub->disconnected))
+ goto out_hdev_lock;
+
+ /* If the hub has died, clean up after it */
+ if (hdev->state == USB_STATE_NOTATTACHED) {
+ hub->error = -ENODEV;
+ hub_quiesce(hub, HUB_DISCONNECT);
+ goto out_hdev_lock;
+ }
+
+ /* Autoresume */
+ ret = usb_autopm_get_interface(intf);
+ if (ret) {
+ dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
+ goto out_hdev_lock;
+ }
+
+ /* If this is an inactive hub, do nothing */
+ if (hub->quiescing)
+ goto out_autopm;
+
+ if (hub->error) {
+ dev_dbg(hub_dev, "resetting for error %d\n", hub->error);
+
+ ret = usb_reset_device(hdev);
+ if (ret) {
+ dev_dbg(hub_dev, "error resetting hub: %d\n", ret);
+ goto out_autopm;
+ }
+
+ hub->nerrors = 0;
+ hub->error = 0;
+ }
+
+ /* deal with port status changes */
+ for (i = 1; i <= hdev->maxchild; i++) {
+ struct usb_port *port_dev = hub->ports[i - 1];
+
+ if (test_bit(i, hub->event_bits)
+ || test_bit(i, hub->change_bits)
+ || test_bit(i, hub->wakeup_bits)) {
+ /*
+ * The get_noresume and barrier ensure that if
+ * the port was in the process of resuming, we
+ * flush that work and keep the port active for
+ * the duration of the port_event(). However,
+ * if the port is runtime pm suspended
+ * (powered-off), we leave it in that state, run
+ * an abbreviated port_event(), and move on.
+ */
+ pm_runtime_get_noresume(&port_dev->dev);
+ pm_runtime_barrier(&port_dev->dev);
+ usb_lock_port(port_dev);
+ port_event(hub, i);
+ usb_unlock_port(port_dev);
+ pm_runtime_put_sync(&port_dev->dev);
+ }
+ }
+
+ /* deal with hub status changes */
+ if (test_and_clear_bit(0, hub->event_bits) == 0)
+ ; /* do nothing */
+ else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
+ dev_err(hub_dev, "get_hub_status failed\n");
+ else {
+ if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+ dev_dbg(hub_dev, "power change\n");
+ clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
+ if (hubstatus & HUB_STATUS_LOCAL_POWER)
+ /* FIXME: Is this always true? */
+ hub->limited_power = 1;
+ else
+ hub->limited_power = 0;
+ }
+ if (hubchange & HUB_CHANGE_OVERCURRENT) {
+ u16 status = 0;
+ u16 unused;
+
+ dev_dbg(hub_dev, "over-current change\n");
+ clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
+ msleep(500); /* Cool down */
+ hub_power_on(hub, true);
+ hub_hub_status(hub, &status, &unused);
+ if (status & HUB_STATUS_OVERCURRENT)
+ dev_err(hub_dev, "over-current condition\n");
+ }
+ }
+
+out_autopm:
+ /* Balance the usb_autopm_get_interface() above */
+ usb_autopm_put_interface_no_suspend(intf);
+out_hdev_lock:
+ usb_unlock_device(hdev);
+
+ /* Balance the stuff in kick_hub_wq() and allow autosuspend */
+ usb_autopm_put_interface(intf);
+ kref_put(&hub->kref, hub_release);
+}
+
+static const struct usb_device_id hub_id_table[] = {
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = USB_VENDOR_SMSC,
+ .idProduct = USB_PRODUCT_USB5534B,
+ .bInterfaceClass = USB_CLASS_HUB,
+ .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT,
+ .idVendor = USB_VENDOR_CYPRESS,
+ .idProduct = USB_PRODUCT_CY7C65632,
+ .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_INT_CLASS,
+ .idVendor = USB_VENDOR_GENESYS_LOGIC,
+ .bInterfaceClass = USB_CLASS_HUB,
+ .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
+ { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
+ .bDeviceClass = USB_CLASS_HUB},
+ { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+ .bInterfaceClass = USB_CLASS_HUB},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, hub_id_table);
+
+static struct usb_driver hub_driver = {
+ .name = "hub",
+ .probe = hub_probe,
+ .disconnect = hub_disconnect,
+ .suspend = hub_suspend,
+ .resume = hub_resume,
+ .reset_resume = hub_reset_resume,
+ .pre_reset = hub_pre_reset,
+ .post_reset = hub_post_reset,
+ .unlocked_ioctl = hub_ioctl,
+ .id_table = hub_id_table,
+ .supports_autosuspend = 1,
+};
+
+int usb_hub_init(void)
+{
+ if (usb_register(&hub_driver) < 0) {
+ printk(KERN_ERR "%s: can't register hub driver\n",
+ usbcore_name);
+ return -1;
+ }
+
+ /*
+ * The workqueue needs to be freezable to avoid interfering with
+ * USB-PERSIST port handover. Otherwise it might see that a full-speed
+ * device was gone before the EHCI controller had handed its port
+ * over to the companion full-speed controller.
+ */
+ hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);
+ if (hub_wq)
+ return 0;
+
+ /* Fall through if kernel_thread failed */
+ usb_deregister(&hub_driver);
+ pr_err("%s: can't allocate workqueue for usb hub\n", usbcore_name);
+
+ return -1;
+}
+
+void usb_hub_cleanup(void)
+{
+ destroy_workqueue(hub_wq);
+
+ /*
+ * Hub resources are freed for us by usb_deregister. It calls
+ * usb_driver_purge on every device which in turn calls that
+ * devices disconnect function if it is using this driver.
+ * The hub_disconnect function takes care of releasing the
+ * individual hub resources. -greg
+ */
+ 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)
+ *
+ * WARNING - don't use this routine to reset a composite device
+ * (one with multiple interfaces owned by separate drivers)!
+ * Use usb_reset_device() instead.
+ *
+ * Do a port reset, reassign the device's address, and establish its
+ * former operating configuration. If the reset fails, or the device's
+ * descriptors change from their values before the reset, or the original
+ * configuration and altsettings cannot be restored, a flag will be set
+ * telling hub_wq to pretend the device has been disconnected and then
+ * re-connected. All drivers will be unbound, and the device will be
+ * re-enumerated and probed all over again.
+ *
+ * Return: 0 if the reset succeeded, -ENODEV if the device has been
+ * flagged for logical disconnection, or some other negative error code
+ * if the reset wasn't even attempted.
+ *
+ * Note:
+ * The caller must own the device lock and the port lock, the latter is
+ * taken by usb_reset_device(). For example, it's safe to use
+ * usb_reset_device() from a driver probe() routine after downloading
+ * new firmware. For calls that might not occur during probe(), drivers
+ * should lock the device using usb_lock_device_for_reset().
+ *
+ * Locking exception: This routine may also be called from within an
+ * autoresume handler. Such usage won't conflict with other tasks
+ * holding the device lock because these tasks should always call
+ * usb_autopm_resume_device(), thereby preventing any unwanted
+ * autoresume. The autoresume handler is expected to have already
+ * acquired the port lock before calling this routine.
+ */
+static int usb_reset_and_verify_device(struct usb_device *udev)
+{
+ struct usb_device *parent_hdev = udev->parent;
+ struct usb_hub *parent_hub;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_device_descriptor descriptor = udev->descriptor;
+ struct usb_host_bos *bos;
+ int i, j, ret = 0;
+ int port1 = udev->portnum;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED) {
+ dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
+ udev->state);
+ return -EINVAL;
+ }
+
+ if (!parent_hdev)
+ return -EISDIR;
+
+ parent_hub = usb_hub_to_struct_hub(parent_hdev);
+
+ /* Disable USB2 hardware LPM.
+ * It will be re-enabled by the enumeration process.
+ */
+ usb_disable_usb2_hardware_lpm(udev);
+
+ /* Disable LPM while we reset the device and reinstall the alt settings.
+ * Device-initiated LPM, and system exit latency settings are cleared
+ * when the device is reset, so we have to set them up again.
+ */
+ ret = usb_unlocked_disable_lpm(udev);
+ if (ret) {
+ dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__);
+ goto re_enumerate_no_bos;
+ }
+
+ bos = udev->bos;
+ udev->bos = NULL;
+
+ mutex_lock(hcd->address0_mutex);
+
+ for (i = 0; i < SET_CONFIG_TRIES; ++i) {
+
+ /* ep0 maxpacket size may change; let the HCD know about it.
+ * Other endpoints will be handled by re-enumeration. */
+ usb_ep0_reinit(udev);
+ ret = hub_port_init(parent_hub, udev, port1, i);
+ if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
+ break;
+ }
+ mutex_unlock(hcd->address0_mutex);
+
+ if (ret < 0)
+ goto re_enumerate;
+
+ /* Device might have changed firmware (DFU or similar) */
+ if (descriptors_changed(udev, &descriptor, bos)) {
+ dev_info(&udev->dev, "device firmware changed\n");
+ udev->descriptor = descriptor; /* for disconnect() calls */
+ goto re_enumerate;
+ }
+
+ /* Restore the device's previous configuration */
+ if (!udev->actconfig)
+ goto done;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
+ if (ret < 0) {
+ dev_warn(&udev->dev,
+ "Busted HC? Not enough HCD resources for "
+ "old configuration.\n");
+ mutex_unlock(hcd->bandwidth_mutex);
+ goto re_enumerate;
+ }
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ udev->actconfig->desc.bConfigurationValue, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&udev->dev,
+ "can't restore configuration #%d (error=%d)\n",
+ udev->actconfig->desc.bConfigurationValue, ret);
+ mutex_unlock(hcd->bandwidth_mutex);
+ goto re_enumerate;
+ }
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_set_device_state(udev, USB_STATE_CONFIGURED);
+
+ /* Put interfaces back into the same altsettings as before.
+ * Don't bother to send the Set-Interface request for interfaces
+ * that were already in altsetting 0; besides being unnecessary,
+ * many devices can't handle it. Instead just reset the host-side
+ * endpoint state.
+ */
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_host_config *config = udev->actconfig;
+ struct usb_interface *intf = config->interface[i];
+ struct usb_interface_descriptor *desc;
+
+ desc = &intf->cur_altsetting->desc;
+ if (desc->bAlternateSetting == 0) {
+ usb_disable_interface(udev, intf, true);
+ usb_enable_interface(udev, intf, true);
+ ret = 0;
+ } else {
+ /* Let the bandwidth allocation function know that this
+ * device has been reset, and it will have to use
+ * alternate setting 0 as the current alternate setting.
+ */
+ intf->resetting_device = 1;
+ ret = usb_set_interface(udev, desc->bInterfaceNumber,
+ desc->bAlternateSetting);
+ intf->resetting_device = 0;
+ }
+ if (ret < 0) {
+ dev_err(&udev->dev, "failed to restore interface %d "
+ "altsetting %d (error=%d)\n",
+ desc->bInterfaceNumber,
+ desc->bAlternateSetting,
+ ret);
+ goto re_enumerate;
+ }
+ /* Resetting also frees any allocated streams */
+ for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++)
+ intf->cur_altsetting->endpoint[j].streams = 0;
+ }
+
+done:
+ /* Now that the alt settings are re-installed, enable LTM and LPM. */
+ usb_enable_usb2_hardware_lpm(udev);
+ usb_unlocked_enable_lpm(udev);
+ usb_enable_ltm(udev);
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
+ return 0;
+
+re_enumerate:
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
+re_enumerate_no_bos:
+ /* LPM state doesn't matter when we're about to destroy the device. */
+ hub_port_logical_disconnect(parent_hub, port1);
+ return -ENODEV;
+}
+
+/**
+ * usb_reset_device - warn interface drivers and perform a USB port reset
+ * @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
+ * the reset is over (using their post_reset method).
+ *
+ * Return: The same as for usb_reset_and_verify_device().
+ *
+ * Note:
+ * The caller must own the device lock. For example, it's safe to use
+ * this from a driver probe() routine after downloading new firmware.
+ * For calls that might not occur during probe(), drivers should lock
+ * the device using usb_lock_device_for_reset().
+ *
+ * If an interface is currently being probed or disconnected, we assume
+ * its driver knows how to handle resets. For all other interfaces,
+ * if the driver doesn't have pre_reset and post_reset methods then
+ * we attempt to unbind it and rebind afterward.
+ */
+int usb_reset_device(struct usb_device *udev)
+{
+ int ret;
+ int i;
+ unsigned int noio_flag;
+ struct usb_port *port_dev;
+ struct usb_host_config *config = udev->actconfig;
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+
+ if (udev->state == USB_STATE_NOTATTACHED) {
+ dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
+ udev->state);
+ return -EINVAL;
+ }
+
+ if (!udev->parent) {
+ /* this requires hcd-specific logic; see ohci_restart() */
+ dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
+ return -EISDIR;
+ }
+
+ port_dev = hub->ports[udev->portnum - 1];
+
+ /*
+ * Don't allocate memory with GFP_KERNEL in current
+ * context to avoid possible deadlock if usb mass
+ * storage interface or usbnet interface(iSCSI case)
+ * is included in current configuration. The easist
+ * approach is to do it for every device reset,
+ * because the device 'memalloc_noio' flag may have
+ * not been set before reseting the usb device.
+ */
+ noio_flag = memalloc_noio_save();
+
+ /* Prevent autosuspend during the reset */
+ usb_autoresume_device(udev);
+
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+ int unbind = 0;
+
+ if (cintf->dev.driver) {
+ drv = to_usb_driver(cintf->dev.driver);
+ if (drv->pre_reset && drv->post_reset)
+ unbind = (drv->pre_reset)(cintf);
+ else if (cintf->condition ==
+ USB_INTERFACE_BOUND)
+ unbind = 1;
+ if (unbind)
+ usb_forced_unbind_intf(cintf);
+ }
+ }
+ }
+
+ usb_lock_port(port_dev);
+ ret = usb_reset_and_verify_device(udev);
+ usb_unlock_port(port_dev);
+
+ if (config) {
+ for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+ int rebind = cintf->needs_binding;
+
+ if (!rebind && cintf->dev.driver) {
+ drv = to_usb_driver(cintf->dev.driver);
+ if (drv->post_reset)
+ rebind = (drv->post_reset)(cintf);
+ else if (cintf->condition ==
+ USB_INTERFACE_BOUND)
+ rebind = 1;
+ if (rebind)
+ cintf->needs_binding = 1;
+ }
+ }
+
+ /* If the reset failed, hub_wq will unbind drivers later */
+ if (ret == 0)
+ usb_unbind_and_rebind_marked_interfaces(udev);
+ }
+
+ usb_autosuspend_device(udev);
+ memalloc_noio_restore(noio_flag);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_reset_device);
+
+
+/**
+ * usb_queue_reset_device - Reset a USB device from an atomic context
+ * @iface: USB interface belonging to the device to reset
+ *
+ * This function can be used to reset a USB device from an atomic
+ * context, where usb_reset_device() won't work (as it blocks).
+ *
+ * Doing a reset via this method is functionally equivalent to calling
+ * usb_reset_device(), except for the fact that it is delayed to a
+ * workqueue. This means that any drivers bound to other interfaces
+ * might be unbound, as well as users from usbfs in user space.
+ *
+ * Corner cases:
+ *
+ * - Scheduling two resets at the same time from two different drivers
+ * attached to two different interfaces of the same device is
+ * possible; depending on how the driver attached to each interface
+ * handles ->pre_reset(), the second reset might happen or not.
+ *
+ * - If the reset is delayed so long that the interface is unbound from
+ * its driver, the reset will be skipped.
+ *
+ * - This function can be called during .probe(). It can also be called
+ * during .disconnect(), but doing so is pointless because the reset
+ * will not occur. If you really want to reset the device during
+ * .disconnect(), call usb_reset_device() directly -- but watch out
+ * for nested unbinding issues!
+ */
+void usb_queue_reset_device(struct usb_interface *iface)
+{
+ if (schedule_work(&iface->reset_ws))
+ usb_get_intf(iface);
+}
+EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+/**
+ * usb_hub_find_child - Get the pointer of child device
+ * attached to the port which is specified by @port1.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num to indicate which port the child device
+ * is attached to.
+ *
+ * USB drivers call this function to get hub's child device
+ * pointer.
+ *
+ * Return: %NULL if input param is invalid and
+ * child's usb_device pointer if non-NULL.
+ */
+struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+ int port1)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+
+ if (port1 < 1 || port1 > hdev->maxchild)
+ return NULL;
+ return hub->ports[port1 - 1]->child;
+}
+EXPORT_SYMBOL_GPL(usb_hub_find_child);
+
+void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+ struct usb_hub_descriptor *desc)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ enum usb_port_connect_type connect_type;
+ int i;
+
+ if (!hub)
+ return;
+
+ if (!hub_is_superspeed(hdev)) {
+ for (i = 1; i <= hdev->maxchild; i++) {
+ struct usb_port *port_dev = hub->ports[i - 1];
+
+ connect_type = port_dev->connect_type;
+ if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+ u8 mask = 1 << (i%8);
+
+ if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) {
+ dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");
+ desc->u.hs.DeviceRemovable[i/8] |= mask;
+ }
+ }
+ }
+ } else {
+ u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);
+
+ for (i = 1; i <= hdev->maxchild; i++) {
+ struct usb_port *port_dev = hub->ports[i - 1];
+
+ connect_type = port_dev->connect_type;
+ if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
+ u16 mask = 1 << i;
+
+ if (!(port_removable & mask)) {
+ dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");
+ port_removable |= mask;
+ }
+ }
+ }
+
+ desc->u.ss.DeviceRemovable = cpu_to_le16(port_removable);
+ }
+}
+
+#ifdef CONFIG_ACPI
+/**
+ * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ *
+ * Return: Port's acpi handle if successful, %NULL if params are
+ * invalid.
+ */
+acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+ int port1)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+
+ if (!hub)
+ return NULL;
+
+ return ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
+}
+#endif
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
new file mode 100644
index 000000000..df3aa0b69
--- /dev/null
+++ b/drivers/usb/core/hub.h
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * usb hub driver head file
+ *
+ * Copyright (C) 1999 Linus Torvalds
+ * Copyright (C) 1999 Johannes Erdfelt
+ * Copyright (C) 1999 Gregory P. Smith
+ * Copyright (C) 2001 Brad Hards (bhards@bigpond.net.au)
+ * Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com)
+ *
+ * move struct usb_hub to this file.
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+struct usb_hub {
+ struct device *intfdev; /* the "interface" device */
+ struct usb_device *hdev;
+ struct kref kref;
+ struct urb *urb; /* for interrupt polling pipe */
+
+ /* buffer for urb ... with extra space in case of babble */
+ u8 (*buffer)[8];
+ union {
+ struct usb_hub_status hub;
+ struct usb_port_status port;
+ } *status; /* buffer for status reports */
+ struct mutex status_mutex; /* for the status buffer */
+
+ int error; /* last reported error */
+ int nerrors; /* track consecutive errors */
+
+ unsigned long event_bits[1]; /* status change bitmask */
+ unsigned long change_bits[1]; /* ports with logical connect
+ status change */
+ unsigned long removed_bits[1]; /* ports with a "removed"
+ device present */
+ unsigned long wakeup_bits[1]; /* ports that have signaled
+ remote wakeup */
+ unsigned long power_bits[1]; /* ports that are powered */
+ unsigned long child_usage_bits[1]; /* ports powered on for
+ children */
+ unsigned long warm_reset_bits[1]; /* ports requesting warm
+ reset recovery */
+#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
+#error event_bits[] is too short!
+#endif
+
+ struct usb_hub_descriptor *descriptor; /* class descriptor */
+ struct usb_tt tt; /* Transaction Translator */
+
+ unsigned mA_per_port; /* current for each child */
+#ifdef CONFIG_PM
+ unsigned wakeup_enabled_descendants;
+#endif
+
+ unsigned limited_power:1;
+ unsigned quiescing:1;
+ unsigned disconnected:1;
+ unsigned in_reset:1;
+ unsigned quirk_disable_autosuspend:1;
+
+ unsigned quirk_check_port_auto_suspend:1;
+
+ unsigned has_indicators:1;
+ u8 indicator[USB_MAXCHILDREN];
+ struct delayed_work leds;
+ struct delayed_work init_work;
+ struct work_struct events;
+ struct usb_port **ports;
+};
+
+/**
+ * struct usb port - kernel's representation of a usb port
+ * @child: usb device attached to the port
+ * @dev: generic device interface
+ * @port_owner: port's owner
+ * @peer: related usb2 and usb3 ports (share the same connector)
+ * @req: default pm qos request for hubs without port power control
+ * @connect_type: port's connect type
+ * @location: opaque representation of platform connector location
+ * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
+ * @portnum: port index num based one
+ * @is_superspeed cache super-speed status
+ * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
+ * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
+ */
+struct usb_port {
+ struct usb_device *child;
+ struct device dev;
+ struct usb_dev_state *port_owner;
+ struct usb_port *peer;
+ struct dev_pm_qos_request *req;
+ enum usb_port_connect_type connect_type;
+ usb_port_location_t location;
+ struct mutex status_lock;
+ u32 over_current_count;
+ u8 portnum;
+ u32 quirks;
+ unsigned int is_superspeed:1;
+ unsigned int usb3_lpm_u1_permit:1;
+ unsigned int usb3_lpm_u2_permit:1;
+};
+
+#define to_usb_port(_dev) \
+ container_of(_dev, struct usb_port, dev)
+
+extern int usb_hub_create_port_device(struct usb_hub *hub,
+ int port1);
+extern void usb_hub_remove_port_device(struct usb_hub *hub,
+ int port1);
+extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
+ int port1, bool set);
+extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
+extern int hub_port_debounce(struct usb_hub *hub, int port1,
+ bool must_be_connected);
+extern int usb_clear_port_feature(struct usb_device *hdev,
+ int port1, int feature);
+
+static inline bool hub_is_port_power_switchable(struct usb_hub *hub)
+{
+ __le16 hcs;
+
+ if (!hub)
+ return false;
+ hcs = hub->descriptor->wHubCharacteristics;
+ return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM;
+}
+
+static inline int hub_is_superspeed(struct usb_device *hdev)
+{
+ return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS;
+}
+
+static inline int hub_is_superspeedplus(struct usb_device *hdev)
+{
+ return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
+ le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
+ hdev->bos->ssp_cap);
+}
+
+static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
+{
+ unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2;
+
+ if (!hub->hdev->parent) /* root hub */
+ return delay;
+ else /* Wait at least 100 msec for power to become stable */
+ return max(delay, 100U);
+}
+
+static inline int hub_port_debounce_be_connected(struct usb_hub *hub,
+ int port1)
+{
+ return hub_port_debounce(hub, port1, true);
+}
+
+static inline int hub_port_debounce_be_stable(struct usb_hub *hub,
+ int port1)
+{
+ return hub_port_debounce(hub, port1, false);
+}
diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c
new file mode 100644
index 000000000..c12ac5660
--- /dev/null
+++ b/drivers/usb/core/ledtrig-usbport.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB port LED trigger
+ *
+ * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/of.h>
+
+struct usbport_trig_data {
+ struct led_classdev *led_cdev;
+ struct list_head ports;
+ struct notifier_block nb;
+ int count; /* Amount of connected matching devices */
+};
+
+struct usbport_trig_port {
+ struct usbport_trig_data *data;
+ struct usb_device *hub;
+ int portnum;
+ char *port_name;
+ bool observed;
+ struct device_attribute attr;
+ struct list_head list;
+};
+
+/***************************************
+ * Helpers
+ ***************************************/
+
+/**
+ * usbport_trig_usb_dev_observed - Check if dev is connected to observed port
+ */
+static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data,
+ struct usb_device *usb_dev)
+{
+ struct usbport_trig_port *port;
+
+ if (!usb_dev->parent)
+ return false;
+
+ list_for_each_entry(port, &usbport_data->ports, list) {
+ if (usb_dev->parent == port->hub &&
+ usb_dev->portnum == port->portnum)
+ return port->observed;
+ }
+
+ return false;
+}
+
+static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data)
+{
+ struct usbport_trig_data *usbport_data = data;
+
+ if (usbport_trig_usb_dev_observed(usbport_data, usb_dev))
+ usbport_data->count++;
+
+ return 0;
+}
+
+/**
+ * usbport_trig_update_count - Recalculate amount of connected matching devices
+ */
+static void usbport_trig_update_count(struct usbport_trig_data *usbport_data)
+{
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
+
+ usbport_data->count = 0;
+ usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
+ led_set_brightness(led_cdev, usbport_data->count ? LED_FULL : LED_OFF);
+}
+
+/***************************************
+ * Device attr
+ ***************************************/
+
+static ssize_t usbport_trig_port_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usbport_trig_port *port = container_of(attr,
+ struct usbport_trig_port,
+ attr);
+
+ return sprintf(buf, "%d\n", port->observed) + 1;
+}
+
+static ssize_t usbport_trig_port_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct usbport_trig_port *port = container_of(attr,
+ struct usbport_trig_port,
+ attr);
+
+ if (!strcmp(buf, "0") || !strcmp(buf, "0\n"))
+ port->observed = 0;
+ else if (!strcmp(buf, "1") || !strcmp(buf, "1\n"))
+ port->observed = 1;
+ else
+ return -EINVAL;
+
+ usbport_trig_update_count(port->data);
+
+ return size;
+}
+
+static struct attribute *ports_attrs[] = {
+ NULL,
+};
+
+static const struct attribute_group ports_group = {
+ .name = "ports",
+ .attrs = ports_attrs,
+};
+
+/***************************************
+ * Adding & removing ports
+ ***************************************/
+
+/**
+ * usbport_trig_port_observed - Check if port should be observed
+ */
+static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data,
+ struct usb_device *usb_dev, int port1)
+{
+ struct device *dev = usbport_data->led_cdev->dev;
+ struct device_node *led_np = dev->of_node;
+ struct of_phandle_args args;
+ struct device_node *port_np;
+ int count, i;
+
+ if (!led_np)
+ return false;
+
+ /*
+ * 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");
+ if (count < 0) {
+ dev_warn(dev, "Failed to get trigger sources for %pOF\n",
+ led_np);
+ return false;
+ }
+
+ /* Check list of sources for this specific port */
+ for (i = 0; i < count; i++) {
+ int err;
+
+ err = of_parse_phandle_with_args(led_np, "trigger-sources",
+ "#trigger-source-cells", i,
+ &args);
+ if (err) {
+ dev_err(dev, "Failed to get trigger source phandle at index %d: %d\n",
+ i, err);
+ continue;
+ }
+
+ of_node_put(args.np);
+
+ if (args.np == port_np)
+ return true;
+ }
+
+ return false;
+}
+
+static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
+ struct usb_device *usb_dev,
+ const char *hub_name, int portnum)
+{
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
+ struct usbport_trig_port *port;
+ size_t len;
+ int err;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ port->data = usbport_data;
+ port->hub = usb_dev;
+ port->portnum = portnum;
+ port->observed = usbport_trig_port_observed(usbport_data, usb_dev,
+ portnum);
+
+ len = strlen(hub_name) + 8;
+ port->port_name = kzalloc(len, GFP_KERNEL);
+ if (!port->port_name) {
+ err = -ENOMEM;
+ goto err_free_port;
+ }
+ snprintf(port->port_name, len, "%s-port%d", hub_name, portnum);
+
+ sysfs_attr_init(&port->attr.attr);
+ port->attr.attr.name = port->port_name;
+ port->attr.attr.mode = S_IRUSR | S_IWUSR;
+ port->attr.show = usbport_trig_port_show;
+ port->attr.store = usbport_trig_port_store;
+
+ err = sysfs_add_file_to_group(&led_cdev->dev->kobj, &port->attr.attr,
+ ports_group.name);
+ if (err)
+ goto err_free_port_name;
+
+ list_add_tail(&port->list, &usbport_data->ports);
+
+ return 0;
+
+err_free_port_name:
+ kfree(port->port_name);
+err_free_port:
+ kfree(port);
+err_out:
+ return err;
+}
+
+static int usbport_trig_add_usb_dev_ports(struct usb_device *usb_dev,
+ void *data)
+{
+ struct usbport_trig_data *usbport_data = data;
+ int i;
+
+ for (i = 1; i <= usb_dev->maxchild; i++)
+ usbport_trig_add_port(usbport_data, usb_dev,
+ dev_name(&usb_dev->dev), i);
+
+ return 0;
+}
+
+static void usbport_trig_remove_port(struct usbport_trig_data *usbport_data,
+ struct usbport_trig_port *port)
+{
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
+
+ list_del(&port->list);
+ sysfs_remove_file_from_group(&led_cdev->dev->kobj, &port->attr.attr,
+ ports_group.name);
+ kfree(port->port_name);
+ kfree(port);
+}
+
+static void usbport_trig_remove_usb_dev_ports(struct usbport_trig_data *usbport_data,
+ struct usb_device *usb_dev)
+{
+ struct usbport_trig_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
+ if (port->hub == usb_dev)
+ usbport_trig_remove_port(usbport_data, port);
+ }
+}
+
+/***************************************
+ * Init, exit, etc.
+ ***************************************/
+
+static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct usbport_trig_data *usbport_data =
+ container_of(nb, struct usbport_trig_data, nb);
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
+ struct usb_device *usb_dev = data;
+ bool observed;
+
+ observed = usbport_trig_usb_dev_observed(usbport_data, usb_dev);
+
+ switch (action) {
+ case USB_DEVICE_ADD:
+ usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
+ if (observed && usbport_data->count++ == 0)
+ led_set_brightness(led_cdev, LED_FULL);
+ return NOTIFY_OK;
+ case USB_DEVICE_REMOVE:
+ usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
+ if (observed && --usbport_data->count == 0)
+ led_set_brightness(led_cdev, LED_OFF);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int usbport_trig_activate(struct led_classdev *led_cdev)
+{
+ struct usbport_trig_data *usbport_data;
+ int err;
+
+ usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL);
+ if (!usbport_data)
+ return -ENOMEM;
+ usbport_data->led_cdev = led_cdev;
+
+ /* List of ports */
+ INIT_LIST_HEAD(&usbport_data->ports);
+ err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group);
+ if (err)
+ goto err_free;
+ usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
+ usbport_trig_update_count(usbport_data);
+
+ /* Notifications */
+ usbport_data->nb.notifier_call = usbport_trig_notify;
+ led_set_trigger_data(led_cdev, usbport_data);
+ usb_register_notify(&usbport_data->nb);
+ return 0;
+
+err_free:
+ kfree(usbport_data);
+ return err;
+}
+
+static void usbport_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct usbport_trig_data *usbport_data = led_get_trigger_data(led_cdev);
+ struct usbport_trig_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
+ usbport_trig_remove_port(usbport_data, port);
+ }
+
+ sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
+
+ usb_unregister_notify(&usbport_data->nb);
+
+ kfree(usbport_data);
+}
+
+static struct led_trigger usbport_led_trigger = {
+ .name = "usbport",
+ .activate = usbport_trig_activate,
+ .deactivate = usbport_trig_deactivate,
+};
+
+static int __init usbport_trig_init(void)
+{
+ return led_trigger_register(&usbport_led_trigger);
+}
+
+static void __exit usbport_trig_exit(void)
+{
+ led_trigger_unregister(&usbport_led_trigger);
+}
+
+module_init(usbport_trig_init);
+module_exit(usbport_trig_exit);
+
+MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");
+MODULE_DESCRIPTION("USB port trigger");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
new file mode 100644
index 000000000..152228d33
--- /dev/null
+++ b/drivers/usb/core/message.c
@@ -0,0 +1,2269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * message.c - synchronous message handling
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/pci.h> /* for scatterlist macros */
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/nls.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+#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"
+
+static void cancel_async_set_config(struct usb_device *udev);
+
+struct api_context {
+ struct completion done;
+ int status;
+};
+
+static void usb_api_blocking_completion(struct urb *urb)
+{
+ struct api_context *ctx = urb->context;
+
+ ctx->status = urb->status;
+ complete(&ctx->done);
+}
+
+
+/*
+ * Starts urb and waits for completion or timeout. Note that this call
+ * is NOT interruptible. Many device driver i/o requests should be
+ * interruptible and therefore these drivers should implement their
+ * own interruptible routines.
+ */
+static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+{
+ struct api_context ctx;
+ unsigned long expire;
+ int retval;
+
+ init_completion(&ctx.done);
+ urb->context = &ctx;
+ urb->actual_length = 0;
+ retval = usb_submit_urb(urb, GFP_NOIO);
+ if (unlikely(retval))
+ goto out;
+
+ expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (!wait_for_completion_timeout(&ctx.done, expire)) {
+ usb_kill_urb(urb);
+ retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
+
+ dev_dbg(&urb->dev->dev,
+ "%s timed out on ep%d%s len=%u/%u\n",
+ current->comm,
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length);
+ } else
+ retval = ctx.status;
+out:
+ if (actual_length)
+ *actual_length = urb->actual_length;
+
+ usb_free_urb(urb);
+ return retval;
+}
+
+/*-------------------------------------------------------------------*/
+/* returns status (negative) or length (positive) */
+static int usb_internal_control_msg(struct usb_device *usb_dev,
+ unsigned int pipe,
+ struct usb_ctrlrequest *cmd,
+ void *data, int len, int timeout)
+{
+ struct urb *urb;
+ int retv;
+ int length;
+
+ urb = usb_alloc_urb(0, GFP_NOIO);
+ if (!urb)
+ return -ENOMEM;
+
+ usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
+ len, usb_api_blocking_completion, NULL);
+
+ retv = usb_start_wait_urb(urb, timeout, &length);
+ if (retv < 0)
+ return retv;
+ else
+ return length;
+}
+
+/**
+ * usb_control_msg - Builds a control urb, sends it off and waits for completion
+ * @dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @request: USB message request value
+ * @requesttype: USB message request type value
+ * @value: USB message value
+ * @index: USB message index value
+ * @data: pointer to the data to send
+ * @size: length in bytes of the data to send
+ * @timeout: time in msecs to wait for the message to complete before timing
+ * out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple control message to a specified endpoint and
+ * waits for the message to complete, or timeout.
+ *
+ * Don't use this function from within an interrupt context. If you need
+ * an asynchronous message, or need to send a message from within interrupt
+ * context, use usb_submit_urb(). If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete. Since you
+ * don't have a handle on the URB used, you can't cancel the request.
+ *
+ * Return: If successful, the number of bytes transferred. Otherwise, a negative
+ * error number.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
+ __u8 requesttype, __u16 value, __u16 index, void *data,
+ __u16 size, int timeout)
+{
+ struct usb_ctrlrequest *dr;
+ int ret;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+ if (!dr)
+ return -ENOMEM;
+
+ dr->bRequestType = requesttype;
+ dr->bRequest = request;
+ dr->wValue = cpu_to_le16(value);
+ dr->wIndex = cpu_to_le16(index);
+ dr->wLength = cpu_to_le16(size);
+
+ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+ /* Linger a bit, prior to the next control message. */
+ if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
+ msleep(200);
+
+ kfree(dr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_control_msg);
+
+/**
+ * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ * timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple interrupt message to a specified endpoint and
+ * waits for the message to complete, or timeout.
+ *
+ * Don't use this function from within an interrupt context. If you need
+ * an asynchronous message, or need to send a message from within interrupt
+ * context, use usb_submit_urb() If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete. Since you
+ * don't have a handle on the URB used, you can't cancel the request.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length parameter.
+ */
+int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout);
+}
+EXPORT_SYMBOL_GPL(usb_interrupt_msg);
+
+/**
+ * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ * timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple bulk message to a specified endpoint
+ * and waits for the message to complete, or timeout.
+ *
+ * Don't use this function from within an interrupt context. If you need
+ * an asynchronous message, or need to send a message from within interrupt
+ * context, use usb_submit_urb() If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete. Since you
+ * don't have a handle on the URB used, you can't cancel the request.
+ *
+ * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl,
+ * users are forced to abuse this routine by using it to submit URBs for
+ * interrupt endpoints. We will take the liberty of creating an interrupt URB
+ * (with the default interval) if the target is an interrupt endpoint.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length parameter.
+ *
+ */
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ struct urb *urb;
+ struct usb_host_endpoint *ep;
+
+ ep = usb_pipe_endpoint(usb_dev, pipe);
+ if (!ep || len < 0)
+ return -EINVAL;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT) {
+ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+ usb_fill_int_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL,
+ ep->desc.bInterval);
+ } else
+ usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL);
+
+ return usb_start_wait_urb(urb, timeout, actual_length);
+}
+EXPORT_SYMBOL_GPL(usb_bulk_msg);
+
+/*-------------------------------------------------------------------*/
+
+static void sg_clean(struct usb_sg_request *io)
+{
+ if (io->urbs) {
+ while (io->entries--)
+ usb_free_urb(io->urbs[io->entries]);
+ kfree(io->urbs);
+ io->urbs = NULL;
+ }
+ io->dev = NULL;
+}
+
+static void sg_complete(struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_sg_request *io = urb->context;
+ int status = urb->status;
+
+ spin_lock_irqsave(&io->lock, flags);
+
+ /* In 2.5 we require hcds' endpoint queues not to progress after fault
+ * reports, until the completion callback (this!) returns. That lets
+ * device driver code (like this routine) unlink queued urbs first,
+ * if it needs to, since the HC won't work on them at all. So it's
+ * not possible for page N+1 to overwrite page N, and so on.
+ *
+ * That's only for "hard" faults; "soft" faults (unlinks) sometimes
+ * complete before the HCD can get requests away from hardware,
+ * though never during cleanup after a hard fault.
+ */
+ if (io->status
+ && (io->status != -ECONNRESET
+ || status != -ECONNRESET)
+ && urb->actual_length) {
+ dev_err(io->dev->bus->controller,
+ "dev %s ep%d%s scatterlist error %d/%d\n",
+ io->dev->devpath,
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
+ status, io->status);
+ /* BUG (); */
+ }
+
+ if (io->status == 0 && status && status != -ECONNRESET) {
+ int i, found, retval;
+
+ io->status = status;
+
+ /* the previous urbs, and this one, completed already.
+ * unlink pending urbs so they won't rx/tx bad data.
+ * careful: unlink can sometimes be synchronous...
+ */
+ spin_unlock_irqrestore(&io->lock, flags);
+ for (i = 0, found = 0; i < io->entries; i++) {
+ if (!io->urbs[i])
+ continue;
+ if (found) {
+ usb_block_urb(io->urbs[i]);
+ retval = usb_unlink_urb(io->urbs[i]);
+ if (retval != -EINPROGRESS &&
+ retval != -ENODEV &&
+ retval != -EBUSY &&
+ retval != -EIDRM)
+ dev_err(&io->dev->dev,
+ "%s, unlink --> %d\n",
+ __func__, retval);
+ } else if (urb == io->urbs[i])
+ found = 1;
+ }
+ spin_lock_irqsave(&io->lock, flags);
+ }
+
+ /* on the last completion, signal usb_sg_wait() */
+ io->bytes += urb->actual_length;
+ io->count--;
+ if (!io->count)
+ complete(&io->complete);
+
+ spin_unlock_irqrestore(&io->lock, flags);
+}
+
+
+/**
+ * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
+ * @io: request block being initialized. until usb_sg_wait() returns,
+ * treat this as a pointer to an opaque block of memory,
+ * @dev: the usb device that will send or receive the data
+ * @pipe: endpoint "pipe" used to transfer the data
+ * @period: polling rate for interrupt endpoints, in frames or
+ * (for high speed endpoints) microframes; ignored for bulk
+ * @sg: scatterlist entries
+ * @nents: how many entries in the scatterlist
+ * @length: how many bytes to send from the scatterlist, or zero to
+ * send every byte identified in the list.
+ * @mem_flags: SLAB_* flags affecting memory allocations in this call
+ *
+ * This initializes a scatter/gather request, allocating resources such as
+ * I/O mappings and urb memory (except maybe memory used by USB controller
+ * drivers).
+ *
+ * The request must be issued using usb_sg_wait(), which waits for the I/O to
+ * complete (or to be canceled) and then cleans up all resources allocated by
+ * usb_sg_init().
+ *
+ * The request may be canceled with usb_sg_cancel(), either before or after
+ * usb_sg_wait() is called.
+ *
+ * Return: Zero for success, else a negative errno value.
+ */
+int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+ unsigned pipe, unsigned period, struct scatterlist *sg,
+ int nents, size_t length, gfp_t mem_flags)
+{
+ int i;
+ int urb_flags;
+ int use_sg;
+
+ if (!io || !dev || !sg
+ || usb_pipecontrol(pipe)
+ || usb_pipeisoc(pipe)
+ || nents <= 0)
+ return -EINVAL;
+
+ spin_lock_init(&io->lock);
+ io->dev = dev;
+ io->pipe = pipe;
+
+ if (dev->bus->sg_tablesize > 0) {
+ use_sg = true;
+ io->entries = 1;
+ } else {
+ use_sg = false;
+ io->entries = nents;
+ }
+
+ /* initialize all the urbs we'll use */
+ io->urbs = kmalloc_array(io->entries, sizeof(*io->urbs), mem_flags);
+ if (!io->urbs)
+ goto nomem;
+
+ urb_flags = URB_NO_INTERRUPT;
+ if (usb_pipein(pipe))
+ urb_flags |= URB_SHORT_NOT_OK;
+
+ for_each_sg(sg, sg, io->entries, i) {
+ struct urb *urb;
+ unsigned len;
+
+ urb = usb_alloc_urb(0, mem_flags);
+ if (!urb) {
+ io->entries = i;
+ goto nomem;
+ }
+ io->urbs[i] = urb;
+
+ urb->dev = NULL;
+ urb->pipe = pipe;
+ urb->interval = period;
+ urb->transfer_flags = urb_flags;
+ urb->complete = sg_complete;
+ urb->context = io;
+ urb->sg = sg;
+
+ if (use_sg) {
+ /* There is no single transfer buffer */
+ urb->transfer_buffer = NULL;
+ urb->num_sgs = nents;
+
+ /* A length of zero means transfer the whole sg list */
+ len = length;
+ if (len == 0) {
+ struct scatterlist *sg2;
+ int j;
+
+ for_each_sg(sg, sg2, nents, j)
+ len += sg2->length;
+ }
+ } else {
+ /*
+ * Some systems can't use DMA; they use PIO instead.
+ * For their sakes, transfer_buffer is set whenever
+ * possible.
+ */
+ if (!PageHighMem(sg_page(sg)))
+ urb->transfer_buffer = sg_virt(sg);
+ else
+ urb->transfer_buffer = NULL;
+
+ len = sg->length;
+ if (length) {
+ len = min_t(size_t, len, length);
+ length -= len;
+ if (length == 0)
+ io->entries = i + 1;
+ }
+ }
+ urb->transfer_buffer_length = len;
+ }
+ io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+
+ /* transaction state */
+ io->count = io->entries;
+ io->status = 0;
+ io->bytes = 0;
+ init_completion(&io->complete);
+ return 0;
+
+nomem:
+ sg_clean(io);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(usb_sg_init);
+
+/**
+ * usb_sg_wait - synchronously execute scatter/gather request
+ * @io: request block handle, as initialized with usb_sg_init().
+ * some fields become accessible when this call returns.
+ * Context: !in_interrupt ()
+ *
+ * This function blocks until the specified I/O operation completes. It
+ * leverages the grouping of the related I/O requests to get good transfer
+ * rates, by queueing the requests. At higher speeds, such queuing can
+ * significantly improve USB throughput.
+ *
+ * There are three kinds of completion for this function.
+ *
+ * (1) success, where io->status is zero. The number of io->bytes
+ * transferred is as requested.
+ * (2) error, where io->status is a negative errno value. The number
+ * of io->bytes transferred before the error is usually less
+ * than requested, and can be nonzero.
+ * (3) cancellation, a type of error with status -ECONNRESET that
+ * is initiated by usb_sg_cancel().
+ *
+ * When this function returns, all memory allocated through usb_sg_init() or
+ * this call will have been freed. The request block parameter may still be
+ * passed to usb_sg_cancel(), or it may be freed. It could also be
+ * reinitialized and then reused.
+ *
+ * Data Transfer Rates:
+ *
+ * Bulk transfers are valid for full or high speed endpoints.
+ * The best full speed data rate is 19 packets of 64 bytes each
+ * per frame, or 1216 bytes per millisecond.
+ * The best high speed data rate is 13 packets of 512 bytes each
+ * per microframe, or 52 KBytes per millisecond.
+ *
+ * The reason to use interrupt transfers through this API would most likely
+ * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond
+ * could be transferred. That capability is less useful for low or full
+ * speed interrupt endpoints, which allow at most one packet per millisecond,
+ * of at most 8 or 64 bytes (respectively).
+ *
+ * It is not necessary to call this function to reserve bandwidth for devices
+ * under an xHCI host controller, as the bandwidth is reserved when the
+ * configuration or interface alt setting is selected.
+ */
+void usb_sg_wait(struct usb_sg_request *io)
+{
+ int i;
+ int entries = io->entries;
+
+ /* queue the urbs. */
+ spin_lock_irq(&io->lock);
+ i = 0;
+ while (i < entries && !io->status) {
+ int retval;
+
+ io->urbs[i]->dev = io->dev;
+ spin_unlock_irq(&io->lock);
+
+ retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
+
+ switch (retval) {
+ /* maybe we retrying will recover */
+ case -ENXIO: /* hc didn't queue this one */
+ case -EAGAIN:
+ case -ENOMEM:
+ retval = 0;
+ yield();
+ break;
+
+ /* no error? continue immediately.
+ *
+ * NOTE: to work better with UHCI (4K I/O buffer may
+ * need 3K of TDs) it may be good to limit how many
+ * URBs are queued at once; N milliseconds?
+ */
+ case 0:
+ ++i;
+ cpu_relax();
+ break;
+
+ /* fail any uncompleted urbs */
+ default:
+ io->urbs[i]->status = retval;
+ dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
+ __func__, retval);
+ usb_sg_cancel(io);
+ }
+ spin_lock_irq(&io->lock);
+ if (retval && (io->status == 0 || io->status == -ECONNRESET))
+ io->status = retval;
+ }
+ io->count -= entries - i;
+ if (io->count == 0)
+ complete(&io->complete);
+ spin_unlock_irq(&io->lock);
+
+ /* OK, yes, this could be packaged as non-blocking.
+ * So could the submit loop above ... but it's easier to
+ * solve neither problem than to solve both!
+ */
+ wait_for_completion(&io->complete);
+
+ sg_clean(io);
+}
+EXPORT_SYMBOL_GPL(usb_sg_wait);
+
+/**
+ * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
+ * @io: request block, initialized with usb_sg_init()
+ *
+ * This stops a request after it has been started by usb_sg_wait().
+ * It can also prevents one initialized by usb_sg_init() from starting,
+ * so that call just frees resources allocated to the request.
+ */
+void usb_sg_cancel(struct usb_sg_request *io)
+{
+ unsigned long flags;
+ int i, retval;
+
+ spin_lock_irqsave(&io->lock, flags);
+ if (io->status || io->count == 0) {
+ spin_unlock_irqrestore(&io->lock, flags);
+ return;
+ }
+ /* shut everything down */
+ io->status = -ECONNRESET;
+ io->count++; /* Keep the request alive until we're done */
+ spin_unlock_irqrestore(&io->lock, flags);
+
+ for (i = io->entries - 1; i >= 0; --i) {
+ usb_block_urb(io->urbs[i]);
+
+ retval = usb_unlink_urb(io->urbs[i]);
+ if (retval != -EINPROGRESS
+ && retval != -ENODEV
+ && retval != -EBUSY
+ && retval != -EIDRM)
+ dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
+ __func__, retval);
+ }
+
+ spin_lock_irqsave(&io->lock, flags);
+ io->count--;
+ if (!io->count)
+ complete(&io->complete);
+ spin_unlock_irqrestore(&io->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_sg_cancel);
+
+/*-------------------------------------------------------------------*/
+
+/**
+ * usb_get_descriptor - issues a generic GET_DESCRIPTOR request
+ * @dev: the device whose descriptor is being retrieved
+ * @type: the descriptor type (USB_DT_*)
+ * @index: the number of the descriptor
+ * @buf: where to put the descriptor
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * Gets a USB descriptor. Convenience functions exist to simplify
+ * getting some types of descriptors. Use
+ * usb_get_string() or usb_string() for USB_DT_STRING.
+ * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)
+ * are part of the device structure.
+ * In addition to a number of USB-standard descriptors, some
+ * devices also use class-specific or vendor-specific descriptors.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Return: The number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_descriptor(struct usb_device *dev, unsigned char type,
+ unsigned char index, void *buf, int size)
+{
+ int i;
+ int result;
+
+ memset(buf, 0, size); /* Make sure we parse really received data */
+
+ for (i = 0; i < 3; ++i) {
+ /* retry on length 0 or error; some devices are flakey */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (type << 8) + index, 0, buf, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (result <= 0 && result != -ETIMEDOUT)
+ continue;
+ if (result > 1 && ((u8 *)buf)[1] != type) {
+ result = -ENODATA;
+ continue;
+ }
+ break;
+ }
+ return result;
+}
+EXPORT_SYMBOL_GPL(usb_get_descriptor);
+
+/**
+ * usb_get_string - gets a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @langid: code for language chosen (from string descriptor zero)
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
+ * in little-endian byte order).
+ * The usb_string() function will often be a convenient way to turn
+ * these strings into kernel-printable form.
+ *
+ * Strings may be referenced in device, configuration, interface, or other
+ * descriptors, and could also be used in vendor-specific ways.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Return: The number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+static int usb_get_string(struct usb_device *dev, unsigned short langid,
+ unsigned char index, void *buf, int size)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < 3; ++i) {
+ /* retry on length 0 or stall; some devices are flakey */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid, buf, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (result == 0 || result == -EPIPE)
+ continue;
+ if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
+ result = -ENODATA;
+ continue;
+ }
+ break;
+ }
+ return result;
+}
+
+static void usb_try_string_workarounds(unsigned char *buf, int *length)
+{
+ int newlength, oldlength = *length;
+
+ for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
+ if (!isprint(buf[newlength]) || buf[newlength + 1])
+ break;
+
+ if (newlength > 2) {
+ buf[0] = newlength;
+ *length = newlength;
+ }
+}
+
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+ unsigned int index, unsigned char *buf)
+{
+ int rc;
+
+ /* Try to read the string descriptor by asking for the maximum
+ * possible number of bytes */
+ if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
+ rc = -EIO;
+ else
+ rc = usb_get_string(dev, langid, index, buf, 255);
+
+ /* If that failed try to read the descriptor length, then
+ * ask for just that many bytes */
+ if (rc < 2) {
+ rc = usb_get_string(dev, langid, index, buf, 2);
+ if (rc == 2)
+ rc = usb_get_string(dev, langid, index, buf, buf[0]);
+ }
+
+ if (rc >= 2) {
+ if (!buf[0] && !buf[1])
+ usb_try_string_workarounds(buf, &rc);
+
+ /* There might be extra junk at the end of the descriptor */
+ if (buf[0] < rc)
+ rc = buf[0];
+
+ rc = rc - (rc & 1); /* force a multiple of two */
+ }
+
+ if (rc < 2)
+ rc = (rc < 0 ? rc : -EINVAL);
+
+ return rc;
+}
+
+static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
+{
+ int err;
+
+ if (dev->have_langid)
+ return 0;
+
+ if (dev->string_langid < 0)
+ return -EPIPE;
+
+ err = usb_string_sub(dev, 0, 0, tbuf);
+
+ /* If the string was reported but is malformed, default to english
+ * (0x0409) */
+ if (err == -ENODATA || (err > 0 && err < 4)) {
+ dev->string_langid = 0x0409;
+ dev->have_langid = 1;
+ dev_err(&dev->dev,
+ "language id specifier not provided by device, defaulting to English\n");
+ return 0;
+ }
+
+ /* In case of all other errors, we assume the device is not able to
+ * 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_info(&dev->dev, "string descriptor 0 read error: %d\n",
+ err);
+ dev->string_langid = -1;
+ return -EPIPE;
+ }
+
+ /* always use the first langid listed */
+ dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+ dev->have_langid = 1;
+ dev_dbg(&dev->dev, "default language 0x%04x\n",
+ dev->string_langid);
+ return 0;
+}
+
+/**
+ * usb_string - returns UTF-8 version of a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * This converts the UTF-16LE encoded strings returned by devices, from
+ * usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
+ * that are more usable in most kernel contexts. Note that this function
+ * chooses strings in the first language supported by the device.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Return: length of the string (>= 0) or usb_control_msg status (< 0).
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+ unsigned char *tbuf;
+ int err;
+
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (size <= 0 || !buf)
+ return -EINVAL;
+ buf[0] = 0;
+ if (index <= 0 || index >= 256)
+ return -EINVAL;
+ tbuf = kmalloc(256, GFP_NOIO);
+ if (!tbuf)
+ return -ENOMEM;
+
+ err = usb_get_langid(dev, tbuf);
+ if (err < 0)
+ goto errout;
+
+ err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+ if (err < 0)
+ goto errout;
+
+ size--; /* leave room for trailing NULL char in output buffer */
+ err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
+ UTF16_LITTLE_ENDIAN, buf, size);
+ buf[err] = 0;
+
+ if (tbuf[1] != USB_DT_STRING)
+ dev_dbg(&dev->dev,
+ "wrong descriptor type %02x for string %d (\"%s\")\n",
+ tbuf[1], index, buf);
+
+ errout:
+ kfree(tbuf);
+ return err;
+}
+EXPORT_SYMBOL_GPL(usb_string);
+
+/* one UTF-8-encoded 16-bit character has at most three bytes */
+#define MAX_USB_STRING_SIZE (127 * 3 + 1)
+
+/**
+ * usb_cache_string - read a string descriptor and cache it for later use
+ * @udev: the device whose string descriptor is being read
+ * @index: the descriptor index
+ *
+ * Return: A pointer to a kmalloc'ed buffer containing the descriptor string,
+ * or %NULL if the index is 0 or the string could not be read.
+ */
+char *usb_cache_string(struct usb_device *udev, int index)
+{
+ char *buf;
+ char *smallbuf = NULL;
+ int len;
+
+ if (index <= 0)
+ return NULL;
+
+ buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO);
+ if (buf) {
+ len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
+ if (len > 0) {
+ smallbuf = kmalloc(++len, GFP_NOIO);
+ if (!smallbuf)
+ return buf;
+ memcpy(smallbuf, buf, len);
+ }
+ kfree(buf);
+ }
+ return smallbuf;
+}
+
+/*
+ * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
+ * @dev: the device whose device descriptor is being updated
+ * @size: how much of the descriptor to read
+ * Context: !in_interrupt ()
+ *
+ * Updates the copy of the device descriptor stored in the device structure,
+ * which dedicates space for this purpose.
+ *
+ * Not exported, only for use by the core. If drivers really want to read
+ * the device descriptor directly, they can call usb_get_descriptor() with
+ * type = USB_DT_DEVICE and index = 0.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Return: The number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
+{
+ struct usb_device_descriptor *desc;
+ int ret;
+
+ if (size > sizeof(*desc))
+ return -EINVAL;
+ desc = kmalloc(sizeof(*desc), GFP_NOIO);
+ if (!desc)
+ return -ENOMEM;
+
+ ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
+ if (ret >= 0)
+ memcpy(&dev->descriptor, desc, size);
+ kfree(desc);
+ 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,
+ 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
+ * @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 ()
+ *
+ * Returns device, interface, or endpoint status. Normally only of
+ * interest to see if the device is self powered, or has enabled the
+ * remote wakeup facility; or whether a bulk or interrupt endpoint
+ * is halted ("stalled").
+ *
+ * Bits in these status bitmaps are set using the SET_FEATURE request,
+ * and cleared using the CLEAR_FEATURE request. The usb_clear_halt()
+ * function should be used to clear halt ("stall") status.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * 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 recip, int type, int target,
+ void *data)
+{
+ int ret;
+ 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 | 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;
+ }
+
+ *(u16 *) data = le16_to_cpu(*(__le16 *) status);
+ ret = 0;
+ break;
+ default:
+ ret = -EIO;
+ }
+
+ kfree(status);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_get_status);
+
+/**
+ * usb_clear_halt - tells device to clear endpoint halt/stall condition
+ * @dev: device whose endpoint is halted
+ * @pipe: endpoint "pipe" being cleared
+ * Context: !in_interrupt ()
+ *
+ * This is used to clear halt conditions for bulk and interrupt endpoints,
+ * as reported by URB completion status. Endpoints that are halted are
+ * sometimes referred to as being "stalled". Such endpoints are unable
+ * to transmit or receive data until the halt status is cleared. Any URBs
+ * queued for such an endpoint should normally be unlinked by the driver
+ * before clearing the halt condition, as described in sections 5.7.5
+ * and 5.8.5 of the USB 2.0 spec.
+ *
+ * Note that control and isochronous endpoints don't halt, although control
+ * endpoints report "protocol stall" (for unsupported requests) using the
+ * same status code used to report a true stall.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Return: Zero on success, or else the status code returned by the
+ * underlying usb_control_msg() call.
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe);
+
+ if (usb_pipein(pipe))
+ endp |= USB_DIR_IN;
+
+ /* we don't care if it wasn't halted first. in fact some devices
+ * (like some ibmcam model 1 units) seem to expect hosts to make
+ * this request for iso endpoints, which can't halt!
+ */
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT, endp, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+
+ /* don't un-halt or force to DATA0 except on success */
+ if (result < 0)
+ return result;
+
+ /* NOTE: seems like Microsoft and Apple don't bother verifying
+ * the clear "took", so some devices could lock up if you check...
+ * such as the Hagiwara FlashGate DUAL. So we won't bother.
+ *
+ * NOTE: make sure the logic here doesn't diverge much from
+ * the copy in usb-storage, for as long as we need two copies.
+ */
+
+ usb_reset_endpoint(dev, endp);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_clear_halt);
+
+static int create_intf_ep_devs(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ if (intf->ep_devs_created || intf->unregistering)
+ return 0;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+ (void) usb_create_ep_devs(&intf->dev, &alt->endpoint[i], udev);
+ intf->ep_devs_created = 1;
+ return 0;
+}
+
+static void remove_intf_ep_devs(struct usb_interface *intf)
+{
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ if (!intf->ep_devs_created)
+ return;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+ usb_remove_ep_devs(&alt->endpoint[i]);
+ intf->ep_devs_created = 0;
+}
+
+/**
+ * usb_disable_endpoint -- Disable an endpoint by address
+ * @dev: the device whose endpoint is being disabled
+ * @epaddr: the endpoint's address. Endpoint number for output,
+ * endpoint number + USB_DIR_IN for input
+ * @reset_hardware: flag to erase any endpoint state stored in the
+ * controller hardware
+ *
+ * Disables the endpoint for URB submission and nukes all pending URBs.
+ * If @reset_hardware is set then also deallocates hcd/hardware state
+ * for the endpoint.
+ */
+void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr,
+ bool reset_hardware)
+{
+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
+ struct usb_host_endpoint *ep;
+
+ if (!dev)
+ return;
+
+ if (usb_endpoint_out(epaddr)) {
+ ep = dev->ep_out[epnum];
+ if (reset_hardware && epnum != 0)
+ dev->ep_out[epnum] = NULL;
+ } else {
+ ep = dev->ep_in[epnum];
+ if (reset_hardware && epnum != 0)
+ dev->ep_in[epnum] = NULL;
+ }
+ if (ep) {
+ ep->enabled = 0;
+ usb_hcd_flush_endpoint(dev, ep);
+ if (reset_hardware)
+ usb_hcd_disable_endpoint(dev, ep);
+ }
+}
+
+/**
+ * usb_reset_endpoint - Reset an endpoint's state.
+ * @dev: the device whose endpoint is to be reset
+ * @epaddr: the endpoint's address. Endpoint number for output,
+ * endpoint number + USB_DIR_IN for input
+ *
+ * Resets any host-side endpoint state such as the toggle bit,
+ * sequence number or current window.
+ */
+void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr)
+{
+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
+ struct usb_host_endpoint *ep;
+
+ if (usb_endpoint_out(epaddr))
+ ep = dev->ep_out[epnum];
+ else
+ ep = dev->ep_in[epnum];
+ if (ep)
+ usb_hcd_reset_endpoint(dev, ep);
+}
+EXPORT_SYMBOL_GPL(usb_reset_endpoint);
+
+
+/**
+ * usb_disable_interface -- Disable all endpoints for an interface
+ * @dev: the device whose interface is being disabled
+ * @intf: pointer to the interface descriptor
+ * @reset_hardware: flag to erase any endpoint state stored in the
+ * controller hardware
+ *
+ * Disables all the endpoints for the interface's current altsetting.
+ */
+void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
+ bool reset_hardware)
+{
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
+ usb_disable_endpoint(dev,
+ alt->endpoint[i].desc.bEndpointAddress,
+ reset_hardware);
+ }
+}
+
+/*
+ * usb_disable_device_endpoints -- Disable all endpoints for a device
+ * @dev: the device whose endpoints are being disabled
+ * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
+ */
+static void usb_disable_device_endpoints(struct usb_device *dev, int skip_ep0)
+{
+ struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+ int i;
+
+ if (hcd->driver->check_bandwidth) {
+ /* First pass: Cancel URBs, leave endpoint pointers intact. */
+ for (i = skip_ep0; i < 16; ++i) {
+ usb_disable_endpoint(dev, i, false);
+ usb_disable_endpoint(dev, i + USB_DIR_IN, false);
+ }
+ /* Remove endpoints from the host controller internal state */
+ mutex_lock(hcd->bandwidth_mutex);
+ usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ mutex_unlock(hcd->bandwidth_mutex);
+ }
+ /* Second pass: remove endpoint pointers */
+ for (i = skip_ep0; i < 16; ++i) {
+ usb_disable_endpoint(dev, i, true);
+ usb_disable_endpoint(dev, i + USB_DIR_IN, true);
+ }
+}
+
+/**
+ * usb_disable_device - Disable all the endpoints for a USB device
+ * @dev: the device whose endpoints are being disabled
+ * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
+ *
+ * Disables all the device's endpoints, potentially including endpoint 0.
+ * Deallocates hcd/hardware state for the endpoints (nuking all or most
+ * pending urbs) and usbcore state for the interfaces, so that usbcore
+ * must usb_set_configuration() before any interfaces could be used.
+ */
+void usb_disable_device(struct usb_device *dev, int skip_ep0)
+{
+ int i;
+
+ /* getting rid of interfaces will disconnect
+ * any drivers bound to them (a key side effect)
+ */
+ if (dev->actconfig) {
+ /*
+ * FIXME: In order to avoid self-deadlock involving the
+ * bandwidth_mutex, we have to mark all the interfaces
+ * before unregistering any of them.
+ */
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
+ dev->actconfig->interface[i]->unregistering = 1;
+
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *interface;
+
+ /* remove this interface if it has been registered */
+ interface = dev->actconfig->interface[i];
+ if (!device_is_registered(&interface->dev))
+ continue;
+ dev_dbg(&dev->dev, "unregistering interface %s\n",
+ dev_name(&interface->dev));
+ remove_intf_ep_devs(interface);
+ device_del(&interface->dev);
+ }
+
+ /* Now that the interfaces are unbound, nobody should
+ * try to access them.
+ */
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ put_device(&dev->actconfig->interface[i]->dev);
+ dev->actconfig->interface[i] = NULL;
+ }
+
+ usb_disable_usb2_hardware_lpm(dev);
+ usb_unlocked_disable_lpm(dev);
+ usb_disable_ltm(dev);
+
+ dev->actconfig = NULL;
+ if (dev->state == USB_STATE_CONFIGURED)
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
+ }
+
+ dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
+ skip_ep0 ? "non-ep0" : "all");
+
+ usb_disable_device_endpoints(dev, skip_ep0);
+}
+
+/**
+ * usb_enable_endpoint - Enable an endpoint for USB communications
+ * @dev: the device whose interface is being enabled
+ * @ep: the endpoint
+ * @reset_ep: flag to reset the endpoint state
+ *
+ * Resets the endpoint state if asked, and sets dev->ep_{in,out} pointers.
+ * For control endpoints, both the input and output sides are handled.
+ */
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,
+ bool reset_ep)
+{
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
+
+ if (reset_ep)
+ usb_hcd_reset_endpoint(dev, ep);
+ if (is_out || is_control)
+ dev->ep_out[epnum] = ep;
+ if (!is_out || is_control)
+ dev->ep_in[epnum] = ep;
+ ep->enabled = 1;
+}
+
+/**
+ * usb_enable_interface - Enable all the endpoints for an interface
+ * @dev: the device whose interface is being enabled
+ * @intf: pointer to the interface descriptor
+ * @reset_eps: flag to reset the endpoints' state
+ *
+ * Enables all the endpoints for the interface's current altsetting.
+ */
+void usb_enable_interface(struct usb_device *dev,
+ struct usb_interface *intf, bool reset_eps)
+{
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+ usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps);
+}
+
+/**
+ * usb_set_interface - Makes a particular alternate setting be current
+ * @dev: the device whose interface is being updated
+ * @interface: the interface being updated
+ * @alternate: the setting being chosen.
+ * Context: !in_interrupt ()
+ *
+ * This is used to enable data transfers on interfaces that may not
+ * be enabled by default. Not all devices support such configurability.
+ * Only the driver bound to an interface may change its setting.
+ *
+ * Within any given configuration, each interface may have several
+ * alternative settings. These are often used to control levels of
+ * bandwidth consumption. For example, the default setting for a high
+ * speed interrupt endpoint may not send more than 64 bytes per microframe,
+ * while interrupt transfers of up to 3KBytes per microframe are legal.
+ * Also, isochronous endpoints may never be part of an
+ * interface's default setting. To access such bandwidth, alternate
+ * interface settings must be made current.
+ *
+ * Note that in the Linux USB subsystem, bandwidth associated with
+ * an endpoint in a given alternate setting is not reserved until an URB
+ * 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
+ * (perhaps forced by unlinking).
+ *
+ * Return: Zero on success, or else the status code returned by the
+ * underlying usb_control_msg() call.
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+ struct usb_interface *iface;
+ struct usb_host_interface *alt;
+ struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+ int i, ret, manual = 0;
+ unsigned int epaddr;
+ unsigned int pipe;
+
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+
+ iface = usb_ifnum_to_if(dev, interface);
+ if (!iface) {
+ dev_dbg(&dev->dev, "selecting invalid interface %d\n",
+ interface);
+ return -EINVAL;
+ }
+ if (iface->unregistering)
+ return -ENODEV;
+
+ alt = usb_altnum_to_altsetting(iface, alternate);
+ if (!alt) {
+ dev_warn(&dev->dev, "selecting invalid altsetting %d\n",
+ 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.
+ */
+ mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new alt setting is installed,
+ * 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__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
+ /* Changing alt-setting also frees any allocated streams */
+ for (i = 0; i < iface->cur_altsetting->desc.bNumEndpoints; i++)
+ iface->cur_altsetting->endpoint[i].streams = 0;
+
+ ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
+ if (ret < 0) {
+ dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
+ alternate);
+ usb_enable_lpm(dev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return ret;
+ }
+
+ if (dev->quirks & USB_QUIRK_NO_SET_INTF)
+ ret = -EPIPE;
+ else
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
+ alternate, interface, NULL, 0, 5000);
+
+ /* 9.4.10 says devices don't need this and are free to STALL the
+ * request if the interface only has one alternate setting.
+ */
+ if (ret == -EPIPE && iface->num_altsetting == 1) {
+ dev_dbg(&dev->dev,
+ "manual set_interface for iface %d, alt %d\n",
+ interface, alternate);
+ manual = 1;
+ } else if (ret < 0) {
+ /* Re-instate the old alt setting */
+ usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
+ usb_enable_lpm(dev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return ret;
+ }
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ /* FIXME drivers shouldn't need to replicate/bugfix the logic here
+ * when they implement async or easily-killable versions of this or
+ * other "should-be-internal" functions (like clear_halt).
+ * should hcd+usbcore postprocess control requests?
+ */
+
+ /* prevent submissions using previous endpoint settings */
+ if (iface->cur_altsetting != alt) {
+ remove_intf_ep_devs(iface);
+ usb_remove_sysfs_intf_files(iface);
+ }
+ usb_disable_interface(dev, iface, true);
+
+ iface->cur_altsetting = alt;
+
+ /* Now that the interface is installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+
+ /* If the interface only has one altsetting and the device didn't
+ * accept the request, we attempt to carry out the equivalent action
+ * by manually clearing the HALT feature for each endpoint in the
+ * new altsetting.
+ */
+ if (manual) {
+ for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+ epaddr = alt->endpoint[i].desc.bEndpointAddress;
+ pipe = __create_pipe(dev,
+ USB_ENDPOINT_NUMBER_MASK & epaddr) |
+ (usb_endpoint_out(epaddr) ?
+ USB_DIR_OUT : USB_DIR_IN);
+
+ usb_clear_halt(dev, pipe);
+ }
+ }
+
+ /* 9.1.1.5: reset toggles for all endpoints in the new altsetting
+ *
+ * Note:
+ * Despite EP0 is always present in all interfaces/AS, the list of
+ * endpoints from the descriptor does not contain EP0. Due to its
+ * omnipresence one might expect EP0 being considered "affected" by
+ * any SetInterface request and hence assume toggles need to be reset.
+ * However, EP0 toggles are re-synced for every individual transfer
+ * during the SETUP stage - hence EP0 toggles are "don't care" here.
+ * (Likewise, EP0 never "halts" on well designed devices.)
+ */
+ usb_enable_interface(dev, iface, true);
+ if (device_is_registered(&iface->dev)) {
+ usb_create_sysfs_intf_files(iface);
+ create_intf_ep_devs(iface);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_set_interface);
+
+/**
+ * usb_reset_configuration - lightweight device reset
+ * @dev: the device whose configuration is being reset
+ *
+ * This issues a standard SET_CONFIGURATION request to the device using
+ * the current configuration. The effect is to reset most USB-related
+ * state in the device, including interface altsettings (reset to zero),
+ * endpoint halts (cleared), and endpoint state (only for bulk and interrupt
+ * endpoints). Other usbcore state is unchanged, including bindings of
+ * usb device drivers to interfaces.
+ *
+ * Because this affects multiple interfaces, avoid using this with composite
+ * (multi-interface) devices. Instead, the driver for each interface may
+ * use usb_set_interface() on the interfaces it claims. Be careful though;
+ * some devices don't support the SET_INTERFACE request, and others won't
+ * reset all the interface state (notably endpoint state). Resetting the whole
+ * configuration would affect other drivers' interfaces.
+ *
+ * The caller must own the device lock.
+ *
+ * Return: Zero on success, else a negative error code.
+ *
+ * If this routine fails the device will probably be in an unusable state
+ * with endpoints disabled, and interfaces only partially enabled.
+ */
+int usb_reset_configuration(struct usb_device *dev)
+{
+ int i, retval;
+ struct usb_host_config *config;
+ struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+
+ /* caller must have locked the device and must own
+ * the usb bus readlock (so driver bindings are stable);
+ * calls during probe() are fine
+ */
+
+ usb_disable_device_endpoints(dev, 1); /* skip ep0*/
+
+ config = dev->actconfig;
+ retval = 0;
+ mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the configuration is reset, so
+ * 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__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
+
+ /* xHCI adds all endpoints in usb_hcd_alloc_bandwidth */
+ retval = usb_hcd_alloc_bandwidth(dev, config, NULL, NULL);
+ if (retval < 0) {
+ usb_enable_lpm(dev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return retval;
+ }
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ config->desc.bConfigurationValue, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (retval < 0) {
+ usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ usb_enable_lpm(dev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return retval;
+ }
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ /* re-init hc/hcd interface/endpoint state */
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf = config->interface[i];
+ struct usb_host_interface *alt;
+
+ alt = usb_altnum_to_altsetting(intf, 0);
+
+ /* No altsetting 0? We'll assume the first altsetting.
+ * We could use a GetInterface call, but if a device is
+ * so non-compliant that it doesn't have altsetting 0
+ * then I wouldn't trust its reply anyway.
+ */
+ if (!alt)
+ alt = &intf->altsetting[0];
+
+ if (alt != intf->cur_altsetting) {
+ remove_intf_ep_devs(intf);
+ usb_remove_sysfs_intf_files(intf);
+ }
+ intf->cur_altsetting = alt;
+ usb_enable_interface(dev, intf, true);
+ if (device_is_registered(&intf->dev)) {
+ usb_create_sysfs_intf_files(intf);
+ create_intf_ep_devs(intf);
+ }
+ }
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_reset_configuration);
+
+static void usb_release_interface(struct device *dev)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_interface_cache *intfc =
+ altsetting_to_usb_interface_cache(intf->altsetting);
+
+ kref_put(&intfc->ref, usb_release_interface_cache);
+ usb_put_dev(interface_to_usbdev(intf));
+ of_node_put(dev->of_node);
+ kfree(intf);
+}
+
+/*
+ * usb_deauthorize_interface - deauthorize an USB interface
+ *
+ * @intf: USB interface structure
+ */
+void usb_deauthorize_interface(struct usb_interface *intf)
+{
+ struct device *dev = &intf->dev;
+
+ device_lock(dev->parent);
+
+ if (intf->authorized) {
+ device_lock(dev);
+ intf->authorized = 0;
+ device_unlock(dev);
+
+ usb_forced_unbind_intf(intf);
+ }
+
+ device_unlock(dev->parent);
+}
+
+/*
+ * usb_authorize_interface - authorize an USB interface
+ *
+ * @intf: USB interface structure
+ */
+void usb_authorize_interface(struct usb_interface *intf)
+{
+ struct device *dev = &intf->dev;
+
+ if (!intf->authorized) {
+ device_lock(dev);
+ intf->authorized = 1; /* authorize interface */
+ device_unlock(dev);
+ }
+}
+
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_device *usb_dev;
+ struct usb_interface *intf;
+ struct usb_host_interface *alt;
+
+ intf = to_usb_interface(dev);
+ usb_dev = interface_to_usbdev(intf);
+ alt = intf->cur_altsetting;
+
+ if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+
+ if (add_uevent_var(env,
+ "MODALIAS=usb:"
+ "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice),
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol,
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol,
+ alt->desc.bInterfaceNumber))
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct device_type usb_if_device_type = {
+ .name = "usb_interface",
+ .release = usb_release_interface,
+ .uevent = usb_if_uevent,
+};
+
+static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
+ struct usb_host_config *config,
+ u8 inum)
+{
+ struct usb_interface_assoc_descriptor *retval = NULL;
+ struct usb_interface_assoc_descriptor *intf_assoc;
+ int first_intf;
+ int last_intf;
+ int i;
+
+ for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
+ intf_assoc = config->intf_assoc[i];
+ if (intf_assoc->bInterfaceCount == 0)
+ continue;
+
+ first_intf = intf_assoc->bFirstInterface;
+ last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
+ if (inum >= first_intf && inum <= last_intf) {
+ if (!retval)
+ retval = intf_assoc;
+ else
+ dev_err(&dev->dev, "Interface #%d referenced"
+ " by multiple IADs\n", inum);
+ }
+ }
+
+ return retval;
+}
+
+
+/*
+ * Internal function to queue a device reset
+ * See usb_queue_reset_device() for more details
+ */
+static void __usb_queue_reset_device(struct work_struct *ws)
+{
+ int rc;
+ struct usb_interface *iface =
+ container_of(ws, struct usb_interface, reset_ws);
+ struct usb_device *udev = interface_to_usbdev(iface);
+
+ rc = usb_lock_device_for_reset(udev, iface);
+ if (rc >= 0) {
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+ }
+ usb_put_intf(iface); /* Undo _get_ in usb_queue_reset_device() */
+}
+
+
+/*
+ * usb_set_configuration - Makes a particular device setting be current
+ * @dev: the device whose configuration is being updated
+ * @configuration: the configuration being chosen.
+ * Context: !in_interrupt(), caller owns the device lock
+ *
+ * This is used to enable non-default device modes. Not all devices
+ * use this kind of configurability; many devices only have one
+ * configuration.
+ *
+ * @configuration is the value of the configuration to be installed.
+ * According to the USB spec (e.g. section 9.1.1.5), configuration values
+ * must be non-zero; a value of zero indicates that the device in
+ * unconfigured. However some devices erroneously use 0 as one of their
+ * configuration values. To help manage such devices, this routine will
+ * accept @configuration = -1 as indicating the device should be put in
+ * an unconfigured state.
+ *
+ * USB device configurations may affect Linux interoperability,
+ * power consumption and the functionality available. For example,
+ * the default configuration is limited to using 100mA of bus power,
+ * so that when certain device functionality requires more power,
+ * and the device is bus powered, that functionality should be in some
+ * non-default device configuration. Other device modes may also be
+ * reflected as configuration options, such as whether two ISDN
+ * channels are available independently; and choosing between open
+ * standard device protocols (like CDC) or proprietary ones.
+ *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
+ * Note that USB has an additional level of device configurability,
+ * associated with interfaces. That configurability is accessed using
+ * usb_set_interface().
+ *
+ * This call is synchronous. The calling context must be able to sleep,
+ * must own the device lock, and must not hold the driver model's USB
+ * bus mutex; usb interface driver probe() methods cannot use this routine.
+ *
+ * Returns zero on success, or else the status code returned by the
+ * underlying call that failed. On successful completion, each interface
+ * in the original device configuration has been destroyed, and each one
+ * in the new configuration has been probed by all relevant usb device
+ * drivers currently known to the kernel.
+ */
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+ int i, ret;
+ struct usb_host_config *cp = NULL;
+ struct usb_interface **new_interfaces = NULL;
+ struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+ int n, nintf;
+
+ if (dev->authorized == 0 || configuration == -1)
+ configuration = 0;
+ else {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ if (dev->config[i].desc.bConfigurationValue ==
+ configuration) {
+ cp = &dev->config[i];
+ break;
+ }
+ }
+ }
+ if ((!cp && configuration != 0))
+ return -EINVAL;
+
+ /* The USB spec says configuration 0 means unconfigured.
+ * But if a device includes a configuration numbered 0,
+ * we will accept it as a correctly configured state.
+ * Use -1 if you really want to unconfigure the device.
+ */
+ if (cp && configuration == 0)
+ dev_warn(&dev->dev, "config 0 descriptor??\n");
+
+ /* Allocate memory for new interfaces before doing anything else,
+ * so that if we run out then nothing will have changed. */
+ n = nintf = 0;
+ if (cp) {
+ nintf = cp->desc.bNumInterfaces;
+ new_interfaces = kmalloc_array(nintf, sizeof(*new_interfaces),
+ GFP_NOIO);
+ if (!new_interfaces)
+ return -ENOMEM;
+
+ for (; n < nintf; ++n) {
+ new_interfaces[n] = kzalloc(
+ sizeof(struct usb_interface),
+ GFP_NOIO);
+ if (!new_interfaces[n]) {
+ ret = -ENOMEM;
+free_interfaces:
+ while (--n >= 0)
+ kfree(new_interfaces[n]);
+ kfree(new_interfaces);
+ return ret;
+ }
+ }
+
+ i = dev->bus_mA - usb_get_max_power(dev, cp);
+ if (i < 0)
+ dev_warn(&dev->dev, "new config #%d exceeds power "
+ "limit by %dmA\n",
+ configuration, -i);
+ }
+
+ /* Wake up the device so we can send it the Set-Config request */
+ ret = usb_autoresume_device(dev);
+ if (ret)
+ goto free_interfaces;
+
+ /* if it's already configured, clear out old state first.
+ * getting rid of old interfaces means unbinding their drivers.
+ */
+ if (dev->state != USB_STATE_ADDRESS)
+ usb_disable_device(dev, 1); /* Skip ep0 */
+
+ /* Get rid of pending async Set-Config requests for this device */
+ cancel_async_set_config(dev);
+
+ /* Make sure we have bandwidth (and available HCD resources) for this
+ * configuration. Remove endpoints from the schedule if we're dropping
+ * this configuration to set configuration 0. After this point, the
+ * host controller will not allow submissions to dropped endpoints. If
+ * this call fails, the device state is unchanged.
+ */
+ mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new configuration is
+ * installed, so that the xHCI driver can recalculate the U1/U2
+ * timeouts.
+ */
+ if (dev->actconfig && usb_disable_lpm(dev)) {
+ dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ ret = -ENOMEM;
+ goto free_interfaces;
+ }
+ ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
+ if (ret < 0) {
+ if (dev->actconfig)
+ usb_enable_lpm(dev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_autosuspend_device(dev);
+ goto free_interfaces;
+ }
+
+ /*
+ * Initialize the new interface structures and the
+ * hc/hcd/usbcore interface/endpoint state.
+ */
+ for (i = 0; i < nintf; ++i) {
+ 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];
+ intf->altsetting = intfc->altsetting;
+ intf->num_altsetting = intfc->num_altsetting;
+ intf->authorized = !!HCD_INTF_AUTHORIZED(hcd);
+ kref_get(&intfc->ref);
+
+ alt = usb_altnum_to_altsetting(intf, 0);
+
+ /* No altsetting 0? We'll assume the first altsetting.
+ * We could use a GetInterface call, but if a device is
+ * so non-compliant that it doesn't have altsetting 0
+ * then I wouldn't trust its reply anyway.
+ */
+ if (!alt)
+ alt = &intf->altsetting[0];
+
+ 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;
+ intf->dev.groups = usb_interface_groups;
+ /*
+ * Please refer to usb_alloc_dev() to see why we set
+ * dma_mask and dma_pfn_offset.
+ */
+ intf->dev.dma_mask = dev->dev.dma_mask;
+ intf->dev.dma_pfn_offset = dev->dev.dma_pfn_offset;
+ INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
+ 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, ifnum);
+ usb_get_dev(dev);
+ }
+ kfree(new_interfaces);
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (ret < 0 && cp) {
+ /*
+ * All the old state is gone, so what else can we do?
+ * The device is probably useless now anyway.
+ */
+ usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ for (i = 0; i < nintf; ++i) {
+ usb_disable_interface(dev, cp->interface[i], true);
+ put_device(&cp->interface[i]->dev);
+ cp->interface[i] = NULL;
+ }
+ cp = NULL;
+ }
+
+ dev->actconfig = cp;
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ if (!cp) {
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
+
+ /* Leave LPM disabled while the device is unconfigured. */
+ usb_autosuspend_device(dev);
+ return ret;
+ }
+ usb_set_device_state(dev, USB_STATE_CONFIGURED);
+
+ if (cp->string == NULL &&
+ !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+ cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
+
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+ /* Enable LTM if it was turned off by usb_disable_device. */
+ usb_enable_ltm(dev);
+
+ /* Now that all the interfaces are set up, register them
+ * to trigger binding of drivers to interfaces. probe()
+ * routines may install different altsettings and may
+ * claim() any interfaces not yet bound. Many class drivers
+ * need that: CDC, audio, video, etc.
+ */
+ for (i = 0; i < nintf; ++i) {
+ struct usb_interface *intf = cp->interface[i];
+
+ dev_dbg(&dev->dev,
+ "adding %s (config #%d, interface %d)\n",
+ dev_name(&intf->dev), configuration,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ device_enable_async_suspend(&intf->dev);
+ ret = device_add(&intf->dev);
+ if (ret != 0) {
+ dev_err(&dev->dev, "device_add(%s) --> %d\n",
+ dev_name(&intf->dev), ret);
+ continue;
+ }
+ create_intf_ep_devs(intf);
+ }
+
+ usb_autosuspend_device(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_set_configuration);
+
+static LIST_HEAD(set_config_list);
+static DEFINE_SPINLOCK(set_config_lock);
+
+struct set_config_request {
+ struct usb_device *udev;
+ int config;
+ struct work_struct work;
+ struct list_head node;
+};
+
+/* Worker routine for usb_driver_set_configuration() */
+static void driver_set_config_work(struct work_struct *work)
+{
+ struct set_config_request *req =
+ container_of(work, struct set_config_request, work);
+ struct usb_device *udev = req->udev;
+
+ usb_lock_device(udev);
+ spin_lock(&set_config_lock);
+ list_del(&req->node);
+ spin_unlock(&set_config_lock);
+
+ if (req->config >= -1) /* Is req still valid? */
+ usb_set_configuration(udev, req->config);
+ usb_unlock_device(udev);
+ usb_put_dev(udev);
+ kfree(req);
+}
+
+/* Cancel pending Set-Config requests for a device whose configuration
+ * was just changed
+ */
+static void cancel_async_set_config(struct usb_device *udev)
+{
+ struct set_config_request *req;
+
+ spin_lock(&set_config_lock);
+ list_for_each_entry(req, &set_config_list, node) {
+ if (req->udev == udev)
+ req->config = -999; /* Mark as cancelled */
+ }
+ spin_unlock(&set_config_lock);
+}
+
+/**
+ * usb_driver_set_configuration - Provide a way for drivers to change device configurations
+ * @udev: the device whose configuration is being updated
+ * @config: the configuration being chosen.
+ * Context: In process context, must be able to sleep
+ *
+ * Device interface drivers are not allowed to change device configurations.
+ * This is because changing configurations will destroy the interface the
+ * driver is bound to and create new ones; it would be like a floppy-disk
+ * driver telling the computer to replace the floppy-disk drive with a
+ * tape drive!
+ *
+ * Still, in certain specialized circumstances the need may arise. This
+ * routine gets around the normal restrictions by using a work thread to
+ * submit the change-config request.
+ *
+ * Return: 0 if the request was successfully queued, error code otherwise.
+ * The caller has no way to know whether the queued request will eventually
+ * succeed.
+ */
+int usb_driver_set_configuration(struct usb_device *udev, int config)
+{
+ struct set_config_request *req;
+
+ req = kmalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ req->udev = udev;
+ req->config = config;
+ INIT_WORK(&req->work, driver_set_config_work);
+
+ spin_lock(&set_config_lock);
+ list_add(&req->node, &set_config_list);
+ spin_unlock(&set_config_lock);
+
+ usb_get_dev(udev);
+ schedule_work(&req->work);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
+
+/**
+ * cdc_parse_cdc_header - parse the extra headers present in CDC devices
+ * @hdr: the place to put the results of the parsing
+ * @intf: the interface for which parsing is requested
+ * @buffer: pointer to the extra headers to be parsed
+ * @buflen: length of the extra headers
+ *
+ * This evaluates the extra headers present in CDC devices which
+ * bind the interfaces for data and control and provide details
+ * about the capabilities of the device.
+ *
+ * Return: number of descriptors parsed or -EINVAL
+ * if the header is contradictory beyond salvage
+ */
+
+int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
+ struct usb_interface *intf,
+ u8 *buffer,
+ int buflen)
+{
+ /* duplicates are ignored */
+ struct usb_cdc_union_desc *union_header = NULL;
+
+ /* duplicates are not tolerated */
+ struct usb_cdc_header_desc *header = NULL;
+ struct usb_cdc_ether_desc *ether = NULL;
+ struct usb_cdc_mdlm_detail_desc *detail = NULL;
+ struct usb_cdc_mdlm_desc *desc = NULL;
+
+ unsigned int elength;
+ int cnt = 0;
+
+ memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
+ hdr->phonet_magic_present = false;
+ while (buflen > 0) {
+ elength = buffer[0];
+ if (!elength) {
+ dev_err(&intf->dev, "skipping garbage byte\n");
+ elength = 1;
+ goto next_desc;
+ }
+ if ((buflen < elength) || (elength < 3)) {
+ dev_err(&intf->dev, "invalid descriptor buffer length\n");
+ break;
+ }
+ if (buffer[1] != USB_DT_CS_INTERFACE) {
+ dev_err(&intf->dev, "skipping garbage\n");
+ goto next_desc;
+ }
+
+ switch (buffer[2]) {
+ case USB_CDC_UNION_TYPE: /* we've found it */
+ if (elength < sizeof(struct usb_cdc_union_desc))
+ goto next_desc;
+ if (union_header) {
+ dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
+ goto next_desc;
+ }
+ union_header = (struct usb_cdc_union_desc *)buffer;
+ break;
+ case USB_CDC_COUNTRY_TYPE:
+ if (elength < sizeof(struct usb_cdc_country_functional_desc))
+ goto next_desc;
+ hdr->usb_cdc_country_functional_desc =
+ (struct usb_cdc_country_functional_desc *)buffer;
+ break;
+ case USB_CDC_HEADER_TYPE:
+ if (elength != sizeof(struct usb_cdc_header_desc))
+ goto next_desc;
+ if (header)
+ return -EINVAL;
+ header = (struct usb_cdc_header_desc *)buffer;
+ break;
+ case USB_CDC_ACM_TYPE:
+ if (elength < sizeof(struct usb_cdc_acm_descriptor))
+ goto next_desc;
+ hdr->usb_cdc_acm_descriptor =
+ (struct usb_cdc_acm_descriptor *)buffer;
+ break;
+ case USB_CDC_ETHERNET_TYPE:
+ if (elength != sizeof(struct usb_cdc_ether_desc))
+ goto next_desc;
+ if (ether)
+ return -EINVAL;
+ ether = (struct usb_cdc_ether_desc *)buffer;
+ break;
+ case USB_CDC_CALL_MANAGEMENT_TYPE:
+ if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
+ goto next_desc;
+ hdr->usb_cdc_call_mgmt_descriptor =
+ (struct usb_cdc_call_mgmt_descriptor *)buffer;
+ break;
+ case USB_CDC_DMM_TYPE:
+ if (elength < sizeof(struct usb_cdc_dmm_desc))
+ goto next_desc;
+ hdr->usb_cdc_dmm_desc =
+ (struct usb_cdc_dmm_desc *)buffer;
+ break;
+ case USB_CDC_MDLM_TYPE:
+ if (elength < sizeof(struct usb_cdc_mdlm_desc))
+ goto next_desc;
+ if (desc)
+ return -EINVAL;
+ desc = (struct usb_cdc_mdlm_desc *)buffer;
+ break;
+ case USB_CDC_MDLM_DETAIL_TYPE:
+ if (elength < sizeof(struct usb_cdc_mdlm_detail_desc))
+ goto next_desc;
+ if (detail)
+ return -EINVAL;
+ detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
+ break;
+ case USB_CDC_NCM_TYPE:
+ if (elength < sizeof(struct usb_cdc_ncm_desc))
+ goto next_desc;
+ hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
+ break;
+ case USB_CDC_MBIM_TYPE:
+ if (elength < sizeof(struct usb_cdc_mbim_desc))
+ goto next_desc;
+
+ hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
+ break;
+ case USB_CDC_MBIM_EXTENDED_TYPE:
+ if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
+ break;
+ hdr->usb_cdc_mbim_extended_desc =
+ (struct usb_cdc_mbim_extended_desc *)buffer;
+ break;
+ case CDC_PHONET_MAGIC_NUMBER:
+ hdr->phonet_magic_present = true;
+ break;
+ default:
+ /*
+ * there are LOTS more CDC descriptors that
+ * could legitimately be found here.
+ */
+ dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
+ buffer[2], elength);
+ goto next_desc;
+ }
+ cnt++;
+next_desc:
+ buflen -= elength;
+ buffer += elength;
+ }
+ hdr->usb_cdc_union_desc = union_header;
+ hdr->usb_cdc_header_desc = header;
+ hdr->usb_cdc_mdlm_detail_desc = detail;
+ hdr->usb_cdc_mdlm_desc = desc;
+ hdr->usb_cdc_ether_desc = ether;
+ return cnt;
+}
+
+EXPORT_SYMBOL(cdc_parse_cdc_header);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
new file mode 100644
index 000000000..ab474b115
--- /dev/null
+++ b/drivers/usb/core/notify.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * All the USB notify logic
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * notifier functions originally based on those in kernel/sys.c
+ * but fixed up to not be so broken.
+ *
+ * Released under the GPLv2 only.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/notifier.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include "usb.h"
+
+static BLOCKING_NOTIFIER_HEAD(usb_notifier_list);
+
+/**
+ * usb_register_notify - register a notifier callback whenever a usb change happens
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * These changes are either USB devices or busses being added or removed.
+ */
+void usb_register_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_register_notify);
+
+/**
+ * usb_unregister_notify - unregister a notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * usb_register_notify() must have been previously called for this function
+ * to work properly.
+ */
+void usb_unregister_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_unregister_notify);
+
+
+void usb_notify_add_device(struct usb_device *udev)
+{
+ blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
+}
+
+void usb_notify_remove_device(struct usb_device *udev)
+{
+ /* Protect against simultaneous usbfs open */
+ mutex_lock(&usbfs_mutex);
+ blocking_notifier_call_chain(&usb_notifier_list,
+ USB_DEVICE_REMOVE, udev);
+ mutex_unlock(&usbfs_mutex);
+}
+
+void usb_notify_add_bus(struct usb_bus *ubus)
+{
+ blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
+}
+
+void usb_notify_remove_bus(struct usb_bus *ubus)
+{
+ blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
+}
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
new file mode 100644
index 000000000..651708d8c
--- /dev/null
+++ b/drivers/usb/core/of.c
@@ -0,0 +1,107 @@
+// 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>
+ * Copyright (C) 2017 Johan Hovold <johan@kernel.org>
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/of.h>
+
+/**
+ * usb_of_get_device_node() - get a USB device node
+ * @hub: hub to which device is connected
+ * @port1: one-based index of port
+ *
+ * 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_device_node(struct usb_device *hub, int port1)
+{
+ struct device_node *node;
+ u32 reg;
+
+ for_each_child_of_node(hub->dev.of_node, node) {
+ if (of_property_read_u32(node, "reg", &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;
+
+ 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_interface_node);
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
new file mode 100644
index 000000000..2ae90158d
--- /dev/null
+++ b/drivers/usb/core/otg_whitelist.h
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/usb/core/otg_whitelist.h
+ *
+ * Copyright (C) 2004 Texas Instruments
+ */
+
+/*
+ * This OTG and Embedded Host Whitelist is "Targeted Peripheral List".
+ * It should mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
+ *
+ * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
+ */
+
+static struct usb_device_id whitelist_table[] = {
+
+/* hubs are optional in OTG, but very handy ... */
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
+
+#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
+/* FIXME actually, printers are NOT supposed to use device classes;
+ * they're supposed to use interface classes...
+ */
+{ USB_DEVICE_INFO(7, 1, 1) },
+{ USB_DEVICE_INFO(7, 1, 2) },
+{ USB_DEVICE_INFO(7, 1, 3) },
+#endif
+
+#ifdef CONFIG_USB_NET_CDCETHER
+/* Linux-USB CDC Ethernet gadget */
+{ USB_DEVICE(0x0525, 0xa4a1), },
+/* Linux-USB CDC Ethernet + RNDIS gadget */
+{ USB_DEVICE(0x0525, 0xa4a2), },
+#endif
+
+#if IS_ENABLED(CONFIG_USB_TEST)
+/* gadget zero, for testing */
+{ USB_DEVICE(0x0525, 0xa4a0), },
+#endif
+
+{ } /* Terminating entry */
+};
+
+static int is_targeted(struct usb_device *dev)
+{
+ struct usb_device_id *id = whitelist_table;
+
+ /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
+ return 0;
+
+ /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+ return 1;
+
+ /* NOTE: can't use usb_match_id() since interface caches
+ * aren't set up yet. this is cut/paste from that code.
+ */
+ for (id = whitelist_table; id->match_flags; id++) {
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
+ continue;
+
+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
+ greater than any unsigned number. */
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != dev->descriptor.bDeviceClass))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+ continue;
+
+ return 1;
+ }
+
+ /* add other match criteria here ... */
+
+
+ /* OTG MESSAGE: report errors here, customize to match your product */
+ dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ return 0;
+}
+
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
new file mode 100644
index 000000000..987976745
--- /dev/null
+++ b/drivers/usb/core/phy.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * A wrapper for multiple PHYs which passes all phy_* function calls to
+ * multiple (actual) PHY devices. This is comes handy when initializing
+ * all PHYs on a HCD and to keep them all in the same state.
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/phy/phy.h>
+#include <linux/of.h>
+
+#include "phy.h"
+
+struct usb_phy_roothub {
+ struct phy *phy;
+ struct list_head list;
+};
+
+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);
+
+ if (IS_ERR_OR_NULL(phy)) {
+ if (!phy || PTR_ERR(phy) == -ENODEV)
+ return 0;
+ else
+ return PTR_ERR(phy);
+ }
+
+ roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
+ if (!roothub_entry)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&roothub_entry->list);
+
+ roothub_entry->phy = phy;
+
+ list_add_tail(&roothub_entry->list, list);
+
+ return 0;
+}
+
+struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
+{
+ struct usb_phy_roothub *phy_roothub;
+ int i, num_phys, err;
+
+ if (!IS_ENABLED(CONFIG_GENERIC_PHY))
+ return NULL;
+
+ num_phys = of_count_phandle_with_args(dev->of_node, "phys",
+ "#phy-cells");
+ if (num_phys <= 0)
+ return NULL;
+
+ phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
+ if (!phy_roothub)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&phy_roothub->list);
+
+ for (i = 0; i < num_phys; i++) {
+ err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
+ if (err)
+ return ERR_PTR(err);
+ }
+
+ return phy_roothub;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
+
+int usb_phy_roothub_init(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_init(roothub_entry->phy);
+ if (err)
+ goto err_exit_phys;
+ }
+
+ return 0;
+
+err_exit_phys:
+ list_for_each_entry_continue_reverse(roothub_entry, head, list)
+ phy_exit(roothub_entry->phy);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
+
+int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
+{
+ struct usb_phy_roothub *roothub_entry;
+ struct list_head *head;
+ int err, ret = 0;
+
+ if (!phy_roothub)
+ return 0;
+
+ head = &phy_roothub->list;
+
+ list_for_each_entry(roothub_entry, head, list) {
+ err = phy_exit(roothub_entry->phy);
+ if (err)
+ ret = err;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
+
+int usb_phy_roothub_power_on(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_power_on(roothub_entry->phy);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ list_for_each_entry_continue_reverse(roothub_entry, head, list)
+ phy_power_off(roothub_entry->phy);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
+
+void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
+{
+ struct usb_phy_roothub *roothub_entry;
+
+ if (!phy_roothub)
+ return;
+
+ list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
+ phy_power_off(roothub_entry->phy);
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
+
+int usb_phy_roothub_suspend(struct device *controller_dev,
+ struct usb_phy_roothub *phy_roothub)
+{
+ usb_phy_roothub_power_off(phy_roothub);
+
+ /* keep the PHYs initialized so the device can wake up the system */
+ if (device_may_wakeup(controller_dev))
+ return 0;
+
+ return usb_phy_roothub_exit(phy_roothub);
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
+
+int usb_phy_roothub_resume(struct device *controller_dev,
+ struct usb_phy_roothub *phy_roothub)
+{
+ int err;
+
+ /* if the device can't wake up the system _exit was called */
+ if (!device_may_wakeup(controller_dev)) {
+ err = usb_phy_roothub_init(phy_roothub);
+ if (err)
+ return err;
+ }
+
+ err = usb_phy_roothub_power_on(phy_roothub);
+
+ /* undo _init if _power_on failed */
+ if (err && !device_may_wakeup(controller_dev))
+ usb_phy_roothub_exit(phy_roothub);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);
diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h
new file mode 100644
index 000000000..88a3c037e
--- /dev/null
+++ b/drivers/usb/core/phy.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * USB roothub wrapper
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#ifndef __USB_CORE_PHY_H_
+#define __USB_CORE_PHY_H_
+
+struct device;
+struct usb_phy_roothub;
+
+struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev);
+
+int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub);
+int usb_phy_roothub_exit(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);
+
+int usb_phy_roothub_suspend(struct device *controller_dev,
+ struct usb_phy_roothub *phy_roothub);
+int usb_phy_roothub_resume(struct device *controller_dev,
+ struct usb_phy_roothub *phy_roothub);
+
+#endif /* __USB_CORE_PHY_H_ */
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
new file mode 100644
index 000000000..1fe83b522
--- /dev/null
+++ b/drivers/usb/core/port.c
@@ -0,0 +1,604 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * usb port device code
+ *
+ * Copyright (C) 2012 Intel Corp
+ *
+ * Author: Lan Tianyu <tianyu.lan@intel.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/pm_qos.h>
+
+#include "hub.h"
+
+static int usb_port_block_power_off;
+
+static const struct attribute_group *port_dev_group[];
+
+static ssize_t connect_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ char *result;
+
+ switch (port_dev->connect_type) {
+ case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+ result = "hotplug";
+ break;
+ case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+ result = "hardwired";
+ break;
+ case USB_PORT_NOT_USED:
+ result = "not used";
+ break;
+ default:
+ result = "unknown";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", result);
+}
+static DEVICE_ATTR_RO(connect_type);
+
+static ssize_t over_current_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ return sprintf(buf, "%u\n", port_dev->over_current_count);
+}
+static DEVICE_ATTR_RO(over_current_count);
+
+static ssize_t quirks_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ return sprintf(buf, "%08x\n", port_dev->quirks);
+}
+
+static ssize_t quirks_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ u32 value;
+
+ if (kstrtou32(buf, 16, &value))
+ return -EINVAL;
+
+ port_dev->quirks = value;
+ return count;
+}
+static DEVICE_ATTR_RW(quirks);
+
+static ssize_t usb3_lpm_permit_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ const char *p;
+
+ if (port_dev->usb3_lpm_u1_permit) {
+ if (port_dev->usb3_lpm_u2_permit)
+ p = "u1_u2";
+ else
+ p = "u1";
+ } else {
+ if (port_dev->usb3_lpm_u2_permit)
+ p = "u2";
+ else
+ p = "0";
+ }
+
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t usb3_lpm_permit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ struct usb_device *udev = port_dev->child;
+ struct usb_hcd *hcd;
+
+ if (!strncmp(buf, "u1_u2", 5)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 1;
+
+ } else if (!strncmp(buf, "u1", 2)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 0;
+
+ } else if (!strncmp(buf, "u2", 2)) {
+ port_dev->usb3_lpm_u1_permit = 0;
+ port_dev->usb3_lpm_u2_permit = 1;
+
+ } else if (!strncmp(buf, "0", 1)) {
+ port_dev->usb3_lpm_u1_permit = 0;
+ port_dev->usb3_lpm_u2_permit = 0;
+ } else
+ return -EINVAL;
+
+ /* If device is connected to the port, disable or enable lpm
+ * to make new u1 u2 setting take effect immediately.
+ */
+ if (udev) {
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd)
+ return -EINVAL;
+ usb_lock_device(udev);
+ mutex_lock(hcd->bandwidth_mutex);
+ if (!usb_disable_lpm(udev))
+ usb_enable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_unlock_device(udev);
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb3_lpm_permit);
+
+static struct attribute *port_dev_attrs[] = {
+ &dev_attr_connect_type.attr,
+ &dev_attr_quirks.attr,
+ &dev_attr_over_current_count.attr,
+ NULL,
+};
+
+static struct attribute_group port_dev_attr_grp = {
+ .attrs = port_dev_attrs,
+};
+
+static const struct attribute_group *port_dev_group[] = {
+ &port_dev_attr_grp,
+ NULL,
+};
+
+static struct attribute *port_dev_usb3_attrs[] = {
+ &dev_attr_usb3_lpm_permit.attr,
+ NULL,
+};
+
+static struct attribute_group port_dev_usb3_attr_grp = {
+ .attrs = port_dev_usb3_attrs,
+};
+
+static const struct attribute_group *port_dev_usb3_group[] = {
+ &port_dev_attr_grp,
+ &port_dev_usb3_attr_grp,
+ NULL,
+};
+
+static void usb_port_device_release(struct device *dev)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ kfree(port_dev->req);
+ kfree(port_dev);
+}
+
+#ifdef CONFIG_PM
+static int usb_port_runtime_resume(struct device *dev)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ struct usb_device *hdev = to_usb_device(dev->parent->parent);
+ struct usb_interface *intf = to_usb_interface(dev->parent);
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ struct usb_device *udev = port_dev->child;
+ struct usb_port *peer = port_dev->peer;
+ int port1 = port_dev->portnum;
+ int retval;
+
+ if (!hub)
+ return -EINVAL;
+ if (hub->in_reset) {
+ set_bit(port1, hub->power_bits);
+ return 0;
+ }
+
+ /*
+ * Power on our usb3 peer before this usb2 port to prevent a usb3
+ * device from degrading to its usb2 connection
+ */
+ if (!port_dev->is_superspeed && peer)
+ pm_runtime_get_sync(&peer->dev);
+
+ retval = usb_autopm_get_interface(intf);
+ if (retval < 0)
+ return retval;
+
+ retval = usb_hub_set_port_power(hdev, hub, port1, true);
+ msleep(hub_power_on_good_delay(hub));
+ if (udev && !retval) {
+ /*
+ * Our preference is to simply wait for the port to reconnect,
+ * as that is the lowest latency method to restart the port.
+ * However, there are cases where toggling port power results in
+ * the host port and the device port getting out of sync causing
+ * a link training live lock. Upon timeout, flag the port as
+ * needing warm reset recovery (to be performed later by
+ * usb_port_resume() as requested via usb_wakeup_notification())
+ */
+ if (hub_port_debounce_be_connected(hub, port1) < 0) {
+ dev_dbg(&port_dev->dev, "reconnect timeout\n");
+ if (hub_is_superspeed(hdev))
+ set_bit(port1, hub->warm_reset_bits);
+ }
+
+ /* Force the child awake to revalidate after the power loss. */
+ if (!test_and_set_bit(port1, hub->child_usage_bits)) {
+ pm_runtime_get_noresume(&port_dev->dev);
+ pm_request_resume(&udev->dev);
+ }
+ }
+
+ usb_autopm_put_interface(intf);
+
+ return retval;
+}
+
+static int usb_port_runtime_suspend(struct device *dev)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ struct usb_device *hdev = to_usb_device(dev->parent->parent);
+ struct usb_interface *intf = to_usb_interface(dev->parent);
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ struct usb_port *peer = port_dev->peer;
+ int port1 = port_dev->portnum;
+ int retval;
+
+ if (!hub)
+ return -EINVAL;
+ if (hub->in_reset)
+ return -EBUSY;
+
+ if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)
+ == PM_QOS_FLAGS_ALL)
+ return -EAGAIN;
+
+ if (usb_port_block_power_off)
+ return -EBUSY;
+
+ retval = usb_autopm_get_interface(intf);
+ if (retval < 0)
+ return retval;
+
+ retval = usb_hub_set_port_power(hdev, hub, port1, false);
+ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
+ if (!port_dev->is_superspeed)
+ usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
+ usb_autopm_put_interface(intf);
+
+ /*
+ * Our peer usb3 port may now be able to suspend, so
+ * asynchronously queue a suspend request to observe that this
+ * usb2 port is now off.
+ */
+ if (!port_dev->is_superspeed && peer)
+ pm_runtime_put(&peer->dev);
+
+ return retval;
+}
+#endif
+
+static const struct dev_pm_ops usb_port_pm_ops = {
+#ifdef CONFIG_PM
+ .runtime_suspend = usb_port_runtime_suspend,
+ .runtime_resume = usb_port_runtime_resume,
+#endif
+};
+
+struct device_type usb_port_device_type = {
+ .name = "usb_port",
+ .release = usb_port_device_release,
+ .pm = &usb_port_pm_ops,
+};
+
+static struct device_driver usb_port_driver = {
+ .name = "usb",
+ .owner = THIS_MODULE,
+};
+
+static int link_peers(struct usb_port *left, struct usb_port *right)
+{
+ struct usb_port *ss_port, *hs_port;
+ int rc;
+
+ if (left->peer == right && right->peer == left)
+ return 0;
+
+ if (left->peer || right->peer) {
+ struct usb_port *lpeer = left->peer;
+ struct usb_port *rpeer = right->peer;
+ char *method;
+
+ if (left->location && left->location == right->location)
+ method = "location";
+ else
+ method = "default";
+
+ pr_debug("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
+ dev_name(&left->dev), dev_name(&right->dev), method,
+ dev_name(&left->dev),
+ lpeer ? dev_name(&lpeer->dev) : "none",
+ dev_name(&right->dev),
+ rpeer ? dev_name(&rpeer->dev) : "none");
+ return -EBUSY;
+ }
+
+ rc = sysfs_create_link(&left->dev.kobj, &right->dev.kobj, "peer");
+ if (rc)
+ return rc;
+ rc = sysfs_create_link(&right->dev.kobj, &left->dev.kobj, "peer");
+ if (rc) {
+ sysfs_remove_link(&left->dev.kobj, "peer");
+ return rc;
+ }
+
+ /*
+ * We need to wake the HiSpeed port to make sure we don't race
+ * setting ->peer with usb_port_runtime_suspend(). Otherwise we
+ * may miss a suspend event for the SuperSpeed port.
+ */
+ if (left->is_superspeed) {
+ ss_port = left;
+ WARN_ON(right->is_superspeed);
+ hs_port = right;
+ } else {
+ ss_port = right;
+ WARN_ON(!right->is_superspeed);
+ hs_port = left;
+ }
+ pm_runtime_get_sync(&hs_port->dev);
+
+ left->peer = right;
+ right->peer = left;
+
+ /*
+ * The SuperSpeed reference is dropped when the HiSpeed port in
+ * this relationship suspends, i.e. when it is safe to allow a
+ * SuperSpeed connection to drop since there is no risk of a
+ * device degrading to its powered-off HiSpeed connection.
+ *
+ * Also, drop the HiSpeed ref taken above.
+ */
+ pm_runtime_get_sync(&ss_port->dev);
+ pm_runtime_put(&hs_port->dev);
+
+ return 0;
+}
+
+static void link_peers_report(struct usb_port *left, struct usb_port *right)
+{
+ int rc;
+
+ rc = link_peers(left, right);
+ if (rc == 0) {
+ dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev));
+ } else {
+ dev_dbg(&left->dev, "failed to peer to %s (%d)\n",
+ dev_name(&right->dev), rc);
+ pr_warn_once("usb: port power management may be unreliable\n");
+ usb_port_block_power_off = 1;
+ }
+}
+
+static void unlink_peers(struct usb_port *left, struct usb_port *right)
+{
+ struct usb_port *ss_port, *hs_port;
+
+ WARN(right->peer != left || left->peer != right,
+ "%s and %s are not peers?\n",
+ dev_name(&left->dev), dev_name(&right->dev));
+
+ /*
+ * We wake the HiSpeed port to make sure we don't race its
+ * usb_port_runtime_resume() event which takes a SuperSpeed ref
+ * when ->peer is !NULL.
+ */
+ if (left->is_superspeed) {
+ ss_port = left;
+ hs_port = right;
+ } else {
+ ss_port = right;
+ hs_port = left;
+ }
+
+ pm_runtime_get_sync(&hs_port->dev);
+
+ sysfs_remove_link(&left->dev.kobj, "peer");
+ right->peer = NULL;
+ sysfs_remove_link(&right->dev.kobj, "peer");
+ left->peer = NULL;
+
+ /* Drop the SuperSpeed ref held on behalf of the active HiSpeed port */
+ pm_runtime_put(&ss_port->dev);
+
+ /* Drop the ref taken above */
+ pm_runtime_put(&hs_port->dev);
+}
+
+/*
+ * For each usb hub device in the system check to see if it is in the
+ * peer domain of the given port_dev, and if it is check to see if it
+ * has a port that matches the given port by location
+ */
+static int match_location(struct usb_device *peer_hdev, void *p)
+{
+ int port1;
+ struct usb_hcd *hcd, *peer_hcd;
+ struct usb_port *port_dev = p, *peer;
+ struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev);
+ struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent);
+
+ if (!peer_hub)
+ return 0;
+
+ hcd = bus_to_hcd(hdev->bus);
+ peer_hcd = bus_to_hcd(peer_hdev->bus);
+ /* peer_hcd is provisional until we verify it against the known peer */
+ if (peer_hcd != hcd->shared_hcd)
+ return 0;
+
+ for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) {
+ peer = peer_hub->ports[port1 - 1];
+ if (peer && peer->location == port_dev->location) {
+ link_peers_report(port_dev, peer);
+ return 1; /* done */
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Find the peer port either via explicit platform firmware "location"
+ * data, the peer hcd for root hubs, or the upstream peer relationship
+ * for all other hubs.
+ */
+static void find_and_link_peer(struct usb_hub *hub, int port1)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1], *peer;
+ struct usb_device *hdev = hub->hdev;
+ struct usb_device *peer_hdev;
+ struct usb_hub *peer_hub;
+
+ /*
+ * If location data is available then we can only peer this port
+ * by a location match, not the default peer (lest we create a
+ * situation where we need to go back and undo a default peering
+ * when the port is later peered by location data)
+ */
+ if (port_dev->location) {
+ /* we link the peer in match_location() if found */
+ usb_for_each_dev(port_dev, match_location);
+ return;
+ } else if (!hdev->parent) {
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ struct usb_hcd *peer_hcd = hcd->shared_hcd;
+
+ if (!peer_hcd)
+ return;
+
+ peer_hdev = peer_hcd->self.root_hub;
+ } else {
+ struct usb_port *upstream;
+ struct usb_device *parent = hdev->parent;
+ struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent);
+
+ if (!parent_hub)
+ return;
+
+ upstream = parent_hub->ports[hdev->portnum - 1];
+ if (!upstream || !upstream->peer)
+ return;
+
+ peer_hdev = upstream->peer->child;
+ }
+
+ peer_hub = usb_hub_to_struct_hub(peer_hdev);
+ if (!peer_hub || port1 > peer_hdev->maxchild)
+ return;
+
+ /*
+ * we found a valid default peer, last check is to make sure it
+ * does not have location data
+ */
+ peer = peer_hub->ports[port1 - 1];
+ if (peer && peer->location == 0)
+ link_peers_report(port_dev, peer);
+}
+
+int usb_hub_create_port_device(struct usb_hub *hub, int port1)
+{
+ struct usb_port *port_dev;
+ struct usb_device *hdev = hub->hdev;
+ int retval;
+
+ port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
+ if (!port_dev)
+ return -ENOMEM;
+
+ port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL);
+ if (!port_dev->req) {
+ kfree(port_dev);
+ return -ENOMEM;
+ }
+
+ hub->ports[port1 - 1] = port_dev;
+ port_dev->portnum = port1;
+ set_bit(port1, hub->power_bits);
+ port_dev->dev.parent = hub->intfdev;
+ if (hub_is_superspeed(hdev)) {
+ port_dev->usb3_lpm_u1_permit = 1;
+ port_dev->usb3_lpm_u2_permit = 1;
+ port_dev->dev.groups = port_dev_usb3_group;
+ } else
+ port_dev->dev.groups = port_dev_group;
+ port_dev->dev.type = &usb_port_device_type;
+ port_dev->dev.driver = &usb_port_driver;
+ if (hub_is_superspeed(hub->hdev))
+ port_dev->is_superspeed = 1;
+ dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
+ port1);
+ mutex_init(&port_dev->status_lock);
+ retval = device_register(&port_dev->dev);
+ if (retval) {
+ put_device(&port_dev->dev);
+ return retval;
+ }
+
+ /* Set default policy of port-poweroff disabled. */
+ retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req,
+ DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF);
+ if (retval < 0) {
+ device_unregister(&port_dev->dev);
+ return retval;
+ }
+
+ find_and_link_peer(hub, port1);
+
+ /*
+ * Enable runtime pm and hold a refernce that hub_configure()
+ * will drop once the PM_QOS_NO_POWER_OFF flag state has been set
+ * and the hub has been fully registered (hdev->maxchild set).
+ */
+ pm_runtime_set_active(&port_dev->dev);
+ pm_runtime_get_noresume(&port_dev->dev);
+ pm_runtime_enable(&port_dev->dev);
+ device_enable_async_suspend(&port_dev->dev);
+
+ /*
+ * Keep hidden the ability to enable port-poweroff if the hub
+ * does not support power switching.
+ */
+ if (!hub_is_port_power_switchable(hub))
+ return 0;
+
+ /* Attempt to let userspace take over the policy. */
+ retval = dev_pm_qos_expose_flags(&port_dev->dev,
+ PM_QOS_FLAG_NO_POWER_OFF);
+ if (retval < 0) {
+ dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n");
+ return 0;
+ }
+
+ /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */
+ retval = dev_pm_qos_remove_request(port_dev->req);
+ if (retval >= 0) {
+ kfree(port_dev->req);
+ port_dev->req = NULL;
+ }
+ return 0;
+}
+
+void usb_hub_remove_port_device(struct usb_hub *hub, int port1)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+ struct usb_port *peer;
+
+ peer = port_dev->peer;
+ if (peer)
+ unlink_peers(port_dev, peer);
+ device_unregister(&port_dev->dev);
+}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644
index 000000000..f8f2de789
--- /dev/null
+++ b/drivers/usb/core/quirks.c
@@ -0,0 +1,713 @@
+// 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>
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+struct quirk_entry {
+ u16 vid;
+ u16 pid;
+ u32 flags;
+};
+
+static DEFINE_MUTEX(quirk_mutex);
+
+static struct quirk_entry *quirk_list;
+static unsigned int quirk_count;
+
+static char quirks_param[128];
+
+static int quirks_param_set(const char *value, const struct kernel_param *kp)
+{
+ char *val, *p, *field;
+ u16 vid, pid;
+ u32 flags;
+ size_t i;
+ int err;
+
+ val = kstrdup(value, GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
+
+ err = param_set_copystring(val, kp);
+ if (err) {
+ kfree(val);
+ return err;
+ }
+
+ mutex_lock(&quirk_mutex);
+
+ if (!*val) {
+ quirk_count = 0;
+ kfree(quirk_list);
+ quirk_list = NULL;
+ goto unlock;
+ }
+
+ for (quirk_count = 1, i = 0; val[i]; i++)
+ if (val[i] == ',')
+ quirk_count++;
+
+ if (quirk_list) {
+ kfree(quirk_list);
+ quirk_list = NULL;
+ }
+
+ quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry),
+ GFP_KERNEL);
+ if (!quirk_list) {
+ quirk_count = 0;
+ mutex_unlock(&quirk_mutex);
+ kfree(val);
+ return -ENOMEM;
+ }
+
+ for (i = 0, p = val; p && *p;) {
+ /* Each entry consists of VID:PID:flags */
+ field = strsep(&p, ":");
+ if (!field)
+ break;
+
+ if (kstrtou16(field, 16, &vid))
+ break;
+
+ field = strsep(&p, ":");
+ if (!field)
+ break;
+
+ if (kstrtou16(field, 16, &pid))
+ break;
+
+ field = strsep(&p, ",");
+ if (!field || !*field)
+ break;
+
+ /* Collect the flags */
+ for (flags = 0; *field; field++) {
+ switch (*field) {
+ case 'a':
+ flags |= USB_QUIRK_STRING_FETCH_255;
+ break;
+ case 'b':
+ flags |= USB_QUIRK_RESET_RESUME;
+ break;
+ case 'c':
+ flags |= USB_QUIRK_NO_SET_INTF;
+ break;
+ case 'd':
+ flags |= USB_QUIRK_CONFIG_INTF_STRINGS;
+ break;
+ case 'e':
+ flags |= USB_QUIRK_RESET;
+ break;
+ case 'f':
+ flags |= USB_QUIRK_HONOR_BNUMINTERFACES;
+ break;
+ case 'g':
+ flags |= USB_QUIRK_DELAY_INIT;
+ break;
+ case 'h':
+ flags |= USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL;
+ break;
+ case 'i':
+ flags |= USB_QUIRK_DEVICE_QUALIFIER;
+ break;
+ case 'j':
+ flags |= USB_QUIRK_IGNORE_REMOTE_WAKEUP;
+ break;
+ case 'k':
+ flags |= USB_QUIRK_NO_LPM;
+ break;
+ case 'l':
+ flags |= USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL;
+ break;
+ case 'm':
+ flags |= USB_QUIRK_DISCONNECT_SUSPEND;
+ break;
+ case 'n':
+ flags |= USB_QUIRK_DELAY_CTRL_MSG;
+ break;
+ case 'o':
+ flags |= USB_QUIRK_HUB_SLOW_RESET;
+ break;
+ /* Ignore unrecognized flag characters */
+ }
+ }
+
+ quirk_list[i++] = (struct quirk_entry)
+ { .vid = vid, .pid = pid, .flags = flags };
+ }
+
+ if (i < quirk_count)
+ quirk_count = i;
+
+unlock:
+ mutex_unlock(&quirk_mutex);
+ kfree(val);
+
+ return 0;
+}
+
+static const struct kernel_param_ops quirks_param_ops = {
+ .set = quirks_param_set,
+ .get = param_get_string,
+};
+
+static struct kparam_string quirks_param_string = {
+ .maxlen = sizeof(quirks_param),
+ .string = quirks_param,
+};
+
+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.
+ * Device quirks are applied at the very beginning of the enumeration process,
+ * right after reading the device descriptor. They can thus only match on device
+ * information.
+ *
+ * Interface quirks are applied after reading all the configuration descriptors.
+ * They can match on both device and interface information.
+ *
+ * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as
+ * interface quirks, as they only influence the enumeration process which is run
+ * before processing the interface quirks.
+ *
+ * Please keep the lists ordered by:
+ * 1) Vendor ID
+ * 2) Product ID
+ * 3) Class ID
+ */
+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 },
+
+ /* HP 5300/5370C scanner */
+ { USB_DEVICE(0x03f0, 0x0701), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
+ /* HP v222w 16GB Mini USB Drive */
+ { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Creative SB Audigy 2 NX */
+ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* USB3503 */
+ { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Microsoft Wireless Laser Mouse 6000 Receiver */
+ { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Microsoft LifeCam-VX700 v2.0 */
+ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
+ { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
+ { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech HD Webcam C270 */
+ { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech HD Pro Webcams C920, C920-C, C922, 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 },
+ { USB_DEVICE(0x046d, 0x085c), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Logitech ConferenceCam CC3000e */
+ { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT },
+ { USB_DEVICE(0x046d, 0x0848), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Logitech PTZ Pro Camera */
+ { USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Logitech Screen Share */
+ { USB_DEVICE(0x046d, 0x086c), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Logitech Quickcam Fusion */
+ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam Orbit MP */
+ { USB_DEVICE(0x046d, 0x08c2), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam Pro for Notebook */
+ { USB_DEVICE(0x046d, 0x08c3), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam Pro 5000 */
+ { USB_DEVICE(0x046d, 0x08c5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam OEM Dell Notebook */
+ { USB_DEVICE(0x046d, 0x08c6), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam OEM Cisco VT Camera II */
+ { USB_DEVICE(0x046d, 0x08c7), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Harmony 700-series */
+ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Philips PSC805 audio device */
+ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Plantronic Audio 655 DSP */
+ { USB_DEVICE(0x047f, 0xc008), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Plantronic Audio 648 USB */
+ { USB_DEVICE(0x047f, 0xc013), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Artisman Watchdog Dongle */
+ { USB_DEVICE(0x04b4, 0x0526), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Microchip Joss Optical infrared touchboard device */
+ { USB_DEVICE(0x04d8, 0x000c), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* CarrolTouch 4000U */
+ { USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* CarrolTouch 4500U */
+ { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Samsung Android phone modem - ID conflict with SPH-I500 */
+ { USB_DEVICE(0x04e8, 0x6601), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Elan Touchscreen */
+ { USB_DEVICE(0x04f3, 0x0089), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ { USB_DEVICE(0x04f3, 0x009b), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ { USB_DEVICE(0x04f3, 0x010c), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ { USB_DEVICE(0x04f3, 0x0125), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ { USB_DEVICE(0x04f3, 0x016f), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ { USB_DEVICE(0x04f3, 0x0381), .driver_info =
+ USB_QUIRK_NO_LPM },
+
+ { USB_DEVICE(0x04f3, 0x21b8), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
+ /* Roland SC-8820 */
+ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Edirol SD-20 */
+ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Alcor Micro Corp. Hub */
+ { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* 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 },
+
+ /* Avision AV600U */
+ { USB_DEVICE(0x0638, 0x0a13), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
+ /* Saitek Cyborg Gold Joystick */
+ { USB_DEVICE(0x06a3, 0x0006), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Agfa SNAPSCAN 1212U */
+ { USB_DEVICE(0x06bd, 0x0001), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
+ { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Guillemot Webcam Hercules Dualpix Exchange*/
+ { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Guillemot Hercules DJ Console audio card (BZ 208357) */
+ { USB_DEVICE(0x06f8, 0xb000), .driver_info =
+ USB_QUIRK_ENDPOINT_BLACKLIST },
+
+ /* Midiman M-Audio Keystation 88es */
+ { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* SanDisk Ultra Fit and Ultra Flair */
+ { USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM },
+ { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* M-Systems Flash Disk Pioneers */
+ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Baum Vario Ultra */
+ { USB_DEVICE(0x0904, 0x6101), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+ { USB_DEVICE(0x0904, 0x6102), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+ { USB_DEVICE(0x0904, 0x6103), .driver_info =
+ USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+
+ /* Sound Devices USBPre2 */
+ { USB_DEVICE(0x0926, 0x0202), .driver_info =
+ USB_QUIRK_ENDPOINT_BLACKLIST },
+
+ /* Sound Devices MixPre-D */
+ { USB_DEVICE(0x0926, 0x0208), .driver_info =
+ USB_QUIRK_ENDPOINT_BLACKLIST },
+
+ /* Keytouch QWERTY Panel keyboard */
+ { USB_DEVICE(0x0926, 0x3333), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Kingston DataTraveler 3.0 */
+ { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
+ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
+
+ /* ELMO L-12F document camera */
+ { USB_DEVICE(0x09a1, 0x0028), .driver_info = USB_QUIRK_DELAY_CTRL_MSG },
+
+ /* Broadcom BCM92035DGROM BT dongle */
+ { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* MAYA44USB sound device */
+ { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* ASUS Base Station(T100) */
+ { USB_DEVICE(0x0b05, 0x17e0), .driver_info =
+ USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+
+ /* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/
+ { USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Realtek hub in Dell WD19 (Type-C) */
+ { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
+ { USB_DEVICE(0x0bda, 0x5487), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Generic RTL8153 based ethernet adapters */
+ { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* SONiX USB DEVICE Touchpad */
+ { USB_DEVICE(0x0c45, 0x7056), .driver_info =
+ USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+
+ /* Action Semiconductor flash disk */
+ { USB_DEVICE(0x10d6, 0x2200), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
+ /* novation SoundControl XL */
+ { USB_DEVICE(0x1235, 0x0061), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* 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 },
+
+ /* Razer - Razer Blade Keyboard */
+ { USB_DEVICE(0x1532, 0x0116), .driver_info =
+ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+
+ /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
+ { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Lenovo Powered USB-C Travel Hub (4X90S92381, RTL8153 GigE) */
+ { USB_DEVICE(0x17ef, 0x721e), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Lenovo ThinkCenter A630Z TI024Gen3 usb-audio */
+ { USB_DEVICE(0x17ef, 0xa012), .driver_info =
+ USB_QUIRK_DISCONNECT_SUSPEND },
+
+ /* Lenovo ThinkPad USB-C Dock Gen2 Ethernet (RTL8153 GigE) */
+ { USB_DEVICE(0x17ef, 0xa387), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* BUILDWIN Photo Frame */
+ { USB_DEVICE(0x1908, 0x1315), .driver_info =
+ USB_QUIRK_HONOR_BNUMINTERFACES },
+
+ /* Protocol and OTG Electrical Test Device */
+ { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
+ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+
+ /* Terminus Technology Inc. Hub */
+ { USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET },
+
+ /* Corsair K70 RGB */
+ { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT |
+ USB_QUIRK_DELAY_CTRL_MSG },
+
+ /* Corsair Strafe */
+ { USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT |
+ USB_QUIRK_DELAY_CTRL_MSG },
+
+ /* Corsair Strafe RGB */
+ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
+ USB_QUIRK_DELAY_CTRL_MSG },
+
+ /* Corsair K70 LUX RGB */
+ { USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Corsair K70 LUX */
+ { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
+
+ /* Corsair K70 RGB RAPDIFIRE */
+ { USB_DEVICE(0x1b1c, 0x1b38), .driver_info = USB_QUIRK_DELAY_INIT |
+ USB_QUIRK_DELAY_CTRL_MSG },
+
+ /* MIDI keyboard WORLDE MINI */
+ { USB_DEVICE(0x1c75, 0x0204), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Acer C120 LED Projector */
+ { USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Blackmagic Design Intensity Shuttle */
+ { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Blackmagic Design UltraStudio SDI */
+ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Hauppauge HVR-950q */
+ { USB_DEVICE(0x2040, 0x7200), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Raydium Touchscreen */
+ { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
+
+ { USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
+
+ { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* DJI CineSSD */
+ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* DELL USB GEN2 */
+ { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
+
+ /* VCOM device */
+ { USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* INTEL VALUE SSD */
+ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ { } /* terminating entry must be last */
+};
+
+static const struct usb_device_id usb_interface_quirk_list[] = {
+ /* Logitech UVC Cameras */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0),
+ .driver_info = USB_QUIRK_RESET_RESUME },
+
+ { } /* terminating entry must be last */
+};
+
+static const struct usb_device_id usb_amd_resume_quirk_list[] = {
+ /* Lenovo Mouse with Pixart controller */
+ { USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Pixart Mouse */
+ { USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
+ { USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
+ { USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
+ { USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Optical Mouse M90/M100 */
+ { USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ { } /* terminating entry must be last */
+};
+
+/*
+ * Entries for blacklisted endpoints that should be ignored when parsing
+ * configuration descriptors.
+ *
+ * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST.
+ */
+static const struct usb_device_id usb_endpoint_blacklist[] = {
+ { USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x01 },
+ { USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x81 },
+ { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
+ { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
+ { }
+};
+
+bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+ struct usb_host_interface *intf,
+ struct usb_endpoint_descriptor *epd)
+{
+ const struct usb_device_id *id;
+ unsigned int address;
+
+ for (id = usb_endpoint_blacklist; id->match_flags; ++id) {
+ if (!usb_match_device(udev, id))
+ continue;
+
+ if (!usb_match_one_id_intf(udev, intf, id))
+ continue;
+
+ address = id->driver_info;
+ if (address == epd->bEndpointAddress)
+ return true;
+ }
+
+ return false;
+}
+
+static bool usb_match_any_interface(struct usb_device *udev,
+ const struct usb_device_id *id)
+{
+ unsigned int i;
+
+ for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
+ struct usb_host_config *cfg = &udev->config[i];
+ unsigned int j;
+
+ for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
+ struct usb_interface_cache *cache;
+ struct usb_host_interface *intf;
+
+ cache = cfg->intf_cache[j];
+ if (cache->num_altsetting == 0)
+ continue;
+
+ intf = &cache->altsetting[0];
+ if (usb_match_one_id_intf(udev, intf, id))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int usb_amd_resume_quirk(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = bus_to_hcd(udev->bus);
+ /* The device should be attached directly to root hub */
+ if (udev->level == 1 && hcd->amd_resume_bug == 1)
+ return 1;
+
+ return 0;
+}
+
+static u32 usb_detect_static_quirks(struct usb_device *udev,
+ const struct usb_device_id *id)
+{
+ u32 quirks = 0;
+
+ for (; id->match_flags; id++) {
+ if (!usb_match_device(udev, id))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) &&
+ !usb_match_any_interface(udev, id))
+ continue;
+
+ quirks |= (u32)(id->driver_info);
+ }
+
+ return quirks;
+}
+
+static u32 usb_detect_dynamic_quirks(struct usb_device *udev)
+{
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+ int i, flags = 0;
+
+ mutex_lock(&quirk_mutex);
+
+ for (i = 0; i < quirk_count; i++) {
+ if (vid == quirk_list[i].vid && pid == quirk_list[i].pid) {
+ flags = quirk_list[i].flags;
+ break;
+ }
+ }
+
+ mutex_unlock(&quirk_mutex);
+
+ return flags;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+ udev->quirks = usb_detect_static_quirks(udev, usb_quirk_list);
+
+ /*
+ * Pixart-based mice would trigger remote wakeup issue on AMD
+ * Yangtze chipset, so set them as RESET_RESUME flag.
+ */
+ if (usb_amd_resume_quirk(udev))
+ udev->quirks |= usb_detect_static_quirks(udev,
+ usb_amd_resume_quirk_list);
+
+ udev->quirks ^= usb_detect_dynamic_quirks(udev);
+
+ if (udev->quirks)
+ dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+ udev->quirks);
+
+#ifdef CONFIG_USB_DEFAULT_PERSIST
+ if (!(udev->quirks & USB_QUIRK_RESET))
+ udev->persist_enabled = 1;
+#else
+ /* Hubs are automatically enabled for USB-PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ udev->persist_enabled = 1;
+#endif /* CONFIG_USB_DEFAULT_PERSIST */
+}
+
+void usb_detect_interface_quirks(struct usb_device *udev)
+{
+ u32 quirks;
+
+ quirks = usb_detect_static_quirks(udev, usb_interface_quirk_list);
+ if (quirks == 0)
+ return;
+
+ dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n",
+ quirks);
+ udev->quirks |= quirks;
+}
+
+void usb_release_quirk_list(void)
+{
+ mutex_lock(&quirk_mutex);
+ kfree(quirk_list);
+ quirk_list = NULL;
+ mutex_unlock(&quirk_mutex);
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
new file mode 100644
index 000000000..b93b18ba8
--- /dev/null
+++ b/drivers/usb/core/sysfs.c
@@ -0,0 +1,1161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/core/sysfs.c
+ *
+ * (C) Copyright 2002 David Brownell
+ * (C) Copyright 2002,2004 Greg Kroah-Hartman
+ * (C) Copyright 2002,2004 IBM Corp.
+ *
+ * All of the sysfs file attributes for usb devices and interfaces.
+ *
+ * Released under the GPLv2 only.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include <linux/of.h>
+#include "usb.h"
+
+/* Active configuration fields */
+#define usb_actconfig_show(field, format_string) \
+static ssize_t field##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_device *udev; \
+ struct usb_host_config *actconfig; \
+ ssize_t rc; \
+ \
+ udev = to_usb_device(dev); \
+ rc = usb_lock_device_interruptible(udev); \
+ if (rc < 0) \
+ return -EINTR; \
+ actconfig = udev->actconfig; \
+ if (actconfig) \
+ rc = sprintf(buf, format_string, \
+ actconfig->desc.field); \
+ usb_unlock_device(udev); \
+ return rc; \
+} \
+
+#define usb_actconfig_attr(field, format_string) \
+ usb_actconfig_show(field, format_string) \
+ static DEVICE_ATTR_RO(field)
+
+usb_actconfig_attr(bNumInterfaces, "%2d\n");
+usb_actconfig_attr(bmAttributes, "%2x\n");
+
+static ssize_t bMaxPower_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+ struct usb_host_config *actconfig;
+ ssize_t rc;
+
+ udev = to_usb_device(dev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+ actconfig = udev->actconfig;
+ if (actconfig)
+ rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
+ usb_unlock_device(udev);
+ return rc;
+}
+static DEVICE_ATTR_RO(bMaxPower);
+
+static ssize_t configuration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+ struct usb_host_config *actconfig;
+ ssize_t rc;
+
+ udev = to_usb_device(dev);
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+ actconfig = udev->actconfig;
+ if (actconfig && actconfig->string)
+ rc = sprintf(buf, "%s\n", actconfig->string);
+ usb_unlock_device(udev);
+ return rc;
+}
+static DEVICE_ATTR_RO(configuration);
+
+/* configuration value is always present, and r/w */
+usb_actconfig_show(bConfigurationValue, "%u\n");
+
+static ssize_t bConfigurationValue_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int config, value, rc;
+
+ if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
+ return -EINVAL;
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+ value = usb_set_configuration(udev, config);
+ usb_unlock_device(udev);
+ return (value < 0) ? value : count;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
+ bConfigurationValue_show, bConfigurationValue_store);
+
+#ifdef CONFIG_OF
+static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct device_node *of_node = dev->of_node;
+
+ return sprintf(buf, "%pOF\n", of_node);
+}
+static DEVICE_ATTR_RO(devspec);
+#endif
+
+/* String fields */
+#define usb_string_attr(name) \
+static ssize_t name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_device *udev; \
+ int retval; \
+ \
+ udev = to_usb_device(dev); \
+ retval = usb_lock_device_interruptible(udev); \
+ if (retval < 0) \
+ return -EINTR; \
+ retval = sprintf(buf, "%s\n", udev->name); \
+ usb_unlock_device(udev); \
+ return retval; \
+} \
+static DEVICE_ATTR_RO(name)
+
+usb_string_attr(product);
+usb_string_attr(manufacturer);
+usb_string_attr(serial);
+
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+ char *speed;
+
+ udev = to_usb_device(dev);
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5";
+ break;
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_FULL:
+ speed = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "480";
+ break;
+ case USB_SPEED_WIRELESS:
+ speed = "480";
+ break;
+ case USB_SPEED_SUPER:
+ speed = "5000";
+ break;
+ case USB_SPEED_SUPER_PLUS:
+ speed = "10000";
+ break;
+ default:
+ speed = "unknown";
+ }
+ return sprintf(buf, "%s\n", speed);
+}
+static DEVICE_ATTR_RO(speed);
+
+static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->rx_lanes);
+}
+static DEVICE_ATTR_RO(rx_lanes);
+
+static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->tx_lanes);
+}
+static DEVICE_ATTR_RO(tx_lanes);
+
+static ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->bus->busnum);
+}
+static DEVICE_ATTR_RO(busnum);
+
+static ssize_t devnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->devnum);
+}
+static DEVICE_ATTR_RO(devnum);
+
+static ssize_t devpath_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%s\n", udev->devpath);
+}
+static DEVICE_ATTR_RO(devpath);
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+ u16 bcdUSB;
+
+ udev = to_usb_device(dev);
+ bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
+ return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
+}
+static DEVICE_ATTR_RO(version);
+
+static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->maxchild);
+}
+static DEVICE_ATTR_RO(maxchild);
+
+static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "0x%x\n", udev->quirks);
+}
+static DEVICE_ATTR_RO(quirks);
+
+static ssize_t avoid_reset_quirk_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
+}
+
+static ssize_t avoid_reset_quirk_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int val, rc;
+
+ if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
+ return -EINVAL;
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+ if (val)
+ udev->quirks |= USB_QUIRK_RESET;
+ else
+ udev->quirks &= ~USB_QUIRK_RESET;
+ usb_unlock_device(udev);
+ return count;
+}
+static DEVICE_ATTR_RW(avoid_reset_quirk);
+
+static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR_RO(urbnum);
+
+static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev;
+ char *state;
+
+ udev = to_usb_device(dev);
+
+ switch (udev->removable) {
+ case USB_DEVICE_REMOVABLE:
+ state = "removable";
+ break;
+ case USB_DEVICE_FIXED:
+ state = "fixed";
+ break;
+ default:
+ state = "unknown";
+ }
+
+ return sprintf(buf, "%s\n", state);
+}
+static DEVICE_ATTR_RO(removable);
+
+static ssize_t ltm_capable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (usb_device_supports_ltm(to_usb_device(dev)))
+ return sprintf(buf, "%s\n", "yes");
+ return sprintf(buf, "%s\n", "no");
+}
+static DEVICE_ATTR_RO(ltm_capable);
+
+#ifdef CONFIG_PM
+
+static ssize_t persist_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%d\n", udev->persist_enabled);
+}
+
+static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int value, rc;
+
+ /* Hubs are always enabled for USB_PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ return -EPERM;
+
+ if (sscanf(buf, "%d", &value) != 1)
+ return -EINVAL;
+
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+ udev->persist_enabled = !!value;
+ usb_unlock_device(udev);
+ return count;
+}
+static DEVICE_ATTR_RW(persist);
+
+static int add_persist_attributes(struct device *dev)
+{
+ int rc = 0;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ /* Hubs are automatically enabled for USB_PERSIST,
+ * no point in creating the attribute file.
+ */
+ if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_persist.attr,
+ power_group_name);
+ }
+ return rc;
+}
+
+static void remove_persist_attributes(struct device *dev)
+{
+ sysfs_remove_file_from_group(&dev->kobj,
+ &dev_attr_persist.attr,
+ power_group_name);
+}
+
+static ssize_t connected_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%u\n",
+ jiffies_to_msecs(jiffies - udev->connect_time));
+}
+static DEVICE_ATTR_RO(connected_duration);
+
+/*
+ * If the device is resumed, the last time the device was suspended has
+ * been pre-subtracted from active_duration. We add the current time to
+ * get the duration that the device was actually active.
+ *
+ * If the device is suspended, the active_duration is up-to-date.
+ */
+static ssize_t active_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int duration;
+
+ if (udev->state != USB_STATE_SUSPENDED)
+ duration = jiffies_to_msecs(jiffies + udev->active_duration);
+ else
+ duration = jiffies_to_msecs(udev->active_duration);
+ return sprintf(buf, "%u\n", duration);
+}
+static DEVICE_ATTR_RO(active_duration);
+
+static ssize_t autosuspend_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
+}
+
+static ssize_t autosuspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 ||
+ value <= -INT_MAX/1000)
+ return -EINVAL;
+
+ pm_runtime_set_autosuspend_delay(dev, value * 1000);
+ return count;
+}
+static DEVICE_ATTR_RW(autosuspend);
+
+static const char on_string[] = "on";
+static const char auto_string[] = "auto";
+
+static void warn_level(void)
+{
+ static int level_warned;
+
+ if (!level_warned) {
+ level_warned = 1;
+ printk(KERN_WARNING "WARNING! power/level is deprecated; "
+ "use power/control instead\n");
+ }
+}
+
+static ssize_t level_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p = auto_string;
+
+ warn_level();
+ if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto)
+ p = on_string;
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t level_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int len = count;
+ char *cp;
+ int rc = count;
+ int rv;
+
+ warn_level();
+ cp = memchr(buf, '\n', count);
+ if (cp)
+ len = cp - buf;
+
+ rv = usb_lock_device_interruptible(udev);
+ if (rv < 0)
+ return -EINTR;
+
+ if (len == sizeof on_string - 1 &&
+ strncmp(buf, on_string, len) == 0)
+ usb_disable_autosuspend(udev);
+
+ else if (len == sizeof auto_string - 1 &&
+ strncmp(buf, auto_string, len) == 0)
+ usb_enable_autosuspend(udev);
+
+ else
+ rc = -EINVAL;
+
+ usb_unlock_device(udev);
+ return rc;
+}
+static DEVICE_ATTR_RW(level);
+
+static ssize_t usb2_hardware_lpm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p;
+
+ if (udev->usb2_hw_lpm_allowed == 1)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t usb2_hardware_lpm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ bool value;
+ int ret;
+
+ ret = usb_lock_device_interruptible(udev);
+ if (ret < 0)
+ return -EINTR;
+
+ ret = strtobool(buf, &value);
+
+ if (!ret) {
+ udev->usb2_hw_lpm_allowed = value;
+ if (value)
+ ret = usb_enable_usb2_hardware_lpm(udev);
+ else
+ ret = usb_disable_usb2_hardware_lpm(udev);
+ }
+
+ usb_unlock_device(udev);
+
+ if (!ret)
+ return count;
+
+ return ret;
+}
+static DEVICE_ATTR_RW(usb2_hardware_lpm);
+
+static ssize_t usb2_lpm_l1_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->l1_params.timeout);
+}
+
+static ssize_t usb2_lpm_l1_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ u16 timeout;
+
+ if (kstrtou16(buf, 0, &timeout))
+ return -EINVAL;
+
+ udev->l1_params.timeout = timeout;
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb2_lpm_l1_timeout);
+
+static ssize_t usb2_lpm_besl_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->l1_params.besl);
+}
+
+static ssize_t usb2_lpm_besl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ u8 besl;
+
+ if (kstrtou8(buf, 0, &besl) || besl > 15)
+ return -EINVAL;
+
+ udev->l1_params.besl = besl;
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb2_lpm_besl);
+
+static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p;
+ int rc;
+
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+
+ if (udev->usb3_lpm_u1_enabled)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ usb_unlock_device(udev);
+
+ return sprintf(buf, "%s\n", p);
+}
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
+
+static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p;
+ int rc;
+
+ rc = usb_lock_device_interruptible(udev);
+ if (rc < 0)
+ return -EINTR;
+
+ if (udev->usb3_lpm_u2_enabled)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ usb_unlock_device(udev);
+
+ return sprintf(buf, "%s\n", p);
+}
+static DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
+
+static struct attribute *usb2_hardware_lpm_attr[] = {
+ &dev_attr_usb2_hardware_lpm.attr,
+ &dev_attr_usb2_lpm_l1_timeout.attr,
+ &dev_attr_usb2_lpm_besl.attr,
+ NULL,
+};
+static struct attribute_group usb2_hardware_lpm_attr_group = {
+ .name = power_group_name,
+ .attrs = usb2_hardware_lpm_attr,
+};
+
+static struct attribute *usb3_hardware_lpm_attr[] = {
+ &dev_attr_usb3_hardware_lpm_u1.attr,
+ &dev_attr_usb3_hardware_lpm_u2.attr,
+ NULL,
+};
+static struct attribute_group usb3_hardware_lpm_attr_group = {
+ .name = power_group_name,
+ .attrs = usb3_hardware_lpm_attr,
+};
+
+static struct attribute *power_attrs[] = {
+ &dev_attr_autosuspend.attr,
+ &dev_attr_level.attr,
+ &dev_attr_connected_duration.attr,
+ &dev_attr_active_duration.attr,
+ NULL,
+};
+static struct attribute_group power_attr_group = {
+ .name = power_group_name,
+ .attrs = power_attrs,
+};
+
+static int add_power_attributes(struct device *dev)
+{
+ int rc = 0;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+ rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
+ if (udev->usb2_hw_lpm_capable == 1)
+ rc = sysfs_merge_group(&dev->kobj,
+ &usb2_hardware_lpm_attr_group);
+ 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);
+ }
+
+ return rc;
+}
+
+static void remove_power_attributes(struct device *dev)
+{
+ sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
+ sysfs_unmerge_group(&dev->kobj, &power_attr_group);
+}
+
+#else
+
+#define add_persist_attributes(dev) 0
+#define remove_persist_attributes(dev) do {} while (0)
+
+#define add_power_attributes(dev) 0
+#define remove_power_attributes(dev) do {} while (0)
+
+#endif /* CONFIG_PM */
+
+
+/* Descriptor fields */
+#define usb_descriptor_attr_le16(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct usb_device *udev; \
+ \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, \
+ le16_to_cpu(udev->descriptor.field)); \
+} \
+static DEVICE_ATTR_RO(field)
+
+usb_descriptor_attr_le16(idVendor, "%04x\n");
+usb_descriptor_attr_le16(idProduct, "%04x\n");
+usb_descriptor_attr_le16(bcdDevice, "%04x\n");
+
+#define usb_descriptor_attr(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct usb_device *udev; \
+ \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, udev->descriptor.field); \
+} \
+static DEVICE_ATTR_RO(field)
+
+usb_descriptor_attr(bDeviceClass, "%02x\n");
+usb_descriptor_attr(bDeviceSubClass, "%02x\n");
+usb_descriptor_attr(bDeviceProtocol, "%02x\n");
+usb_descriptor_attr(bNumConfigurations, "%d\n");
+usb_descriptor_attr(bMaxPacketSize0, "%d\n");
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t authorized_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t authorized_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ ssize_t result;
+ struct usb_device *usb_dev = to_usb_device(dev);
+ unsigned val;
+ result = sscanf(buf, "%u\n", &val);
+ if (result != 1)
+ result = -EINVAL;
+ else if (val == 0)
+ result = usb_deauthorize_device(usb_dev);
+ else
+ result = usb_authorize_device(usb_dev);
+ return result < 0 ? result : size;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
+ authorized_show, authorized_store);
+
+/* "Safely remove a device" */
+static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int rc = 0;
+
+ usb_lock_device(udev);
+ if (udev->state != USB_STATE_NOTATTACHED) {
+
+ /* To avoid races, first unconfigure and then remove */
+ usb_set_configuration(udev, -1);
+ rc = usb_remove_device(udev);
+ }
+ if (rc == 0)
+ rc = count;
+ usb_unlock_device(udev);
+ return rc;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store);
+
+
+static struct attribute *dev_attrs[] = {
+ /* current configuration's attributes */
+ &dev_attr_configuration.attr,
+ &dev_attr_bNumInterfaces.attr,
+ &dev_attr_bConfigurationValue.attr,
+ &dev_attr_bmAttributes.attr,
+ &dev_attr_bMaxPower.attr,
+ /* device attributes */
+ &dev_attr_urbnum.attr,
+ &dev_attr_idVendor.attr,
+ &dev_attr_idProduct.attr,
+ &dev_attr_bcdDevice.attr,
+ &dev_attr_bDeviceClass.attr,
+ &dev_attr_bDeviceSubClass.attr,
+ &dev_attr_bDeviceProtocol.attr,
+ &dev_attr_bNumConfigurations.attr,
+ &dev_attr_bMaxPacketSize0.attr,
+ &dev_attr_speed.attr,
+ &dev_attr_rx_lanes.attr,
+ &dev_attr_tx_lanes.attr,
+ &dev_attr_busnum.attr,
+ &dev_attr_devnum.attr,
+ &dev_attr_devpath.attr,
+ &dev_attr_version.attr,
+ &dev_attr_maxchild.attr,
+ &dev_attr_quirks.attr,
+ &dev_attr_avoid_reset_quirk.attr,
+ &dev_attr_authorized.attr,
+ &dev_attr_remove.attr,
+ &dev_attr_removable.attr,
+ &dev_attr_ltm_capable.attr,
+#ifdef CONFIG_OF
+ &dev_attr_devspec.attr,
+#endif
+ NULL,
+};
+static struct attribute_group dev_attr_grp = {
+ .attrs = dev_attrs,
+};
+
+/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
+ * accordingly.
+ */
+static struct attribute *dev_string_attrs[] = {
+ &dev_attr_manufacturer.attr,
+ &dev_attr_product.attr,
+ &dev_attr_serial.attr,
+ NULL
+};
+
+static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct usb_device *udev = to_usb_device(dev);
+
+ if (a == &dev_attr_manufacturer.attr) {
+ if (udev->manufacturer == NULL)
+ return 0;
+ } else if (a == &dev_attr_product.attr) {
+ if (udev->product == NULL)
+ return 0;
+ } else if (a == &dev_attr_serial.attr) {
+ if (udev->serial == NULL)
+ return 0;
+ }
+ return a->mode;
+}
+
+static struct attribute_group dev_string_attr_grp = {
+ .attrs = dev_string_attrs,
+ .is_visible = dev_string_attrs_are_visible,
+};
+
+const struct attribute_group *usb_device_groups[] = {
+ &dev_attr_grp,
+ &dev_string_attr_grp,
+ NULL
+};
+
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct usb_device *udev = to_usb_device(dev);
+ size_t nleft = count;
+ size_t srclen, n;
+ int cfgno;
+ void *src;
+ int retval;
+
+ retval = usb_lock_device_interruptible(udev);
+ if (retval < 0)
+ return -EINTR;
+ /* The binary attribute begins with the device descriptor.
+ * Following that are the raw descriptor entries for all the
+ * configurations (config plus subsidiary descriptors).
+ */
+ for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
+ nleft > 0; ++cfgno) {
+ if (cfgno < 0) {
+ src = &udev->descriptor;
+ srclen = sizeof(struct usb_device_descriptor);
+ } else {
+ src = udev->rawdescriptors[cfgno];
+ srclen = __le16_to_cpu(udev->config[cfgno].desc.
+ wTotalLength);
+ }
+ if (off < srclen) {
+ n = min(nleft, srclen - (size_t) off);
+ memcpy(buf, src + off, n);
+ nleft -= n;
+ buf += n;
+ off = 0;
+ } else {
+ off -= srclen;
+ }
+ }
+ usb_unlock_device(udev);
+ return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+ .attr = {.name = "descriptors", .mode = 0444},
+ .read = read_descriptors,
+ .size = 18 + 65535, /* dev descr + max-size raw descriptor */
+};
+
+int usb_create_sysfs_dev_files(struct usb_device *udev)
+{
+ struct device *dev = &udev->dev;
+ int retval;
+
+ retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+ if (retval)
+ goto error;
+
+ retval = add_persist_attributes(dev);
+ if (retval)
+ goto error;
+
+ retval = add_power_attributes(dev);
+ if (retval)
+ goto error;
+ return retval;
+error:
+ usb_remove_sysfs_dev_files(udev);
+ return retval;
+}
+
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
+{
+ struct device *dev = &udev->dev;
+
+ remove_power_attributes(dev);
+ remove_persist_attributes(dev);
+ device_remove_bin_file(dev, &dev_bin_attr_descriptors);
+}
+
+/* Interface Association Descriptor fields */
+#define usb_intf_assoc_attr(field, format_string) \
+static ssize_t \
+iad_##field##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ \
+ return sprintf(buf, format_string, \
+ intf->intf_assoc->field); \
+} \
+static DEVICE_ATTR_RO(iad_##field)
+
+usb_intf_assoc_attr(bFirstInterface, "%02x\n");
+usb_intf_assoc_attr(bInterfaceCount, "%02d\n");
+usb_intf_assoc_attr(bFunctionClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionSubClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionProtocol, "%02x\n");
+
+/* Interface fields */
+#define usb_intf_attr(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ \
+ return sprintf(buf, format_string, \
+ intf->cur_altsetting->desc.field); \
+} \
+static DEVICE_ATTR_RO(field)
+
+usb_intf_attr(bInterfaceNumber, "%02x\n");
+usb_intf_attr(bAlternateSetting, "%2d\n");
+usb_intf_attr(bNumEndpoints, "%02x\n");
+usb_intf_attr(bInterfaceClass, "%02x\n");
+usb_intf_attr(bInterfaceSubClass, "%02x\n");
+usb_intf_attr(bInterfaceProtocol, "%02x\n");
+
+static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *intf;
+ char *string;
+
+ intf = to_usb_interface(dev);
+ string = READ_ONCE(intf->cur_altsetting->string);
+ if (!string)
+ return 0;
+ return sprintf(buf, "%s\n", string);
+}
+static DEVICE_ATTR_RO(interface);
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ struct usb_host_interface *alt;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
+ alt = READ_ONCE(intf->cur_altsetting);
+
+ return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
+ "ic%02Xisc%02Xip%02Xin%02X\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ le16_to_cpu(udev->descriptor.bcdDevice),
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+ udev->descriptor.bDeviceProtocol,
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol,
+ alt->desc.bInterfaceNumber);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static ssize_t supports_autosuspend_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int s;
+
+ s = device_lock_interruptible(dev);
+ if (s < 0)
+ return -EINTR;
+ /* Devices will be autosuspended even when an interface isn't claimed */
+ s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
+ device_unlock(dev);
+
+ return sprintf(buf, "%u\n", s);
+}
+static DEVICE_ATTR_RO(supports_autosuspend);
+
+/*
+ * interface_authorized_show - show authorization status of an USB interface
+ * 1 is authorized, 0 is deauthorized
+ */
+static ssize_t interface_authorized_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+
+ return sprintf(buf, "%u\n", intf->authorized);
+}
+
+/*
+ * interface_authorized_store - authorize or deauthorize an USB interface
+ */
+static ssize_t interface_authorized_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ bool val;
+
+ if (strtobool(buf, &val) != 0)
+ return -EINVAL;
+
+ if (val)
+ usb_authorize_interface(intf);
+ else
+ usb_deauthorize_interface(intf);
+
+ return count;
+}
+static struct device_attribute dev_attr_interface_authorized =
+ __ATTR(authorized, S_IRUGO | S_IWUSR,
+ interface_authorized_show, interface_authorized_store);
+
+static struct attribute *intf_attrs[] = {
+ &dev_attr_bInterfaceNumber.attr,
+ &dev_attr_bAlternateSetting.attr,
+ &dev_attr_bNumEndpoints.attr,
+ &dev_attr_bInterfaceClass.attr,
+ &dev_attr_bInterfaceSubClass.attr,
+ &dev_attr_bInterfaceProtocol.attr,
+ &dev_attr_modalias.attr,
+ &dev_attr_supports_autosuspend.attr,
+ &dev_attr_interface_authorized.attr,
+ NULL,
+};
+static struct attribute_group intf_attr_grp = {
+ .attrs = intf_attrs,
+};
+
+static struct attribute *intf_assoc_attrs[] = {
+ &dev_attr_iad_bFirstInterface.attr,
+ &dev_attr_iad_bInterfaceCount.attr,
+ &dev_attr_iad_bFunctionClass.attr,
+ &dev_attr_iad_bFunctionSubClass.attr,
+ &dev_attr_iad_bFunctionProtocol.attr,
+ NULL,
+};
+
+static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct usb_interface *intf = to_usb_interface(dev);
+
+ if (intf->intf_assoc == NULL)
+ return 0;
+ return a->mode;
+}
+
+static struct attribute_group intf_assoc_attr_grp = {
+ .attrs = intf_assoc_attrs,
+ .is_visible = intf_assoc_attrs_are_visible,
+};
+
+const struct attribute_group *usb_interface_groups[] = {
+ &intf_attr_grp,
+ &intf_assoc_attr_grp,
+ NULL
+};
+
+void usb_create_sysfs_intf_files(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+
+ if (intf->sysfs_files_created || intf->unregistering)
+ return;
+
+ if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+ alt->string = usb_cache_string(udev, alt->desc.iInterface);
+ if (alt->string && device_create_file(&intf->dev, &dev_attr_interface))
+ ; /* We don't actually care if the function fails. */
+ intf->sysfs_files_created = 1;
+}
+
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
+{
+ if (!intf->sysfs_files_created)
+ return;
+
+ device_remove_file(&intf->dev, &dev_attr_interface);
+ intf->sysfs_files_created = 0;
+}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
new file mode 100644
index 000000000..e88e04a24
--- /dev/null
+++ b/drivers/usb/core/urb.c
@@ -0,0 +1,1029 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
+
+#define to_urb(d) container_of(d, struct urb, kref)
+
+
+static void urb_destroy(struct kref *kref)
+{
+ struct urb *urb = to_urb(kref);
+
+ if (urb->transfer_flags & URB_FREE_BUFFER)
+ kfree(urb->transfer_buffer);
+
+ kfree(urb);
+}
+
+/**
+ * usb_init_urb - initializes a urb so that it can be used by a USB driver
+ * @urb: pointer to the urb to initialize
+ *
+ * Initializes a urb so that the USB subsystem can use it properly.
+ *
+ * If a urb is created with a call to usb_alloc_urb() it is not
+ * necessary to call this function. Only use this if you allocate the
+ * space for a struct urb on your own. If you call this function, be
+ * careful when freeing the memory for your urb that it is no longer in
+ * use by the USB core.
+ *
+ * Only use this function if you _really_ understand what you are doing.
+ */
+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);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_init_urb);
+
+/**
+ * usb_alloc_urb - creates a new urb for a USB driver to use
+ * @iso_packets: number of iso packets for this urb
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
+ * valid options for this.
+ *
+ * Creates an urb for the USB driver to use, initializes a few internal
+ * structures, increments the usage counter, and returns a pointer to it.
+ *
+ * If the driver want to use this urb for interrupt, control, or bulk
+ * endpoints, pass '0' as the number of iso packets.
+ *
+ * The driver must call usb_free_urb() when it is finished with the urb.
+ *
+ * Return: A pointer to the new urb, or %NULL if no memory is available.
+ */
+struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
+{
+ struct urb *urb;
+
+ urb = kmalloc(sizeof(struct urb) +
+ iso_packets * sizeof(struct usb_iso_packet_descriptor),
+ mem_flags);
+ if (!urb)
+ return NULL;
+ usb_init_urb(urb);
+ return urb;
+}
+EXPORT_SYMBOL_GPL(usb_alloc_urb);
+
+/**
+ * usb_free_urb - frees the memory used by a urb when all users of it are finished
+ * @urb: pointer to the urb to free, may be NULL
+ *
+ * Must be called when a user of a urb is finished with it. When the last user
+ * of the urb calls this function, the memory of the urb is freed.
+ *
+ * Note: The transfer buffer associated with the urb is not freed unless the
+ * URB_FREE_BUFFER transfer flag is set.
+ */
+void usb_free_urb(struct urb *urb)
+{
+ if (urb)
+ kref_put(&urb->kref, urb_destroy);
+}
+EXPORT_SYMBOL_GPL(usb_free_urb);
+
+/**
+ * usb_get_urb - increments the reference count of the urb
+ * @urb: pointer to the urb to modify, may be NULL
+ *
+ * This must be called whenever a urb is transferred from a device driver to a
+ * host controller driver. This allows proper reference counting to happen
+ * for urbs.
+ *
+ * Return: A pointer to the urb with the incremented reference counter.
+ */
+struct urb *usb_get_urb(struct urb *urb)
+{
+ if (urb)
+ kref_get(&urb->kref);
+ return urb;
+}
+EXPORT_SYMBOL_GPL(usb_get_urb);
+
+/**
+ * usb_anchor_urb - anchors an URB while it is processed
+ * @urb: pointer to the urb to anchor
+ * @anchor: pointer to the anchor
+ *
+ * This can be called to have access to URBs which are to be executed
+ * without bothering to track them
+ */
+void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ usb_get_urb(urb);
+ list_add_tail(&urb->anchor_list, &anchor->urb_list);
+ urb->anchor = anchor;
+
+ if (unlikely(anchor->poisoned))
+ atomic_inc(&urb->reject);
+
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_anchor_urb);
+
+static int usb_anchor_check_wakeup(struct usb_anchor *anchor)
+{
+ return atomic_read(&anchor->suspend_wakeups) == 0 &&
+ list_empty(&anchor->urb_list);
+}
+
+/* Callers must hold anchor->lock */
+static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+ urb->anchor = NULL;
+ list_del(&urb->anchor_list);
+ usb_put_urb(urb);
+ if (usb_anchor_check_wakeup(anchor))
+ wake_up(&anchor->wait);
+}
+
+/**
+ * usb_unanchor_urb - unanchors an URB
+ * @urb: pointer to the urb to anchor
+ *
+ * Call this to stop the system keeping track of this URB
+ */
+void usb_unanchor_urb(struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_anchor *anchor;
+
+ if (!urb)
+ return;
+
+ anchor = urb->anchor;
+ if (!anchor)
+ return;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ /*
+ * At this point, we could be competing with another thread which
+ * has the same intention. To protect the urb from being unanchored
+ * twice, only the winner of the race gets the job.
+ */
+ if (likely(anchor == urb->anchor))
+ __usb_unanchor_urb(urb, anchor);
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+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
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list
+ * of valid options for this.
+ *
+ * This submits a transfer request, and transfers control of the URB
+ * describing that request to the USB subsystem. Request completion will
+ * be indicated later, asynchronously, by calling the completion handler.
+ * The three types of completion are success, error, and unlink
+ * (a software-induced fault, also called "request cancellation").
+ *
+ * URBs may be submitted in interrupt context.
+ *
+ * The caller must have correctly initialized the URB before submitting
+ * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
+ * available to ensure that most fields are correctly initialized, for
+ * the particular kind of transfer, although they will not initialize
+ * any transfer flags.
+ *
+ * If the submission is successful, the complete() callback from the URB
+ * will be called exactly once, when the USB core and Host Controller Driver
+ * (HCD) are finished with the URB. When the completion function is called,
+ * control of the URB is returned to the device driver which issued the
+ * request. The completion handler may then immediately free or reuse that
+ * URB.
+ *
+ * With few exceptions, USB device drivers should never access URB fields
+ * provided by usbcore or the HCD until its complete() is called.
+ * The exceptions relate to periodic transfer scheduling. For both
+ * interrupt and isochronous urbs, as part of successful URB submission
+ * urb->interval is modified to reflect the actual transfer period used
+ * (normally some power of two units). And for isochronous urbs,
+ * urb->start_frame is modified to reflect when the URB's transfers were
+ * scheduled to start.
+ *
+ * Not all isochronous transfer scheduling policies will work, but most
+ * host controller drivers should easily handle ISO queues going from now
+ * until 10-200 msec into the future. Drivers should try to keep at
+ * least one or two msec of data in the queue; many controllers require
+ * that new transfers start at least 1 msec in the future when they are
+ * added. If the driver is unable to keep up and the queue empties out,
+ * the behavior for new submissions is governed by the URB_ISO_ASAP flag.
+ * If the flag is set, or if the queue is idle, then the URB is always
+ * assigned to the first available (and not yet expired) slot in the
+ * endpoint's schedule. If the flag is not set and the queue is active
+ * then the URB is always assigned to the next slot in the schedule
+ * following the end of the endpoint's previous URB, even if that slot is
+ * in the past. When a packet is assigned in this way to a slot that has
+ * already expired, the packet is not transmitted and the corresponding
+ * usb_iso_packet_descriptor's status field will return -EXDEV. If this
+ * would happen to all the packets in the URB, submission fails with a
+ * -EXDEV error code.
+ *
+ * For control endpoints, the synchronous usb_control_msg() call is
+ * often used (in non-interrupt context) instead of this call.
+ * That is often used through convenience wrappers, for the requests
+ * that are standardized in the USB 2.0 specification. For bulk
+ * endpoints, a synchronous usb_bulk_msg() call is available.
+ *
+ * Return:
+ * 0 on successful submissions. A negative error number otherwise.
+ *
+ * Request Queuing:
+ *
+ * URBs may be submitted to endpoints before previous ones complete, to
+ * minimize the impact of interrupt latencies and system overhead on data
+ * throughput. With that queuing policy, an endpoint's queue would never
+ * be empty. This is required for continuous isochronous data streams,
+ * and may also be required for some kinds of interrupt transfers. Such
+ * queuing also maximizes bandwidth utilization by letting USB controllers
+ * start work on later requests before driver software has finished the
+ * completion processing for earlier (successful) requests.
+ *
+ * As of Linux 2.6, all USB endpoint transfer queues support depths greater
+ * than one. This was previously a HCD-specific behavior, except for ISO
+ * transfers. Non-isochronous endpoint queues are inactive during cleanup
+ * after faults (transfer errors or cancellation).
+ *
+ * Reserved Bandwidth Transfers:
+ *
+ * Periodic transfers (interrupt or isochronous) are performed repeatedly,
+ * using the interval specified in the urb. Submitting the first urb to
+ * the endpoint reserves the bandwidth necessary to make those transfers.
+ * If the USB subsystem can't allocate sufficient bandwidth to perform
+ * the periodic request, submitting such a periodic request should fail.
+ *
+ * For devices under xHCI, the bandwidth is reserved at configuration time, or
+ * when the alt setting is selected. If there is not enough bus bandwidth, the
+ * configuration/alt setting request will fail. Therefore, submissions to
+ * periodic endpoints on devices under xHCI should never fail due to bandwidth
+ * constraints.
+ *
+ * Device drivers must explicitly request that repetition, by ensuring that
+ * some URB is always on the endpoint's queue (except possibly for short
+ * periods during completion callbacks). When there is no longer an urb
+ * queued, the endpoint's bandwidth reservation is canceled. This means
+ * drivers can use their completion handlers to ensure they keep bandwidth
+ * they need, by reinitializing and resubmitting the just-completed urb
+ * until the driver longer needs that periodic bandwidth.
+ *
+ * Memory Flags:
+ *
+ * The general rules for how to decide which mem_flags to use
+ * are the same as for kmalloc. There are four
+ * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
+ * GFP_ATOMIC.
+ *
+ * GFP_NOFS is not ever used, as it has not been implemented yet.
+ *
+ * GFP_ATOMIC is used when
+ * (a) you are inside a completion handler, an interrupt, bottom half,
+ * tasklet or timer, or
+ * (b) you are holding a spinlock or rwlock (does not apply to
+ * semaphores), or
+ * (c) current->state != TASK_RUNNING, this is the case only after
+ * you've changed it.
+ *
+ * GFP_NOIO is used in the block io path and error handling of storage
+ * devices.
+ *
+ * All other situations use GFP_KERNEL.
+ *
+ * Some more specific rules for mem_flags can be inferred, such as
+ * (1) start_xmit, timeout, and receive methods of network drivers must
+ * use GFP_ATOMIC (they are called with a spinlock held);
+ * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
+ * called with a spinlock held);
+ * (3) If you use a kernel thread with a network driver you must use
+ * GFP_NOIO, unless (b) or (c) apply;
+ * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
+ * apply or your are in a storage driver's block io path;
+ * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
+ * (6) changing firmware on a running storage or net device uses
+ * GFP_NOIO, unless b) or c) apply
+ *
+ */
+int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+{
+ int xfertype, max;
+ struct usb_device *dev;
+ struct usb_host_endpoint *ep;
+ int is_out;
+ unsigned int allowed;
+
+ if (!urb || !urb->complete)
+ return -EINVAL;
+ if (urb->hcpriv) {
+ WARN_ONCE(1, "URB %pK submitted while active\n", urb);
+ return -EBUSY;
+ }
+
+ dev = urb->dev;
+ if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
+ return -ENODEV;
+
+ /* For now, get the endpoint from the pipe. Eventually drivers
+ * will be required to set urb->ep directly and we will eliminate
+ * urb->pipe.
+ */
+ ep = usb_pipe_endpoint(dev, urb->pipe);
+ if (!ep)
+ return -ENOENT;
+
+ urb->ep = ep;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+
+ /* Lots of sanity checks, so HCDs can rely on clean data
+ * and don't need to duplicate tests
+ */
+ xfertype = usb_endpoint_type(&ep->desc);
+ if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+ struct usb_ctrlrequest *setup =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!setup)
+ return -ENOEXEC;
+ is_out = !(setup->bRequestType & USB_DIR_IN) ||
+ !setup->wLength;
+ } else {
+ is_out = usb_endpoint_dir_out(&ep->desc);
+ }
+
+ /* Clear the internal flags and cache the direction for later use */
+ urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
+ URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
+ URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
+ URB_DMA_SG_COMBINED);
+ urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
+
+ if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+ dev->state < USB_STATE_CONFIGURED)
+ return -ENODEV;
+
+ max = usb_endpoint_maxp(&ep->desc);
+ if (max <= 0) {
+ dev_dbg(&dev->dev,
+ "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
+ usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
+ __func__, max);
+ return -EMSGSIZE;
+ }
+
+ /* periodic transfers limit size per frame/uframe,
+ * but drivers only control those sizes for ISO.
+ * while we're checking, initialize return status.
+ */
+ if (xfertype == USB_ENDPOINT_XFER_ISOC) {
+ int n, len;
+
+ /* SuperSpeed isoc endpoints have up to 16 bursts of up to
+ * 3 packets each
+ */
+ if (dev->speed >= USB_SPEED_SUPER) {
+ int burst = 1 + ep->ss_ep_comp.bMaxBurst;
+ int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
+ max *= burst;
+ max *= mult;
+ }
+
+ if (dev->speed == USB_SPEED_SUPER_PLUS &&
+ USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) {
+ struct usb_ssp_isoc_ep_comp_descriptor *isoc_ep_comp;
+
+ isoc_ep_comp = &ep->ssp_isoc_ep_comp;
+ max = le32_to_cpu(isoc_ep_comp->dwBytesPerInterval);
+ }
+
+ /* "high bandwidth" mode, 1-3 packets/uframe? */
+ if (dev->speed == USB_SPEED_HIGH)
+ max *= usb_endpoint_maxp_mult(&ep->desc);
+
+ if (urb->number_of_packets <= 0)
+ return -EINVAL;
+ for (n = 0; n < urb->number_of_packets; n++) {
+ len = urb->iso_frame_desc[n].length;
+ if (len < 0 || len > max)
+ return -EMSGSIZE;
+ urb->iso_frame_desc[n].status = -EXDEV;
+ urb->iso_frame_desc[n].actual_length = 0;
+ }
+ } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
+ dev->speed != USB_SPEED_WIRELESS) {
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
+ if (sg->length % max)
+ return -EINVAL;
+ }
+
+ /* the I/O buffer must be mapped/unmapped, except when length=0 */
+ if (urb->transfer_buffer_length > INT_MAX)
+ return -EMSGSIZE;
+
+ /*
+ * stuff that drivers shouldn't do, but which shouldn't
+ * cause problems in HCDs if they get it wrong.
+ */
+
+ /* Check that the pipe's type matches the endpoint's type */
+ 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]);
+
+ /* Check against a simple/standard policy */
+ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
+ URB_FREE_BUFFER);
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ if (is_out)
+ allowed |= URB_ZERO_PACKET;
+ /* FALLTHROUGH */
+ default: /* all non-iso endpoints */
+ if (!is_out)
+ allowed |= URB_SHORT_NOT_OK;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ allowed |= URB_ISO_ASAP;
+ break;
+ }
+ allowed &= urb->transfer_flags;
+
+ /* warn if submitter gave bogus flags */
+ if (allowed != urb->transfer_flags)
+ dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
+ urb->transfer_flags, allowed);
+
+ /*
+ * Force periodic transfer intervals to be legal values that are
+ * a power of two (so HCDs don't need to).
+ *
+ * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
+ * supports different values... this uses EHCI/UHCI defaults (and
+ * EHCI can use smaller non-default values).
+ */
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
+ /* too small? */
+ switch (dev->speed) {
+ case USB_SPEED_WIRELESS:
+ if ((urb->interval < 6)
+ && (xfertype == USB_ENDPOINT_XFER_INT))
+ return -EINVAL;
+ /* fall through */
+ default:
+ if (urb->interval <= 0)
+ return -EINVAL;
+ break;
+ }
+ /* too big? */
+ switch (dev->speed) {
+ case USB_SPEED_SUPER_PLUS:
+ case USB_SPEED_SUPER: /* units are 125us */
+ /* Handle up to 2^(16-1) microframes */
+ if (urb->interval > (1 << 15))
+ return -EINVAL;
+ max = 1 << 15;
+ break;
+ case USB_SPEED_WIRELESS:
+ if (urb->interval > 16)
+ return -EINVAL;
+ break;
+ case USB_SPEED_HIGH: /* units are microframes */
+ /* NOTE usb handles 2^15 */
+ if (urb->interval > (1024 * 8))
+ urb->interval = 1024 * 8;
+ max = 1024 * 8;
+ break;
+ case USB_SPEED_FULL: /* units are frames/msec */
+ case USB_SPEED_LOW:
+ if (xfertype == USB_ENDPOINT_XFER_INT) {
+ if (urb->interval > 255)
+ return -EINVAL;
+ /* NOTE ohci only handles up to 32 */
+ max = 128;
+ } else {
+ if (urb->interval > 1024)
+ urb->interval = 1024;
+ /* NOTE usb and ohci handle up to 2^15 */
+ max = 1024;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (dev->speed != USB_SPEED_WIRELESS) {
+ /* Round down to a power of 2, no more than max */
+ urb->interval = min(max, 1 << ilog2(urb->interval));
+ }
+ }
+
+ return usb_hcd_submit_urb(urb, mem_flags);
+}
+EXPORT_SYMBOL_GPL(usb_submit_urb);
+
+/*-------------------------------------------------------------------*/
+
+/**
+ * usb_unlink_urb - abort/cancel a transfer request for an endpoint
+ * @urb: pointer to urb describing a previously submitted request,
+ * may be NULL
+ *
+ * This routine cancels an in-progress request. URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * Drivers should not call this routine or related routines, such as
+ * usb_kill_urb() or usb_unlink_anchored_urbs(), after their disconnect
+ * method has returned. The disconnect function should synchronize with
+ * a driver's I/O routines to insure that all URB-related activity has
+ * completed before it returns.
+ *
+ * This request is asynchronous, however the HCD might call the ->complete()
+ * callback during unlink. Therefore when drivers call usb_unlink_urb(), they
+ * must not hold any locks that may be taken by the completion function.
+ * Success is indicated by returning -EINPROGRESS, at which time the URB will
+ * probably not yet have been given back to the device driver. When it is
+ * eventually called, the completion function will see @urb->status ==
+ * -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
+ * Return: -EINPROGRESS on success. See description for other values on
+ * failure.
+ *
+ * Unlinking and Endpoint Queues:
+ *
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
+ * Host Controller Drivers (HCDs) place all the URBs for a particular
+ * endpoint in a queue. Normally the queue advances as the controller
+ * hardware processes each request. But when an URB terminates with an
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns. It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns. The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO. Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors. Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates. Such queues do not stop when an URB
+ * encounters an error or is unlinked. An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
+ */
+int usb_unlink_urb(struct urb *urb)
+{
+ if (!urb)
+ return -EINVAL;
+ if (!urb->dev)
+ return -ENODEV;
+ if (!urb->ep)
+ return -EIDRM;
+ return usb_hcd_unlink_urb(urb, -ECONNRESET);
+}
+EXPORT_SYMBOL_GPL(usb_unlink_urb);
+
+/**
+ * usb_kill_urb - cancel a transfer request and wait for it to finish
+ * @urb: pointer to URB describing a previously submitted request,
+ * may be NULL
+ *
+ * This routine cancels an in-progress request. It is guaranteed that
+ * upon return all completion handlers will have finished and the URB
+ * will be totally idle and available for reuse. These features make
+ * this an ideal way to stop I/O in a disconnect() callback or close()
+ * function. If the request has not already finished or been unlinked
+ * the completion handler will see urb->status == -ENOENT.
+ *
+ * While the routine is running, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
+ * This routine may not be used in an interrupt context (such as a bottom
+ * half or a completion handler), or when holding a spinlock, or in other
+ * situations where the caller can't schedule().
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_kill_urb(struct urb *urb)
+{
+ might_sleep();
+ if (!(urb && urb->dev && urb->ep))
+ return;
+ atomic_inc(&urb->reject);
+ /*
+ * Order the write of urb->reject above before the read
+ * of urb->use_count below. Pairs with the barriers in
+ * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+ */
+ smp_mb__after_atomic();
+
+ usb_hcd_unlink_urb(urb, -ENOENT);
+ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+
+ atomic_dec(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_kill_urb);
+
+/**
+ * usb_poison_urb - reliably kill a transfer and prevent further use of an URB
+ * @urb: pointer to URB describing a previously submitted request,
+ * may be NULL
+ *
+ * This routine cancels an in-progress request. It is guaranteed that
+ * upon return all completion handlers will have finished and the URB
+ * will be totally idle and cannot be reused. These features make
+ * this an ideal way to stop I/O in a disconnect() callback.
+ * If the request has not already finished or been unlinked
+ * the completion handler will see urb->status == -ENOENT.
+ *
+ * After and while the routine runs, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
+ * This routine may not be used in an interrupt context (such as a bottom
+ * half or a completion handler), or when holding a spinlock, or in other
+ * situations where the caller can't schedule().
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_poison_urb(struct urb *urb)
+{
+ might_sleep();
+ if (!urb)
+ return;
+ atomic_inc(&urb->reject);
+ /*
+ * Order the write of urb->reject above before the read
+ * of urb->use_count below. Pairs with the barriers in
+ * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+ */
+ smp_mb__after_atomic();
+
+ if (!urb->dev || !urb->ep)
+ return;
+
+ usb_hcd_unlink_urb(urb, -ENOENT);
+ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+}
+EXPORT_SYMBOL_GPL(usb_poison_urb);
+
+void usb_unpoison_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+
+ atomic_dec(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_urb);
+
+/**
+ * usb_block_urb - reliably prevent further use of an URB
+ * @urb: pointer to URB to be blocked, may be NULL
+ *
+ * After the routine has run, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ */
+void usb_block_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+
+ atomic_inc(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_block_urb);
+
+/**
+ * usb_kill_anchored_urbs - kill all URBs associated with an anchor
+ * @anchor: anchor the requests are bound to
+ *
+ * This kills all outstanding URBs starting from the back of the queue,
+ * with guarantee that no completer callbacks will take place from the
+ * anchor after this function returns.
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_kill_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ int surely_empty;
+
+ do {
+ spin_lock_irq(&anchor->lock);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ /* make sure the URB isn't freed before we kill it */
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_kill_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
+
+ spin_unlock_irq(&anchor->lock);
+ cpu_relax();
+ } while (!surely_empty);
+}
+EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
+
+
+/**
+ * usb_poison_anchored_urbs - cease all traffic from an anchor
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be poisoned starting
+ * from the back of the queue. Newly added URBs will also be
+ * poisoned
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_poison_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ int surely_empty;
+
+ do {
+ spin_lock_irq(&anchor->lock);
+ anchor->poisoned = 1;
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ /* make sure the URB isn't freed before we kill it */
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_poison_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
+
+ spin_unlock_irq(&anchor->lock);
+ cpu_relax();
+ } while (!surely_empty);
+}
+EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
+
+/**
+ * usb_unpoison_anchored_urbs - let an anchor be used successfully again
+ * @anchor: anchor the requests are bound to
+ *
+ * Reverses the effect of usb_poison_anchored_urbs
+ * the anchor can be used normally after it returns
+ */
+void usb_unpoison_anchored_urbs(struct usb_anchor *anchor)
+{
+ unsigned long flags;
+ struct urb *lazarus;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) {
+ usb_unpoison_urb(lazarus);
+ }
+ anchor->poisoned = 0;
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
+/**
+ * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be unlinked starting
+ * from the back of the queue. This function is asynchronous.
+ * The unlinking is just triggered. It may happen after this
+ * function has returned.
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+
+ while ((victim = usb_get_from_anchor(anchor)) != NULL) {
+ usb_unlink_urb(victim);
+ usb_put_urb(victim);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
+
+/**
+ * usb_anchor_suspend_wakeups
+ * @anchor: the anchor you want to suspend wakeups on
+ *
+ * Call this to stop the last urb being unanchored from waking up any
+ * usb_wait_anchor_empty_timeout waiters. This is used in the hcd urb give-
+ * back path to delay waking up until after the completion handler has run.
+ */
+void usb_anchor_suspend_wakeups(struct usb_anchor *anchor)
+{
+ if (anchor)
+ atomic_inc(&anchor->suspend_wakeups);
+}
+EXPORT_SYMBOL_GPL(usb_anchor_suspend_wakeups);
+
+/**
+ * usb_anchor_resume_wakeups
+ * @anchor: the anchor you want to resume wakeups on
+ *
+ * Allow usb_wait_anchor_empty_timeout waiters to be woken up again, and
+ * wake up any current waiters if the anchor is empty.
+ */
+void usb_anchor_resume_wakeups(struct usb_anchor *anchor)
+{
+ if (!anchor)
+ return;
+
+ atomic_dec(&anchor->suspend_wakeups);
+ if (usb_anchor_check_wakeup(anchor))
+ wake_up(&anchor->wait);
+}
+EXPORT_SYMBOL_GPL(usb_anchor_resume_wakeups);
+
+/**
+ * usb_wait_anchor_empty_timeout - wait for an anchor to be unused
+ * @anchor: the anchor you want to become unused
+ * @timeout: how long you are willing to wait in milliseconds
+ *
+ * Call this is you want to be sure all an anchor's
+ * URBs have finished
+ *
+ * Return: Non-zero if the anchor became unused. Zero on timeout.
+ */
+int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+ unsigned int timeout)
+{
+ return wait_event_timeout(anchor->wait,
+ usb_anchor_check_wakeup(anchor),
+ msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
+
+/**
+ * usb_get_from_anchor - get an anchor's oldest urb
+ * @anchor: the anchor whose urb you want
+ *
+ * This will take the oldest urb from an anchor,
+ * unanchor and return it
+ *
+ * Return: The oldest urb from @anchor, or %NULL if @anchor has no
+ * urbs associated with it.
+ */
+struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ if (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.next, struct urb,
+ anchor_list);
+ usb_get_urb(victim);
+ __usb_unanchor_urb(victim, anchor);
+ } else {
+ victim = NULL;
+ }
+ spin_unlock_irqrestore(&anchor->lock, flags);
+
+ return victim;
+}
+
+EXPORT_SYMBOL_GPL(usb_get_from_anchor);
+
+/**
+ * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs
+ * @anchor: the anchor whose urbs you want to unanchor
+ *
+ * use this to get rid of all an anchor's urbs
+ */
+void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+ int surely_empty;
+
+ do {
+ spin_lock_irqsave(&anchor->lock, flags);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev,
+ struct urb, anchor_list);
+ __usb_unanchor_urb(victim, anchor);
+ }
+ surely_empty = usb_anchor_check_wakeup(anchor);
+
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ cpu_relax();
+ } while (!surely_empty);
+}
+
+EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
+
+/**
+ * usb_anchor_empty - is an anchor empty
+ * @anchor: the anchor you want to query
+ *
+ * Return: 1 if the anchor has no urbs associated with it.
+ */
+int usb_anchor_empty(struct usb_anchor *anchor)
+{
+ return list_empty(&anchor->urb_list);
+}
+
+EXPORT_SYMBOL_GPL(usb_anchor_empty);
+
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
new file mode 100644
index 000000000..e221861b3
--- /dev/null
+++ b/drivers/usb/core/usb-acpi.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB-ACPI glue code
+ *
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <linux/usb/hcd.h>
+
+#include "hub.h"
+
+/**
+ * usb_acpi_power_manageable - check whether usb port has
+ * acpi power resource.
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ *
+ * Return true if the port has acpi power resource and false if no.
+ */
+bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
+{
+ acpi_handle port_handle;
+ int port1 = index + 1;
+
+ port_handle = usb_get_hub_port_acpi_handle(hdev,
+ port1);
+ if (port_handle)
+ return acpi_bus_power_manageable(port_handle);
+ else
+ return false;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
+
+/**
+ * usb_acpi_set_power_state - control usb port's power via acpi power
+ * resource
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ * @enable: power state expected to be set
+ *
+ * Notice to use usb_acpi_power_manageable() to check whether the usb port
+ * has acpi power resource before invoking this function.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
+ struct usb_port *port_dev;
+ acpi_handle port_handle;
+ unsigned char state;
+ int port1 = index + 1;
+ int error = -EINVAL;
+
+ if (!hub)
+ return -ENODEV;
+ port_dev = hub->ports[port1 - 1];
+
+ port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1);
+ if (!port_handle)
+ return error;
+
+ if (enable)
+ state = ACPI_STATE_D0;
+ else
+ state = ACPI_STATE_D3_COLD;
+
+ error = acpi_bus_set_power(port_handle, state);
+ if (!error)
+ dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable);
+ else
+ dev_dbg(&port_dev->dev, "acpi: power failed to be set\n");
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
+
+static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
+ struct acpi_pld_info *pld)
+{
+ enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *upc;
+ acpi_status status;
+
+ /*
+ * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port
+ * is user visible and _UPC indicates whether it is connectable. If
+ * the port was visible and connectable, it could be freely connected
+ * and disconnected with USB devices. If no visible and connectable,
+ * a usb device is directly hard-wired to the port. If no visible and
+ * no connectable, the port would be not used.
+ */
+ status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
+ upc = buffer.pointer;
+ if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
+ || upc->package.count != 4) {
+ goto out;
+ }
+
+ if (upc->package.elements[0].integer.value)
+ if (pld->user_visible)
+ connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;
+ else
+ connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED;
+ else if (!pld->user_visible)
+ connect_type = USB_PORT_NOT_USED;
+out:
+ kfree(upc);
+ return connect_type;
+}
+
+
+/*
+ * Private to usb-acpi, all the core needs to know is that
+ * port_dev->location is non-zero when it has been set by the firmware.
+ */
+#define USB_ACPI_LOCATION_VALID (1 << 31)
+
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+ int raw)
+{
+ struct acpi_device *adev;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ if (acpi_device_adr(adev) == raw)
+ return adev;
+ }
+
+ return acpi_find_child_device(parent, raw, false);
+}
+
+static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+{
+ struct usb_device *udev;
+ struct acpi_device *adev;
+ acpi_handle *parent_handle;
+
+ /*
+ * In the ACPI DSDT table, only usb root hub and usb ports are
+ * acpi device nodes. The hierarchy like following.
+ * Device (EHC1)
+ * Device (HUBN)
+ * Device (PR01)
+ * Device (PR11)
+ * Device (PR12)
+ * Device (PR13)
+ * ...
+ * So all binding process is divided into two parts. binding
+ * root hub and usb ports.
+ */
+ if (is_usb_device(dev)) {
+ udev = to_usb_device(dev);
+ if (udev->parent)
+ return NULL;
+
+ /* root hub is only child (_ADR=0) under its parent, the HC */
+ adev = ACPI_COMPANION(dev->parent);
+ return acpi_find_child_device(adev, 0, false);
+ } else if (is_usb_port(dev)) {
+ struct usb_port *port_dev = to_usb_port(dev);
+ int port1 = port_dev->portnum;
+ struct acpi_pld_info *pld;
+ acpi_handle *handle;
+ acpi_status status;
+
+ /* Get the struct usb_device point of port's hub */
+ udev = to_usb_device(dev->parent->parent);
+
+ /*
+ * The root hub ports' parent is the root hub. The non-root-hub
+ * ports' parent is the parent hub port which the hub is
+ * connected to.
+ */
+ if (!udev->parent) {
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int raw;
+
+ raw = usb_hcd_find_raw_port_number(hcd, port1);
+
+ adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+ raw);
+
+ if (!adev)
+ return NULL;
+ } else {
+ parent_handle =
+ usb_get_hub_port_acpi_handle(udev->parent,
+ udev->portnum);
+ if (!parent_handle)
+ return NULL;
+
+ acpi_bus_get_device(parent_handle, &adev);
+
+ adev = usb_acpi_find_port(adev, port1);
+
+ if (!adev)
+ return NULL;
+ }
+ handle = adev->handle;
+ status = acpi_get_physical_device_location(handle, &pld);
+ if (ACPI_FAILURE(status) || !pld)
+ return adev;
+
+ port_dev->location = USB_ACPI_LOCATION_VALID
+ | pld->group_token << 8 | pld->group_position;
+ port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
+ ACPI_FREE(pld);
+
+ return adev;
+ }
+
+ return NULL;
+}
+
+static bool usb_acpi_bus_match(struct device *dev)
+{
+ return is_usb_device(dev) || is_usb_port(dev);
+}
+
+static struct acpi_bus_type usb_acpi_bus = {
+ .name = "USB",
+ .match = usb_acpi_bus_match,
+ .find_companion = usb_acpi_find_companion,
+};
+
+int usb_acpi_register(void)
+{
+ return register_acpi_bus_type(&usb_acpi_bus);
+}
+
+void usb_acpi_unregister(void)
+{
+ unregister_acpi_bus_type(&usb_acpi_bus);
+}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
new file mode 100644
index 000000000..4ebfbd737
--- /dev/null
+++ b/drivers/usb/core/usb.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/core/usb.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2004
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ * Released under the GPLv2 only.
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+ * generic USB things that the real drivers can use..
+ *
+ * Think of this as a "USB library" rather than anything else.
+ * It should be considered a slave, with no callbacks. Callbacks
+ * are evil.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h> /* for in_interrupt() */
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/usb/of.h>
+
+#include <asm/io.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include "usb.h"
+
+
+const char *usbcore_name = "usbcore";
+
+static bool nousb; /* Disable USB when built into kernel image */
+
+module_param(nousb, bool, 0444);
+
+/*
+ * for external read access to <nousb>
+ */
+int usb_disabled(void)
+{
+ return nousb;
+}
+EXPORT_SYMBOL_GPL(usb_disabled);
+
+#ifdef CONFIG_PM
+static int usb_autosuspend_delay = 2; /* Default delay value,
+ * in seconds */
+module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
+MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
+
+#else
+#define usb_autosuspend_delay 0
+#endif
+
+static bool match_endpoint(struct usb_endpoint_descriptor *epd,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ switch (usb_endpoint_type(epd)) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (usb_endpoint_dir_in(epd)) {
+ if (bulk_in && !*bulk_in) {
+ *bulk_in = epd;
+ break;
+ }
+ } else {
+ if (bulk_out && !*bulk_out) {
+ *bulk_out = epd;
+ break;
+ }
+ }
+
+ return false;
+ case USB_ENDPOINT_XFER_INT:
+ if (usb_endpoint_dir_in(epd)) {
+ if (int_in && !*int_in) {
+ *int_in = epd;
+ break;
+ }
+ } else {
+ if (int_out && !*int_out) {
+ *int_out = epd;
+ break;
+ }
+ }
+
+ return false;
+ default:
+ return false;
+ }
+
+ return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
+ (!int_in || *int_in) && (!int_out || *int_out);
+}
+
+/**
+ * usb_find_common_endpoints() -- look up common endpoint descriptors
+ * @alt: alternate setting to search
+ * @bulk_in: pointer to descriptor pointer, or NULL
+ * @bulk_out: pointer to descriptor pointer, or NULL
+ * @int_in: pointer to descriptor pointer, or NULL
+ * @int_out: pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the first bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ struct usb_endpoint_descriptor *epd;
+ int i;
+
+ if (bulk_in)
+ *bulk_in = NULL;
+ if (bulk_out)
+ *bulk_out = NULL;
+ if (int_in)
+ *int_in = NULL;
+ if (int_out)
+ *int_out = NULL;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
+ epd = &alt->endpoint[i].desc;
+
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+ return 0;
+ }
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
+
+/**
+ * usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
+ * @alt: alternate setting to search
+ * @bulk_in: pointer to descriptor pointer, or NULL
+ * @bulk_out: pointer to descriptor pointer, or NULL
+ * @int_in: pointer to descriptor pointer, or NULL
+ * @int_out: pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the last bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ struct usb_endpoint_descriptor *epd;
+ int i;
+
+ if (bulk_in)
+ *bulk_in = NULL;
+ if (bulk_out)
+ *bulk_out = NULL;
+ if (int_in)
+ *int_in = NULL;
+ if (int_out)
+ *int_out = NULL;
+
+ for (i = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
+ epd = &alt->endpoint[i].desc;
+
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+ return 0;
+ }
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
+
+/**
+ * usb_find_alt_setting() - Given a configuration, find the alternate setting
+ * for the given interface.
+ * @config: the configuration to search (not necessarily the current config).
+ * @iface_num: interface number to search in
+ * @alt_num: alternate interface setting number to search for.
+ *
+ * Search the configuration's interface cache for the given alt setting.
+ *
+ * Return: The alternate setting, if found. %NULL otherwise.
+ */
+struct usb_host_interface *usb_find_alt_setting(
+ struct usb_host_config *config,
+ unsigned int iface_num,
+ unsigned int alt_num)
+{
+ 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) {
+ intf_cache = config->intf_cache[i];
+ break;
+ }
+ }
+ if (!intf_cache)
+ return NULL;
+ for (i = 0; i < intf_cache->num_altsetting; i++)
+ if (intf_cache->altsetting[i].desc.bAlternateSetting == alt_num)
+ return &intf_cache->altsetting[i];
+
+ printk(KERN_DEBUG "Did not find alt setting %u for intf %u, "
+ "config %u\n", alt_num, iface_num,
+ config->desc.bConfigurationValue);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_find_alt_setting);
+
+/**
+ * usb_ifnum_to_if - get the interface object with a given interface number
+ * @dev: the device whose current configuration is considered
+ * @ifnum: the desired interface
+ *
+ * This walks the device descriptor for the currently active configuration
+ * to find the interface object with the particular interface number.
+ *
+ * Note that configuration descriptors are not required to assign interface
+ * numbers sequentially, so that it would be incorrect to assume that
+ * the first interface in that descriptor corresponds to interface zero.
+ * This routine helps device drivers avoid such mistakes.
+ * However, you should make sure that you do the right thing with any
+ * alternate settings available for this interfaces.
+ *
+ * Don't call this function unless you are bound to one of the interfaces
+ * on this device or you have locked the device!
+ *
+ * Return: A pointer to the interface that has @ifnum as interface number,
+ * if found. %NULL otherwise.
+ */
+struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+ unsigned ifnum)
+{
+ struct usb_host_config *config = dev->actconfig;
+ int i;
+
+ if (!config)
+ return NULL;
+ for (i = 0; i < config->desc.bNumInterfaces; i++)
+ if (config->interface[i]->altsetting[0]
+ .desc.bInterfaceNumber == ifnum)
+ return config->interface[i];
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
+
+/**
+ * usb_altnum_to_altsetting - get the altsetting structure with a given alternate setting number.
+ * @intf: the interface containing the altsetting in question
+ * @altnum: the desired alternate setting number
+ *
+ * This searches the altsetting array of the specified interface for
+ * an entry with the correct bAlternateSetting value.
+ *
+ * Note that altsettings need not be stored sequentially by number, so
+ * it would be incorrect to assume that the first altsetting entry in
+ * the array corresponds to altsetting zero. This routine helps device
+ * drivers avoid such mistakes.
+ *
+ * Don't call this function unless you are bound to the intf interface
+ * or you have locked the device!
+ *
+ * Return: A pointer to the entry of the altsetting array of @intf that
+ * has @altnum as the alternate setting number. %NULL if not found.
+ */
+struct usb_host_interface *usb_altnum_to_altsetting(
+ const struct usb_interface *intf,
+ unsigned int altnum)
+{
+ int i;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ if (intf->altsetting[i].desc.bAlternateSetting == altnum)
+ return &intf->altsetting[i];
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);
+
+struct find_interface_arg {
+ int minor;
+ struct device_driver *drv;
+};
+
+static int __find_interface(struct device *dev, void *data)
+{
+ struct find_interface_arg *arg = data;
+ struct usb_interface *intf;
+
+ if (!is_usb_interface(dev))
+ return 0;
+
+ if (dev->driver != arg->drv)
+ return 0;
+ intf = to_usb_interface(dev);
+ return intf->minor == arg->minor;
+}
+
+/**
+ * usb_find_interface - find usb_interface pointer for driver and device
+ * @drv: the driver whose current configuration is considered
+ * @minor: the minor number of the desired device
+ *
+ * This walks the bus device list and returns a pointer to the interface
+ * with the matching minor and driver. Note, this only works for devices
+ * that share the USB major number.
+ *
+ * Return: A pointer to the interface with the matching major and @minor.
+ */
+struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
+{
+ struct find_interface_arg argb;
+ struct device *dev;
+
+ argb.minor = minor;
+ argb.drv = &drv->drvwrap.driver;
+
+ dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface);
+
+ /* Drop reference count from bus_find_device */
+ put_device(dev);
+
+ return dev ? to_usb_interface(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(usb_find_interface);
+
+struct each_dev_arg {
+ void *data;
+ int (*fn)(struct usb_device *, void *);
+};
+
+static int __each_dev(struct device *dev, void *data)
+{
+ struct each_dev_arg *arg = (struct each_dev_arg *)data;
+
+ /* There are struct usb_interface on the same bus, filter them out */
+ if (!is_usb_device(dev))
+ return 0;
+
+ return arg->fn(to_usb_device(dev), arg->data);
+}
+
+/**
+ * usb_for_each_dev - iterate over all USB devices in the system
+ * @data: data pointer that will be handed to the callback function
+ * @fn: callback function to be called for each USB device
+ *
+ * Iterate over all USB devices and call @fn for each, passing it @data. If it
+ * returns anything other than 0, we break the iteration prematurely and return
+ * that value.
+ */
+int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *))
+{
+ struct each_dev_arg arg = {data, fn};
+
+ return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev);
+}
+EXPORT_SYMBOL_GPL(usb_for_each_dev);
+
+/**
+ * usb_release_dev - free a usb device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this usb device are
+ * done.
+ */
+static void usb_release_dev(struct device *dev)
+{
+ struct usb_device *udev;
+ struct usb_hcd *hcd;
+
+ udev = to_usb_device(dev);
+ hcd = bus_to_hcd(udev->bus);
+
+ usb_destroy_configuration(udev);
+ usb_release_bos_descriptor(udev);
+ of_node_put(dev->of_node);
+ usb_put_hcd(hcd);
+ kfree(udev->product);
+ kfree(udev->manufacturer);
+ kfree(udev->serial);
+ kfree(udev);
+}
+
+static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_device *usb_dev;
+
+ usb_dev = to_usb_device(dev);
+
+ if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum))
+ return -ENOMEM;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* USB device Power-Management thunks.
+ * There's no need to distinguish here between quiescing a USB device
+ * and powering it down; the generic_suspend() routine takes care of
+ * it by skipping the usb_port_suspend() call for a quiesce. And for
+ * USB interfaces there's no difference at all.
+ */
+
+static int usb_dev_prepare(struct device *dev)
+{
+ return 0; /* Implement eventually? */
+}
+
+static void usb_dev_complete(struct device *dev)
+{
+ /* Currently used only for rebinding interfaces */
+ usb_resume_complete(dev);
+}
+
+static int usb_dev_suspend(struct device *dev)
+{
+ return usb_suspend(dev, PMSG_SUSPEND);
+}
+
+static int usb_dev_resume(struct device *dev)
+{
+ return usb_resume(dev, PMSG_RESUME);
+}
+
+static int usb_dev_freeze(struct device *dev)
+{
+ return usb_suspend(dev, PMSG_FREEZE);
+}
+
+static int usb_dev_thaw(struct device *dev)
+{
+ return usb_resume(dev, PMSG_THAW);
+}
+
+static int usb_dev_poweroff(struct device *dev)
+{
+ return usb_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int usb_dev_restore(struct device *dev)
+{
+ return usb_resume(dev, PMSG_RESTORE);
+}
+
+static const struct dev_pm_ops usb_device_pm_ops = {
+ .prepare = usb_dev_prepare,
+ .complete = usb_dev_complete,
+ .suspend = usb_dev_suspend,
+ .resume = usb_dev_resume,
+ .freeze = usb_dev_freeze,
+ .thaw = usb_dev_thaw,
+ .poweroff = usb_dev_poweroff,
+ .restore = usb_dev_restore,
+ .runtime_suspend = usb_runtime_suspend,
+ .runtime_resume = usb_runtime_resume,
+ .runtime_idle = usb_runtime_idle,
+};
+
+#endif /* CONFIG_PM */
+
+
+static char *usb_devnode(struct device *dev,
+ umode_t *mode, kuid_t *uid, kgid_t *gid)
+{
+ struct usb_device *usb_dev;
+
+ usb_dev = to_usb_device(dev);
+ return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum);
+}
+
+struct device_type usb_device_type = {
+ .name = "usb_device",
+ .release = usb_release_dev,
+ .uevent = usb_dev_uevent,
+ .devnode = usb_devnode,
+#ifdef CONFIG_PM
+ .pm = &usb_device_pm_ops,
+#endif
+};
+
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = bus_to_hcd(bus);
+ return hcd->wireless;
+}
+
+
+/**
+ * usb_alloc_dev - usb device constructor (usbcore-internal)
+ * @parent: hub to which device is connected; null to allocate a root hub
+ * @bus: bus used to access the device
+ * @port1: one-based index of port; ignored for root hubs
+ * Context: !in_interrupt()
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ *
+ * This call may not be used in a non-sleeping context.
+ *
+ * Return: On success, a pointer to the allocated usb device. %NULL on
+ * failure.
+ */
+struct usb_device *usb_alloc_dev(struct usb_device *parent,
+ struct usb_bus *bus, unsigned port1)
+{
+ struct usb_device *dev;
+ struct usb_hcd *usb_hcd = bus_to_hcd(bus);
+ unsigned root_hub = 0;
+ unsigned raw_port = port1;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ if (!usb_get_hcd(usb_hcd)) {
+ kfree(dev);
+ return NULL;
+ }
+ /* Root hubs aren't true devices, so don't allocate HCD resources */
+ if (usb_hcd->driver->alloc_dev && parent &&
+ !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
+ usb_put_hcd(bus_to_hcd(bus));
+ kfree(dev);
+ return NULL;
+ }
+
+ device_initialize(&dev->dev);
+ dev->dev.bus = &usb_bus_type;
+ dev->dev.type = &usb_device_type;
+ dev->dev.groups = usb_device_groups;
+ /*
+ * Fake a dma_mask/offset for the USB device:
+ * We cannot really use the dma-mapping API (dma_alloc_* and
+ * dma_map_*) for USB devices but instead need to use
+ * usb_alloc_coherent and pass data in 'urb's, but some subsystems
+ * manually look into the mask/offset pair to determine whether
+ * they need bounce buffers.
+ * Note: calling dma_set_mask() on a USB device would set the
+ * mask for the entire HCD, so don't do that.
+ */
+ dev->dev.dma_mask = bus->sysdev->dma_mask;
+ dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset;
+ set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
+ dev->state = USB_STATE_ATTACHED;
+ dev->lpm_disable_count = 1;
+ atomic_set(&dev->urbnum, 0);
+
+ INIT_LIST_HEAD(&dev->ep0.urb_list);
+ dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
+ dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
+ /* ep0 maxpacket comes later, from device descriptor */
+ usb_enable_endpoint(dev, &dev->ep0, false);
+ dev->can_submit = 1;
+
+ /* Save readable and stable topology id, distinguishing devices
+ * by location for diagnostics, tools, driver model, etc. The
+ * string is a path along hub ports, from the root. Each device's
+ * dev->devpath will be stable until USB is re-cabled, and hubs
+ * are often labeled with these port numbers. The name isn't
+ * as stable: bus->busnum changes easily from modprobe order,
+ * cardbus or pci hotplugging, and so on.
+ */
+ if (unlikely(!parent)) {
+ dev->devpath[0] = '0';
+ dev->route = 0;
+
+ dev->dev.parent = bus->controller;
+ device_set_of_node_from_dev(&dev->dev, bus->sysdev);
+ dev_set_name(&dev->dev, "usb%d", bus->busnum);
+ root_hub = 1;
+ } else {
+ /* match any labeling on the hubs; it's one-based */
+ if (parent->devpath[0] == '0') {
+ snprintf(dev->devpath, sizeof dev->devpath,
+ "%d", port1);
+ /* Root ports are not counted in route string */
+ dev->route = 0;
+ } else {
+ snprintf(dev->devpath, sizeof dev->devpath,
+ "%s.%d", parent->devpath, port1);
+ /* Route string assumes hubs have less than 16 ports */
+ if (port1 < 15)
+ dev->route = parent->route +
+ (port1 << ((parent->level - 1)*4));
+ else
+ dev->route = parent->route +
+ (15 << ((parent->level - 1)*4));
+ }
+
+ dev->dev.parent = &parent->dev;
+ dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
+
+ if (!parent->parent) {
+ /* device under root hub's port */
+ raw_port = usb_hcd_find_raw_port_number(usb_hcd,
+ port1);
+ }
+ dev->dev.of_node = usb_of_get_device_node(parent, raw_port);
+
+ /* hub driver sets up TT records */
+ }
+
+ dev->portnum = port1;
+ dev->bus = bus;
+ dev->parent = parent;
+ INIT_LIST_HEAD(&dev->filelist);
+
+#ifdef CONFIG_PM
+ pm_runtime_set_autosuspend_delay(&dev->dev,
+ usb_autosuspend_delay * 1000);
+ dev->connect_time = jiffies;
+ dev->active_duration = -jiffies;
+#endif
+ if (root_hub) /* Root hub always ok [and always wired] */
+ dev->authorized = 1;
+ else {
+ dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd);
+ dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0;
+ }
+ return dev;
+}
+EXPORT_SYMBOL_GPL(usb_alloc_dev);
+
+/**
+ * usb_get_dev - increments the reference count of the usb device structure
+ * @dev: the device being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for USB interfaces should normally record such references in
+ * their probe() methods, when they bind to an interface, and release
+ * them by calling usb_put_dev(), in their disconnect() methods.
+ *
+ * Return: A pointer to the device with the incremented reference counter.
+ */
+struct usb_device *usb_get_dev(struct usb_device *dev)
+{
+ if (dev)
+ get_device(&dev->dev);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(usb_get_dev);
+
+/**
+ * usb_put_dev - release a use of the usb device structure
+ * @dev: device that's been disconnected
+ *
+ * Must be called when a user of a device is finished with it. When the last
+ * user of the device calls this function, the memory of the device is freed.
+ */
+void usb_put_dev(struct usb_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(usb_put_dev);
+
+/**
+ * usb_get_intf - increments the reference count of the usb interface structure
+ * @intf: the interface being referenced
+ *
+ * Each live reference to a interface must be refcounted.
+ *
+ * Drivers for USB interfaces should normally record such references in
+ * their probe() methods, when they bind to an interface, and release
+ * them by calling usb_put_intf(), in their disconnect() methods.
+ *
+ * Return: A pointer to the interface with the incremented reference counter.
+ */
+struct usb_interface *usb_get_intf(struct usb_interface *intf)
+{
+ if (intf)
+ get_device(&intf->dev);
+ return intf;
+}
+EXPORT_SYMBOL_GPL(usb_get_intf);
+
+/**
+ * usb_put_intf - release a use of the usb interface structure
+ * @intf: interface that's been decremented
+ *
+ * Must be called when a user of an interface is finished with it. When the
+ * last user of the interface calls this function, the memory of the interface
+ * is freed.
+ */
+void usb_put_intf(struct usb_interface *intf)
+{
+ if (intf)
+ put_device(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_put_intf);
+
+/* USB device locking
+ *
+ * USB devices and interfaces are locked using the semaphore in their
+ * embedded struct device. The hub driver guarantees that whenever a
+ * device is connected or disconnected, drivers are called with the
+ * USB device locked as well as their particular interface.
+ *
+ * Complications arise when several devices are to be locked at the same
+ * time. Only hub-aware drivers that are part of usbcore ever have to
+ * do this; nobody else needs to worry about it. The rule for locking
+ * is simple:
+ *
+ * When locking both a device and its parent, always lock the
+ * the parent first.
+ */
+
+/**
+ * usb_lock_device_for_reset - cautiously acquire the lock for a usb device structure
+ * @udev: device that's being locked
+ * @iface: interface bound to the driver making the request (optional)
+ *
+ * Attempts to acquire the device lock, but fails if the device is
+ * NOTATTACHED or SUSPENDED, or if iface is specified and the interface
+ * is neither BINDING nor BOUND. Rather than sleeping to wait for the
+ * lock, the routine polls repeatedly. This is to prevent deadlock with
+ * disconnect; in some drivers (such as usb-storage) the disconnect()
+ * or suspend() method will block waiting for a device reset to complete.
+ *
+ * Return: A negative error code for failure, otherwise 0.
+ */
+int usb_lock_device_for_reset(struct usb_device *udev,
+ const struct usb_interface *iface)
+{
+ unsigned long jiffies_expire = jiffies + HZ;
+
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (iface && (iface->condition == USB_INTERFACE_UNBINDING ||
+ iface->condition == USB_INTERFACE_UNBOUND))
+ return -EINTR;
+
+ while (!usb_trylock_device(udev)) {
+
+ /* If we can't acquire the lock after waiting one second,
+ * we're probably deadlocked */
+ if (time_after(jiffies, jiffies_expire))
+ return -EBUSY;
+
+ msleep(15);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (iface && (iface->condition == USB_INTERFACE_UNBINDING ||
+ iface->condition == USB_INTERFACE_UNBOUND))
+ return -EINTR;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
+
+/**
+ * usb_get_current_frame_number - return current bus frame number
+ * @dev: the device whose bus is being queried
+ *
+ * Return: The current frame number for the USB host controller used
+ * with the given USB device. This can be used when scheduling
+ * isochronous requests.
+ *
+ * Note: Different kinds of host controller have different "scheduling
+ * horizons". While one type might support scheduling only 32 frames
+ * into the future, others could support scheduling up to 1024 frames
+ * into the future.
+ *
+ */
+int usb_get_current_frame_number(struct usb_device *dev)
+{
+ return usb_hcd_get_frame_number(dev);
+}
+EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
+
+/*-------------------------------------------------------------------*/
+/*
+ * __usb_get_extra_descriptor() finds a descriptor of specific type in the
+ * extra field of the interface and endpoint descriptor structs.
+ */
+
+int __usb_get_extra_descriptor(char *buffer, unsigned size,
+ unsigned char type, void **ptr, size_t minsize)
+{
+ struct usb_descriptor_header *header;
+
+ while (size >= sizeof(struct usb_descriptor_header)) {
+ header = (struct usb_descriptor_header *)buffer;
+
+ if (header->bLength < 2 || header->bLength > size) {
+ printk(KERN_ERR
+ "%s: bogus descriptor, type %d length %d\n",
+ usbcore_name,
+ header->bDescriptorType,
+ header->bLength);
+ return -1;
+ }
+
+ if (header->bDescriptorType == type && header->bLength >= minsize) {
+ *ptr = header;
+ return 0;
+ }
+
+ buffer += header->bLength;
+ size -= header->bLength;
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
+
+/**
+ * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
+ * @dev: device the buffer will be used with
+ * @size: requested buffer size
+ * @mem_flags: affect whether allocation may block
+ * @dma: used to return DMA address of buffer
+ *
+ * Return: Either null (indicating no buffer could be allocated), or the
+ * cpu-space pointer to a buffer that may be used to perform DMA to the
+ * specified device. Such cpu-space buffers are returned along with the DMA
+ * address (through the pointer provided).
+ *
+ * Note:
+ * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
+ * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
+ * hardware during URB completion/resubmit. The implementation varies between
+ * platforms, depending on details of how DMA will work to this device.
+ * Using these buffers also eliminates cacheline sharing problems on
+ * architectures where CPU caches are not DMA-coherent. On systems without
+ * bus-snooping caches, these buffers are uncached.
+ *
+ * When the buffer is no longer used, free it with usb_free_coherent().
+ */
+void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags,
+ dma_addr_t *dma)
+{
+ if (!dev || !dev->bus)
+ return NULL;
+ return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
+}
+EXPORT_SYMBOL_GPL(usb_alloc_coherent);
+
+/**
+ * usb_free_coherent - free memory allocated with usb_alloc_coherent()
+ * @dev: device the buffer was used with
+ * @size: requested buffer size
+ * @addr: CPU address of buffer
+ * @dma: DMA address of buffer
+ *
+ * This reclaims an I/O buffer, letting it be reused. The memory must have
+ * been allocated using usb_alloc_coherent(), and the parameters must match
+ * those provided in that allocation request.
+ */
+void usb_free_coherent(struct usb_device *dev, size_t size, void *addr,
+ dma_addr_t dma)
+{
+ if (!dev || !dev->bus)
+ return;
+ if (!addr)
+ return;
+ hcd_buffer_free(dev->bus, size, addr, dma);
+}
+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
+ */
+static int usb_bus_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (dev->type == &usb_device_type)
+ (void) usb_create_sysfs_dev_files(to_usb_device(dev));
+ else if (dev->type == &usb_if_device_type)
+ usb_create_sysfs_intf_files(to_usb_interface(dev));
+ break;
+
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (dev->type == &usb_device_type)
+ usb_remove_sysfs_dev_files(to_usb_device(dev));
+ else if (dev->type == &usb_if_device_type)
+ usb_remove_sysfs_intf_files(to_usb_interface(dev));
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block usb_bus_nb = {
+ .notifier_call = usb_bus_notify,
+};
+
+struct dentry *usb_debug_root;
+EXPORT_SYMBOL_GPL(usb_debug_root);
+
+static void usb_debugfs_init(void)
+{
+ usb_debug_root = debugfs_create_dir("usb", NULL);
+ debugfs_create_file("devices", 0444, usb_debug_root, NULL,
+ &usbfs_devices_fops);
+}
+
+static void usb_debugfs_cleanup(void)
+{
+ debugfs_remove_recursive(usb_debug_root);
+}
+
+/*
+ * Init
+ */
+static int __init usb_init(void)
+{
+ int retval;
+ if (usb_disabled()) {
+ pr_info("%s: USB support disabled\n", usbcore_name);
+ return 0;
+ }
+ usb_init_pool_max();
+
+ usb_debugfs_init();
+
+ usb_acpi_register();
+ retval = bus_register(&usb_bus_type);
+ if (retval)
+ goto bus_register_failed;
+ retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
+ if (retval)
+ goto bus_notifier_failed;
+ retval = usb_major_init();
+ if (retval)
+ goto major_init_failed;
+ retval = usb_register(&usbfs_driver);
+ if (retval)
+ goto driver_register_failed;
+ retval = usb_devio_init();
+ if (retval)
+ goto usb_devio_init_failed;
+ retval = usb_hub_init();
+ if (retval)
+ goto hub_init_failed;
+ retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
+ if (!retval)
+ goto out;
+
+ usb_hub_cleanup();
+hub_init_failed:
+ usb_devio_cleanup();
+usb_devio_init_failed:
+ usb_deregister(&usbfs_driver);
+driver_register_failed:
+ usb_major_cleanup();
+major_init_failed:
+ bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
+bus_notifier_failed:
+ bus_unregister(&usb_bus_type);
+bus_register_failed:
+ usb_acpi_unregister();
+ usb_debugfs_cleanup();
+out:
+ return retval;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit usb_exit(void)
+{
+ /* This will matter if shutdown/reboot does exitcalls. */
+ if (usb_disabled())
+ return;
+
+ usb_release_quirk_list();
+ usb_deregister_device_driver(&usb_generic_driver);
+ usb_major_cleanup();
+ usb_deregister(&usbfs_driver);
+ usb_devio_cleanup();
+ usb_hub_cleanup();
+ bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
+ bus_unregister(&usb_bus_type);
+ usb_acpi_unregister();
+ usb_debugfs_cleanup();
+ idr_destroy(&usb_bus_idr);
+}
+
+subsys_initcall(usb_init);
+module_exit(usb_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
new file mode 100644
index 000000000..c0df5a468
--- /dev/null
+++ b/drivers/usb/core/usb.h
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/pm.h>
+#include <linux/acpi.h>
+
+struct usb_hub_descriptor;
+struct usb_dev_state;
+
+/* Functions local to drivers/usb/core/ */
+
+extern int usb_create_sysfs_dev_files(struct usb_device *dev);
+extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
+extern void usb_create_sysfs_intf_files(struct usb_interface *intf);
+extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
+extern int usb_create_ep_devs(struct device *parent,
+ struct usb_host_endpoint *endpoint,
+ struct usb_device *udev);
+extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint);
+
+extern void usb_enable_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *ep, bool reset_toggle);
+extern void usb_enable_interface(struct usb_device *dev,
+ struct usb_interface *intf, bool reset_toggles);
+extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr,
+ bool reset_hardware);
+extern void usb_disable_interface(struct usb_device *dev,
+ struct usb_interface *intf, bool reset_hardware);
+extern void usb_release_interface_cache(struct kref *ref);
+extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device(struct usb_device *);
+extern int usb_authorize_device(struct usb_device *);
+extern void usb_deauthorize_interface(struct usb_interface *);
+extern void usb_authorize_interface(struct usb_interface *);
+extern void usb_detect_quirks(struct usb_device *udev);
+extern void usb_detect_interface_quirks(struct usb_device *udev);
+extern void usb_release_quirk_list(void);
+extern bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+ struct usb_host_interface *intf,
+ struct usb_endpoint_descriptor *epd);
+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);
+extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
+
+static inline unsigned usb_get_max_power(struct usb_device *udev,
+ struct usb_host_config *c)
+{
+ /* SuperSpeed power is in 8 mA units; others are in 2 mA units */
+ unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
+
+ return c->desc.bMaxPower * mul;
+}
+
+extern void usb_kick_hub_wq(struct usb_device *dev);
+extern int usb_match_one_id_intf(struct usb_device *dev,
+ struct usb_host_interface *intf,
+ const struct usb_device_id *id);
+extern int usb_match_device(struct usb_device *dev,
+ const struct usb_device_id *id);
+extern void usb_forced_unbind_intf(struct usb_interface *intf);
+extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
+
+extern void usb_hub_release_all_ports(struct usb_device *hdev,
+ struct usb_dev_state *owner);
+extern bool usb_device_is_owned(struct usb_device *udev);
+
+extern int usb_hub_init(void);
+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
+
+extern int usb_suspend(struct device *dev, pm_message_t msg);
+extern int usb_resume(struct device *dev, pm_message_t msg);
+extern int usb_resume_complete(struct device *dev);
+
+extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
+extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
+
+extern void usb_autosuspend_device(struct usb_device *udev);
+extern int usb_autoresume_device(struct usb_device *udev);
+extern int usb_remote_wakeup(struct usb_device *dev);
+extern int usb_runtime_suspend(struct device *dev);
+extern int usb_runtime_resume(struct device *dev);
+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);
+
+#else
+
+static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ return 0;
+}
+
+static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
+{
+ return 0;
+}
+
+#define usb_autosuspend_device(udev) do {} while (0)
+static inline int usb_autoresume_device(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+
+#endif
+
+extern struct bus_type usb_bus_type;
+extern struct mutex usb_port_peer_mutex;
+extern struct device_type usb_device_type;
+extern struct device_type usb_if_device_type;
+extern struct device_type usb_ep_device_type;
+extern struct device_type usb_port_device_type;
+extern struct usb_device_driver usb_generic_driver;
+
+static inline int is_usb_device(const struct device *dev)
+{
+ return dev->type == &usb_device_type;
+}
+
+static inline int is_usb_interface(const struct device *dev)
+{
+ return dev->type == &usb_if_device_type;
+}
+
+static inline int is_usb_endpoint(const struct device *dev)
+{
+ return dev->type == &usb_ep_device_type;
+}
+
+static inline int is_usb_port(const struct device *dev)
+{
+ return dev->type == &usb_port_device_type;
+}
+
+/* Do the same for device drivers and interface drivers. */
+
+static inline int is_usb_device_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct usbdrv_wrap, driver)->
+ for_devices;
+}
+
+/* for labeling diagnostics */
+extern const char *usbcore_name;
+
+/* sysfs stuff */
+extern const struct attribute_group *usb_device_groups[];
+extern const struct attribute_group *usb_interface_groups[];
+
+/* usbfs stuff */
+extern struct mutex usbfs_mutex;
+extern struct usb_driver usbfs_driver;
+extern const struct file_operations usbfs_devices_fops;
+extern const struct file_operations usbdev_file_operations;
+extern void usbfs_conn_disc_event(void);
+
+extern int usb_devio_init(void);
+extern void usb_devio_cleanup(void);
+
+/*
+ * Firmware specific cookie identifying a port's location. '0' == no location
+ * data available
+ */
+typedef u32 usb_port_location_t;
+
+/* internal notify stuff */
+extern void usb_notify_add_device(struct usb_device *udev);
+extern void usb_notify_remove_device(struct usb_device *udev);
+extern void usb_notify_add_bus(struct usb_bus *ubus);
+extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
+ struct usb_hub_descriptor *desc);
+
+#ifdef CONFIG_ACPI
+extern int usb_acpi_register(void);
+extern void usb_acpi_unregister(void);
+extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+ int port1);
+#else
+static inline int usb_acpi_register(void) { return 0; };
+static inline void usb_acpi_unregister(void) { };
+#endif