summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/usb/core
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/Kconfig150
-rw-r--r--drivers/usb/core/Makefile14
-rw-r--r--drivers/usb/core/buffer.c151
-rw-r--r--drivers/usb/core/config.c860
-rw-r--r--drivers/usb/core/devices.c688
-rw-r--r--drivers/usb/core/devio.c2181
-rw-r--r--drivers/usb/core/driver.c1741
-rw-r--r--drivers/usb/core/endpoint.c218
-rw-r--r--drivers/usb/core/file.c253
-rw-r--r--drivers/usb/core/generic.c247
-rw-r--r--drivers/usb/core/hcd-pci.c602
-rw-r--r--drivers/usb/core/hcd.c2656
-rw-r--r--drivers/usb/core/hub.c4284
-rw-r--r--drivers/usb/core/inode.c748
-rw-r--r--drivers/usb/core/message.c1952
-rw-r--r--drivers/usb/core/notify.c69
-rw-r--r--drivers/usb/core/otg_whitelist.h112
-rw-r--r--drivers/usb/core/quirks.c199
-rw-r--r--drivers/usb/core/sysfs.c947
-rw-r--r--drivers/usb/core/urb.c888
-rw-r--r--drivers/usb/core/usb.c1131
-rw-r--r--drivers/usb/core/usb.h158
22 files changed, 20249 insertions, 0 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
new file mode 100644
index 00000000..18d02e32
--- /dev/null
+++ b/drivers/usb/core/Kconfig
@@ -0,0 +1,150 @@
+#
+# USB Core configuration
+#
+config USB_DEBUG
+ bool "USB verbose debug messages"
+ depends on USB
+ help
+ Say Y here if you want the USB core & hub drivers to produce a bunch
+ of debug messages to the system log. Select this if you are having a
+ problem with USB support and want to see more of what is going on.
+
+config USB_ANNOUNCE_NEW_DEVICES
+ bool "USB announce new devices"
+ depends on USB
+ default N
+ 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"
+ depends on USB
+
+config USB_DEVICEFS
+ bool "USB device filesystem (DEPRECATED)"
+ depends on USB
+ ---help---
+ If you say Y here (and to "/proc file system support" in the "File
+ systems" section, above), you will get a file /proc/bus/usb/devices
+ which lists the devices currently connected to your USB bus or
+ busses, and for every connected device a file named
+ "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
+ device number; the latter files can be used by user space programs
+ to talk directly to the device. These files are "virtual", meaning
+ they are generated on the fly and not stored on the hard drive.
+
+ You may need to mount the usbfs file system to see the files, use
+ mount -t usbfs none /proc/bus/usb
+
+ For the format of the various /proc/bus/usb/ files, please read
+ <file:Documentation/usb/proc_usb_info.txt>.
+
+ Modern Linux systems do not use this.
+
+ Usbfs entries are files and not character devices; usbfs can't
+ handle Access Control Lists (ACL) which are the default way to
+ grant access to USB devices for untrusted users of a desktop
+ system.
+
+ The usbfs functionality is replaced by real device-nodes managed by
+ udev. These nodes lived in /dev/bus/usb and are used by libusb.
+
+config USB_DEVICE_CLASS
+ bool "USB device class-devices (DEPRECATED)"
+ depends on USB
+ default y
+ ---help---
+ Userspace access to USB devices is granted by device-nodes exported
+ directly from the usbdev in sysfs. Old versions of the driver
+ core and udev needed additional class devices to export device nodes.
+
+ These additional devices are difficult to handle in userspace, if
+ information about USB interfaces must be available. One device
+ contains the device node, the other device contains the interface
+ data. Both devices are at the same level in sysfs (siblings) and one
+ can't access the other. The device node created directly by the
+ usb device is the parent device of the interface and therefore
+ easily accessible from the interface event.
+
+ This option provides backward compatibility for libusb device
+ nodes (lsusb) when usbfs is not used, and the following udev rule
+ doesn't exist:
+ SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
+ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
+
+config USB_DYNAMIC_MINORS
+ bool "Dynamic USB minor allocation"
+ depends on USB
+ 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_SUSPEND
+ bool "USB runtime power management (autosuspend) and wakeup"
+ depends on USB && PM_RUNTIME
+ help
+ If you say Y here, you can use driver calls or the sysfs
+ "power/control" file to enable or disable autosuspend for
+ individual USB peripherals (see
+ Documentation/usb/power-management.txt for more details).
+
+ Also, USB "remote wakeup" signaling is supported, whereby some
+ USB devices (like keyboards and network adapters) can wake up
+ their parent hub. That wakeup cascades up the USB tree, and
+ could wake the system from states like suspend-to-RAM.
+
+ If you are unsure about this, say N here.
+
+config USB_OTG
+ bool "OTG support"
+ depends on USB && EXPERIMENTAL
+ depends on USB_SUSPEND
+ 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 Targeted Peripherals List"
+ depends on USB_OTG || EXPERT
+ default y if USB_OTG
+ default n if EXPERT
+ 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 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.
+
+ Otherwise, peripherals not listed there will only generate a
+ warning and enumeration will continue. That's more like what
+ normal Linux-USB hosts do (other than the warning), and is
+ convenient for many stages of product development.
+
+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.
+
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
new file mode 100644
index 00000000..507a4e1b
--- /dev/null
+++ b/drivers/usb/core/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for USB Core files and filesystem
+#
+
+ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+
+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-$(CONFIG_PCI) += hcd-pci.o
+usbcore-$(CONFIG_USB_DEVICEFS) += inode.o
+
+obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
new file mode 100644
index 00000000..b0585e62
--- /dev/null
+++ b/drivers/usb/core/buffer.c
@@ -0,0 +1,151 @@
+/*
+ * 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, regardles of bus type.
+ */
+
+#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 const size_t pool_max[HCD_BUFFER_POOLS] = {
+ /* platforms without dma-friendly caches might need to
+ * prevent cacheline sharing...
+ */
+ 32,
+ 128,
+ 512,
+ PAGE_SIZE / 2
+ /* bigger --> allocate pages */
+};
+
+
+/* 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, or returns a negative
+ * errno value on error.
+ *
+ * Call hcd_buffer_destroy() to clean up after using those pools.
+ */
+int hcd_buffer_create(struct usb_hcd *hcd)
+{
+ char name[16];
+ int i, size;
+
+ if (!hcd->self.controller->dma_mask &&
+ !(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.controller,
+ 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;
+
+ 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;
+
+ /* some USB hosts just use PIO */
+ if (!bus->controller->dma_mask &&
+ !(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.controller, 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 (!bus->controller->dma_mask &&
+ !(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.controller, size, addr, dma);
+}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
new file mode 100644
index 00000000..f4bdd0ce
--- /dev/null
+++ b/drivers/usb/core/config.c
@@ -0,0 +1,860 @@
+#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/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <asm/byteorder.h>
+#include "usb.h"
+
+
+#define USB_MAXALTSETTING 128 /* Hard limit */
+#define USB_MAXENDPOINTS 30 /* 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_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;
+ }
+
+ 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) &&
+ desc->bmAttributes > 2) {
+ dev_warn(ddev, "Isoc endpoint has Mult of %d in "
+ "config %d interface %d altsetting %d ep %d: "
+ "setting to 3\n", desc->bmAttributes + 1,
+ cfgno, inum, asnum, ep->desc.bEndpointAddress);
+ ep->ss_ep_comp.bmAttributes = 2;
+ }
+
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
+ 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);
+ }
+}
+
+static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
+ int asnum, struct usb_host_interface *ifp, int num_ep,
+ unsigned char *buffer, int size)
+{
+ unsigned char *buffer0 = buffer;
+ struct usb_endpoint_descriptor *d;
+ struct usb_host_endpoint *endpoint;
+ int n, i, j, retval;
+
+ 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;
+
+ 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 32 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:
+ 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 a
+ * 32 ms default value otherwise. */
+ n = fls(d->bInterval*8);
+ if (n == 0)
+ n = 9; /* 32 ms = 2^(9-1) uframes */
+ j = 16;
+ 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 = 32;
+ break;
+ }
+ } else if (usb_endpoint_xfer_isoc(d)) {
+ i = 1;
+ j = 16;
+ switch (to_usb_device(ddev)->speed) {
+ case USB_SPEED_HIGH:
+ n = 9; /* 32 ms = 2^(9-1) uframes */
+ break;
+ default: /* USB_SPEED_FULL */
+ n = 6; /* 32 ms = 2^(6-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);
+ }
+
+ /*
+ * 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)) {
+ unsigned maxp;
+
+ maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
+ 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, 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);
+ if (config->desc.bDescriptorType != USB_DT_CONFIG ||
+ config->desc.bLength < USB_DT_CONFIG_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;
+
+ nintf = nintf_orig = config->desc.bNumInterfaces;
+ if (nintf > USB_MAXINTERFACES) {
+ dev_warn(ddev, "config %d has too many interfaces: %d, "
+ "using maximum allowed: %d\n",
+ 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) {
+ 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] =
+ (struct usb_interface_assoc_descriptor
+ *)header;
+ 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)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ * whole thing. A non-authorized USB device has no
+ * configurations.
+ */
+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;
+ if (dev->authorized == 0) /* Not really an error */
+ goto out_not_authorized;
+ 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);
+ 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;
+ }
+ 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);
+out_not_authorized:
+ 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;
+ }
+}
+
+/* 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;
+ unsigned char *buffer;
+ int length, total_len, num, i;
+ 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) {
+ dev_err(ddev, "unable to get BOS descriptor\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;
+ }
+ total_len -= length;
+
+ for (i = 0; i < num; i++) {
+ buffer += length;
+ cap = (struct usb_dev_cap_header *)buffer;
+ length = cap->bLength;
+
+ if (total_len < length)
+ break;
+ total_len -= length;
+
+ if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+ dev_warn(ddev, "descriptor type invalid, skip\n");
+ continue;
+ }
+
+ switch (cap->bDevCapabilityType) {
+ 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 CONTAINER_ID_TYPE:
+ dev->bos->ss_id =
+ (struct usb_ss_container_id_descriptor *)buffer;
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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 00000000..d9569658
--- /dev/null
+++ b/drivers/usb/core/devices.c
@@ -0,0 +1,688 @@
+/*
+ * 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)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *************************************************************
+ *
+ * <mountpoint>/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /proc/bus/usb/devices/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 /proc/bus/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";
+
+
+/*
+ * Need access to the driver and USB bus lists.
+ * extern struct list_head usb_bus_list;
+ * However, these will come from functions that return ptrs to each of them.
+ */
+
+/*
+ * 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) {
+ switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
+ case 1 << 11:
+ bandwidth = 2; break;
+ case 2 << 11:
+ bandwidth = 3; break;
+ }
+ }
+
+ /* 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) & 0x07ff) *
+ 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)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, format_config,
+ /* mark active/actual/current cfg. */
+ active ? '*' : ' ',
+ desc->bNumInterfaces,
+ desc->bConfigurationValue,
+ desc->bmAttributes,
+ desc->bMaxPower * 2);
+ 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);
+ 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;
+
+ /* 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;
+ 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. */
+ for (chix = 0; chix < usbdev->maxchild; chix++) {
+ struct usb_device *childdev = usbdev->children[chix];
+
+ if (childdev) {
+ usb_lock_device(childdev);
+ ret = usb_device_dump(buffer, nbytes, skip_bytes,
+ file_offset, childdev, bus,
+ level + 1, chix, ++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;
+
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+
+ mutex_lock(&usb_bus_list_lock);
+ /* print devices for all busses */
+ list_for_each_entry(bus, &usb_bus_list, bus_list) {
+ /* recurse through all children of the root hub */
+ if (!bus->root_hub)
+ 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_list_lock);
+ return ret;
+ }
+ total_written += ret;
+ }
+ mutex_unlock(&usb_bus_list_lock);
+ return total_written;
+}
+
+/* Kernel lock for "lastev" protection */
+static unsigned int 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 POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
+{
+ loff_t ret;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ break;
+ case 1:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ break;
+ case 2:
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ return ret;
+}
+
+const struct file_operations usbfs_devices_fops = {
+ .llseek = usb_device_lseek,
+ .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 00000000..4e577728
--- /dev/null
+++ b/drivers/usb/core/devio.c
@@ -0,0 +1,2181 @@
+/*****************************************************************************/
+
+/*
+ * devio.c -- User space communication with USB devices.
+ *
+ * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This file implements the usbfs/x/y files, where
+ * x is the bus number and y the device number.
+ *
+ * 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/slab.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <linux/module.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 <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/moduleparam.h>
+
+#include "usb.h"
+
+#define USB_MAXBUS 64
+#define USB_DEVICE_MAX USB_MAXBUS * 128
+
+/* Mutual exclusion for removal, open, and release */
+DEFINE_MUTEX(usbfs_mutex);
+
+struct 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;
+ 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 secid;
+ u32 disabled_bulk_eps;
+};
+
+struct async {
+ struct list_head asynclist;
+ struct 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;
+ unsigned int mem_usage;
+ int status;
+ u32 secid;
+ 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");
+
+#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 unsigned usbfs_memory_mb = 16;
+module_param(usbfs_memory_mb, uint, 0644);
+MODULE_PARM_DESC(usbfs_memory_mb,
+ "maximum MB allowed for usbfs buffers (0 = no limit)");
+
+/* Hard limit, necessary to avoid aithmetic overflow */
+#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
+
+static atomic_t usbfs_memory_usage; /* Total memory currently allocated */
+
+/* Check whether it's okay to allocate more memory for a transfer */
+static int usbfs_increase_memory_usage(unsigned amount)
+{
+ unsigned lim;
+
+ /*
+ * Convert usbfs_memory_mb to bytes, avoiding overflows.
+ * 0 means use the hard limit (effectively unlimited).
+ */
+ lim = ACCESS_ONCE(usbfs_memory_mb);
+ if (lim == 0 || lim > (USBFS_XFER_MAX >> 20))
+ lim = USBFS_XFER_MAX;
+ else
+ lim <<= 20;
+
+ atomic_add(amount, &usbfs_memory_usage);
+ if (atomic_read(&usbfs_memory_usage) <= lim)
+ return 0;
+ atomic_sub(amount, &usbfs_memory_usage);
+ return -ENOMEM;
+}
+
+/* Memory for a transfer is being deallocated */
+static void usbfs_decrease_memory_usage(unsigned amount)
+{
+ atomic_sub(amount, &usbfs_memory_usage);
+}
+
+static int connected(struct dev_state *ps)
+{
+ return (!list_empty(&ps->list) &&
+ ps->dev->state != USB_STATE_NOTATTACHED);
+}
+
+static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
+{
+ loff_t ret;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ break;
+ case 1:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ break;
+ case 2:
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ return ret;
+}
+
+static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ struct 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)
+{
+ put_pid(as->pid);
+ if (as->cred)
+ put_cred(as->cred);
+ kfree(as->urb->transfer_buffer);
+ kfree(as->urb->setup_packet);
+ usb_free_urb(as->urb);
+ usbfs_decrease_memory_usage(as->mem_usage);
+ kfree(as);
+}
+
+static void async_newpending(struct async *as)
+{
+ struct 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 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 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 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 %p, ep%d %s-%s, "
+ "length %u\n",
+ userurb, ep, t, d, length);
+ else
+ dev_info(&udev->dev, "userurb %p, 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);
+ }
+
+ if (data && data_len > 0) {
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+ data, data_len, 1);
+ }
+}
+
+#define AS_CONTINUATION 1
+#define AS_UNLINK 2
+
+static void cancel_bulk_urbs(struct 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 dev_state *ps = as->ps;
+ struct siginfo sinfo;
+ struct pid *pid = NULL;
+ u32 secid = 0;
+ const struct cred *cred = NULL;
+ int signr;
+
+ spin_lock(&ps->lock);
+ list_move_tail(&as->asynclist, &ps->async_completed);
+ as->status = urb->status;
+ signr = as->signr;
+ if (signr) {
+ 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);
+ secid = as->secid;
+ }
+ snoop(&urb->dev->dev, "urb complete\n");
+ snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
+ as->status, COMPLETE,
+ ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
+ NULL : urb->transfer_buffer, urb->actual_length);
+ if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
+ as->status != -ENOENT)
+ cancel_bulk_urbs(ps, as->bulk_addr);
+ spin_unlock(&ps->lock);
+
+ if (signr) {
+ kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);
+ put_pid(pid);
+ put_cred(cred);
+ }
+
+ wake_up(&ps->wait);
+}
+
+static void destroy_async(struct 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 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 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 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 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;
+
+ intf = usb_ifnum_to_if(dev, ifnum);
+ if (!intf)
+ err = -ENOENT;
+ else
+ err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
+ if (err == 0)
+ set_bit(ifnum, &ps->ifclaimed);
+ return err;
+}
+
+static int releaseintf(struct 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)) {
+ usb_driver_release_interface(&usbfs_driver, intf);
+ err = 0;
+ }
+ return err;
+}
+
+static int checkintf(struct 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 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, where wIndex is (interface << 8 | altsetting)
+ * instead of just interface
+ */
+ 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)
+ index >>= 8;
+ }
+
+ index &= 0xff;
+ switch (requesttype & USB_RECIP_MASK) {
+ case USB_RECIP_ENDPOINT:
+ ret = findintfep(ps->dev, index);
+ if (ret >= 0)
+ ret = checkintf(ps, ret);
+ break;
+
+ case USB_RECIP_INTERFACE:
+ ret = checkintf(ps, index);
+ break;
+ }
+ 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 container_of(dev, struct usb_device, dev);
+}
+
+/*
+ * file operations
+ */
+static int usbdev_open(struct inode *inode, struct file *file)
+{
+ struct usb_device *dev = NULL;
+ struct dev_state *ps;
+ int ret;
+
+ ret = -ENOMEM;
+ ps = kmalloc(sizeof(struct 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);
+
+#ifdef CONFIG_USB_DEVICEFS
+ /* procfs file */
+ if (!dev) {
+ dev = inode->i_private;
+ if (dev && dev->usbfs_dentry &&
+ dev->usbfs_dentry->d_inode == inode)
+ usb_get_dev(dev);
+ else
+ dev = NULL;
+ }
+#endif
+ 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;
+ spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->list);
+ INIT_LIST_HEAD(&ps->async_pending);
+ INIT_LIST_HEAD(&ps->async_completed);
+ init_waitqueue_head(&ps->wait);
+ ps->discsignr = 0;
+ ps->disc_pid = get_pid(task_pid(current));
+ ps->cred = get_current_cred();
+ ps->disccontext = NULL;
+ ps->ifclaimed = 0;
+ security_task_getsecid(current, &ps->secid);
+ 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 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 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,
+ __le16_to_cpup(&ctrl.wValue),
+ __le16_to_cpup(&ctrl.wIndex),
+ __le16_to_cpup(&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 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 >= USBFS_XFER_MAX)
+ return -EINVAL;
+ ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
+ if (ret)
+ return ret;
+ if (!(tbuf = kmalloc(len1, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ tmo = bulk.timeout;
+ if (bulk.ep & 0x80) {
+ if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
+ 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 int proc_resetep(struct 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;
+ usb_reset_endpoint(ps->dev, ep);
+ return 0;
+}
+
+static int proc_clearhalt(struct 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;
+ 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 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 {
+ strncpy(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 dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_connectinfo ci = {
+ .devnum = ps->dev->devnum,
+ .slow = ps->dev->speed == USB_SPEED_LOW
+ };
+
+ if (copy_to_user(arg, &ci, sizeof(ci)))
+ return -EFAULT;
+ return 0;
+}
+
+static int proc_resetdevice(struct dev_state *ps)
+{
+ return usb_reset_device(ps->dev);
+}
+
+static int proc_setintf(struct dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_setinterface setintf;
+ int ret;
+
+ if (copy_from_user(&setintf, arg, sizeof(setintf)))
+ return -EFAULT;
+ if ((ret = checkintf(ps, setintf.interface)))
+ return ret;
+ return usb_set_interface(ps->dev, setintf.interface,
+ setintf.altsetting);
+}
+
+static int proc_setconfig(struct 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 int proc_do_submiturb(struct 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 ret, ifnum = -1;
+ int is_in;
+
+ if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
+ USBDEVFS_URB_SHORT_NOT_OK |
+ USBDEVFS_URB_BULK_CONTINUATION |
+ USBDEVFS_URB_NO_FSBR |
+ USBDEVFS_URB_ZERO_PACKET |
+ USBDEVFS_URB_NO_INTERRUPT))
+ 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;
+ }
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+ is_in = 1;
+ ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ } else {
+ is_in = 0;
+ ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ }
+ if (!ep)
+ return -ENOENT;
+
+ u = 0;
+ switch(uurb->type) {
+ case USBDEVFS_URB_TYPE_CONTROL:
+ if (!usb_endpoint_xfer_control(&ep->desc))
+ return -EINVAL;
+ /* min 8 byte setup packet */
+ 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->number_of_packets = 0;
+ 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;
+ }
+ 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:
+ 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;
+ }
+ uurb->number_of_packets = 0;
+ break;
+
+ case USBDEVFS_URB_TYPE_INTERRUPT:
+ if (!usb_endpoint_xfer_int(&ep->desc))
+ return -EINVAL;
+ interrupt_urb:
+ uurb->number_of_packets = 0;
+ 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;
+ isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
+ uurb->number_of_packets;
+ if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ for (totlen = u = 0; u < uurb->number_of_packets; u++) {
+ /* arbitrary limit,
+ * sufficient for USB 2.0 high-bandwidth iso */
+ if (isopkt[u].length > 8192) {
+ 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 >= USBFS_XFER_MAX) {
+ ret = -EINVAL;
+ goto error;
+ }
+ if (uurb->buffer_length > 0 &&
+ !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ as = alloc_async(uurb->number_of_packets);
+ if (!as) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
+ ret = usbfs_increase_memory_usage(u);
+ if (ret)
+ goto error;
+ as->mem_usage = u;
+
+ if (uurb->buffer_length > 0) {
+ as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
+ GFP_KERNEL);
+ if (!as->urb->transfer_buffer) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ /* 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.
+ */
+ if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
+ 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 (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
+ u |= URB_SHORT_NOT_OK;
+ if (uurb->flags & USBDEVFS_URB_NO_FSBR)
+ u |= URB_NO_FSBR;
+ if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
+ u |= URB_ZERO_PACKET;
+ if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
+ u |= URB_NO_INTERRUPT;
+ as->urb->transfer_flags = u;
+
+ as->urb->transfer_buffer_length = uurb->buffer_length;
+ as->urb->setup_packet = (unsigned char *)dr;
+ dr = NULL;
+ as->urb->start_frame = uurb->start_frame;
+ as->urb->number_of_packets = uurb->number_of_packets;
+ if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+ ps->dev->speed == USB_SPEED_HIGH)
+ 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 < uurb->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 (is_in && uurb->buffer_length > 0)
+ as->userbuffer = uurb->buffer;
+ else
+ as->userbuffer = NULL;
+ as->signr = uurb->signr;
+ as->ifnum = ifnum;
+ as->pid = get_pid(task_pid(current));
+ as->cred = get_current_cred();
+ security_task_getsecid(current, &as->secid);
+ if (!is_in && uurb->buffer_length > 0) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+ uurb->buffer_length)) {
+ ret = -EFAULT;
+ goto error;
+ }
+ }
+ snoop_urb(ps->dev, as->userurb, as->urb->pipe,
+ as->urb->transfer_buffer_length, 0, SUBMIT,
+ is_in ? NULL : as->urb->transfer_buffer,
+ uurb->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 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 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 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;
+
+ if (as->userbuffer && urb->actual_length) {
+ if (urb->number_of_packets > 0) /* Isochronous */
+ i = urb->transfer_buffer_length;
+ else /* Non-Isoc */
+ i = urb->actual_length;
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
+ 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 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)
+ 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 dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+ if (as) {
+ int retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
+ if (signal_pending(current))
+ return -EINTR;
+ return -EIO;
+}
+
+static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
+{
+ int retval;
+ struct async *as;
+
+ as = async_getcompleted(ps);
+ retval = -EAGAIN;
+ if (as) {
+ retval = processcompl(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static int proc_control_compat(struct 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 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 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)
+{
+ __u32 uptr;
+ if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) ||
+ __get_user(kurb->type, &uurb->type) ||
+ __get_user(kurb->endpoint, &uurb->endpoint) ||
+ __get_user(kurb->status, &uurb->status) ||
+ __get_user(kurb->flags, &uurb->flags) ||
+ __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+ __get_user(kurb->actual_length, &uurb->actual_length) ||
+ __get_user(kurb->start_frame, &uurb->start_frame) ||
+ __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+ __get_user(kurb->error_count, &uurb->error_count) ||
+ __get_user(kurb->signr, &uurb->signr))
+ return -EFAULT;
+
+ if (__get_user(uptr, &uurb->buffer))
+ return -EFAULT;
+ kurb->buffer = compat_ptr(uptr);
+ if (__get_user(uptr, &uurb->usercontext))
+ return -EFAULT;
+ kurb->usercontext = compat_ptr(uptr);
+
+ return 0;
+}
+
+static int proc_submiturb_compat(struct 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;
+
+ if (as->userbuffer && urb->actual_length)
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer,
+ urb->actual_length))
+ 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 dev_state *ps, void __user *arg)
+{
+ struct async *as = reap_as(ps);
+ if (as) {
+ int retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ return retval;
+ }
+ if (signal_pending(current))
+ return -EINTR;
+ return -EIO;
+}
+
+static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
+{
+ int retval;
+ struct async *as;
+
+ retval = -EAGAIN;
+ as = async_getcompleted(ps);
+ if (as) {
+ retval = processcompl_compat(as, (void __user * __user *)arg);
+ free_async(as);
+ }
+ return retval;
+}
+
+
+#endif
+
+static int proc_disconnectsignal(struct 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 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 dev_state *ps, void __user *arg)
+{
+ unsigned int ifnum;
+ int ret;
+
+ if (get_user(ifnum, (unsigned int __user *)arg))
+ return -EFAULT;
+ if ((ret = releaseintf(ps, ifnum)) < 0)
+ return ret;
+ destroy_async_on_interface (ps, ifnum);
+ return 0;
+}
+
+static int proc_ioctl(struct 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;
+
+ /* alloc buffer */
+ if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
+ if ((buf = kmalloc(size, GFP_KERNEL)) == 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 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 dev_state *ps, compat_uptr_t arg)
+{
+ struct usbdevfs_ioctl32 __user *uioc;
+ struct usbdevfs_ioctl ctrl;
+ u32 udata;
+
+ uioc = compat_ptr((long)arg);
+ if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) ||
+ __get_user(ctrl.ifno, &uioc->ifno) ||
+ __get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
+ __get_user(udata, &uioc->data))
+ return -EFAULT;
+ ctrl.data = compat_ptr(udata);
+
+ return proc_ioctl(ps, &ctrl);
+}
+#endif
+
+static int proc_claim_port(struct 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 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);
+}
+
+/*
+ * 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 dev_state *ps = file->private_data;
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct usb_device *dev = ps->dev;
+ int ret = -ENOTTY;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EPERM;
+
+ usb_lock_device(dev);
+ 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;
+ break;
+
+ case USBDEVFS_BULK:
+ snoop(&dev->dev, "%s: BULK\n", __func__);
+ ret = proc_bulk(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_RESETEP:
+ snoop(&dev->dev, "%s: RESETEP\n", __func__);
+ ret = proc_resetep(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ break;
+
+ case USBDEVFS_REAPURB32:
+ snoop(&dev->dev, "%s: REAPURB32\n", __func__);
+ ret = proc_reapurb_compat(ps, p);
+ break;
+
+ case USBDEVFS_REAPURBNDELAY32:
+ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
+ ret = proc_reapurbnonblock_compat(ps, p);
+ 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\n", __func__);
+ ret = proc_unlinkurb(ps, p);
+ break;
+
+ case USBDEVFS_REAPURB:
+ snoop(&dev->dev, "%s: REAPURB\n", __func__);
+ ret = proc_reapurb(ps, p);
+ break;
+
+ case USBDEVFS_REAPURBNDELAY:
+ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
+ ret = proc_reapurbnonblock(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;
+ }
+ usb_unlock_device(dev);
+ if (ret >= 0)
+ inode->i_atime = CURRENT_TIME;
+ 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 unsigned int usbdev_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct dev_state *ps = file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &ps->wait, wait);
+ if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
+ mask |= POLLOUT | POLLWRNORM;
+ if (!connected(ps))
+ mask |= POLLERR | POLLHUP;
+ return mask;
+}
+
+const struct file_operations usbdev_file_operations = {
+ .owner = THIS_MODULE,
+ .llseek = usbdev_lseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+ .unlocked_ioctl = usbdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usbdev_compat_ioctl,
+#endif
+ .open = usbdev_open,
+ .release = usbdev_release,
+};
+
+static void usbdev_remove(struct usb_device *udev)
+{
+ struct dev_state *ps;
+ struct siginfo sinfo;
+
+ while (!list_empty(&udev->filelist)) {
+ ps = list_entry(udev->filelist.next, struct dev_state, list);
+ destroy_all_async(ps);
+ wake_up_all(&ps->wait);
+ list_del_init(&ps->list);
+ if (ps->discsignr) {
+ 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, ps->secid);
+ }
+ }
+}
+
+#ifdef CONFIG_USB_DEVICE_CLASS
+static struct class *usb_classdev_class;
+
+static int usb_classdev_add(struct usb_device *dev)
+{
+ struct device *cldev;
+
+ cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt,
+ NULL, "usbdev%d.%d", dev->bus->busnum,
+ dev->devnum);
+ if (IS_ERR(cldev))
+ return PTR_ERR(cldev);
+ dev->usb_classdev = cldev;
+ return 0;
+}
+
+static void usb_classdev_remove(struct usb_device *dev)
+{
+ if (dev->usb_classdev)
+ device_unregister(dev->usb_classdev);
+}
+
+#else
+#define usb_classdev_add(dev) 0
+#define usb_classdev_remove(dev) do {} while (0)
+
+#endif
+
+static int usbdev_notify(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ switch (action) {
+ case USB_DEVICE_ADD:
+ if (usb_classdev_add(dev))
+ return NOTIFY_BAD;
+ break;
+ case USB_DEVICE_REMOVE:
+ usb_classdev_remove(dev);
+ 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;
+ }
+#ifdef CONFIG_USB_DEVICE_CLASS
+ usb_classdev_class = class_create(THIS_MODULE, "usb_device");
+ if (IS_ERR(usb_classdev_class)) {
+ printk(KERN_ERR "Unable to register usb_device class\n");
+ retval = PTR_ERR(usb_classdev_class);
+ cdev_del(&usb_device_cdev);
+ usb_classdev_class = NULL;
+ goto out;
+ }
+ /* devices of this class shadow the major:minor of their parent
+ * device, so clear ->dev_kobj to prevent adding duplicate entries
+ * to /sys/dev
+ */
+ usb_classdev_class->dev_kobj = NULL;
+#endif
+ 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);
+#ifdef CONFIG_USB_DEVICE_CLASS
+ class_destroy(usb_classdev_class);
+#endif
+ 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 00000000..b3df4e9a
--- /dev/null
+++ b/drivers/usb/core/driver.c
@@ -0,0 +1,1741 @@
+/*
+ * 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
+ *
+ * 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"
+
+
+#ifdef CONFIG_HOTPLUG
+
+/*
+ * 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,
+ struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_dynid *dynid;
+ u32 idVendor = 0;
+ u32 idProduct = 0;
+ unsigned int bInterfaceClass = 0;
+ int fields = 0;
+ int retval = 0;
+
+ fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
+ &bInterfaceClass);
+ 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 == 3) {
+ dynid->id.bInterfaceClass = (u8)bInterfaceClass;
+ dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+ }
+
+ spin_lock(&dynids->lock);
+ list_add_tail(&dynid->node, &dynids->list);
+ spin_unlock(&dynids->lock);
+
+ retval = driver_attach(driver);
+
+ if (retval)
+ return retval;
+ return count;
+}
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(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, driver, buf, count);
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+
+/**
+ * store_remove_id - remove a USB device ID from this driver
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Removes a dynamic usb device ID from this driver.
+ */
+static ssize_t
+store_remove_id(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 = 0;
+ u32 idProduct = 0;
+ int fields = 0;
+ int retval = 0;
+
+ 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);
+ retval = 0;
+ break;
+ }
+ }
+ spin_unlock(&usb_driver->dynids.lock);
+
+ if (retval)
+ return retval;
+ return count;
+}
+static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_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);
+}
+#else
+static inline int usb_create_newid_files(struct usb_driver *usb_drv)
+{
+ return 0;
+}
+
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
+{
+}
+
+static inline void usb_free_dynids(struct usb_driver *usb_drv)
+{
+}
+#endif
+
+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 suports 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;
+}
+
+/*
+ * Cancel any pending scheduled resets
+ *
+ * [see usb_queue_reset_device()]
+ *
+ * Called after unconfiguring / when releasing interfaces. See
+ * comments in __usb_queue_reset_device() regarding
+ * udev->reset_running.
+ */
+static void usb_cancel_queued_reset(struct usb_interface *iface)
+{
+ if (iface->reset_running == 0)
+ cancel_work_sync(&iface->reset_ws);
+}
+
+/* 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;
+
+ 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;
+ }
+
+ id = usb_match_id(intf, driver->id_table);
+ if (!id)
+ id = usb_match_dynamic_id(intf, driver);
+ 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);
+
+ /* 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;
+ usb_autosuspend_device(udev);
+ return error;
+
+ err:
+ intf->needs_remote_wakeup = 0;
+ intf->condition = USB_INTERFACE_UNBOUND;
+ usb_cancel_queued_reset(intf);
+
+ /* 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_device *udev;
+ int error, r;
+
+ intf->condition = USB_INTERFACE_UNBINDING;
+
+ /* Autoresume for set_interface call below */
+ udev = interface_to_usbdev(intf);
+ error = usb_autoresume_device(udev);
+
+ /* Terminate all URBs for this interface unless the driver
+ * supports "soft" unbinding.
+ */
+ if (!driver->soft_unbind)
+ usb_disable_interface(udev, intf, false);
+
+ driver->disconnect(intf);
+ usb_cancel_queued_reset(intf);
+
+ /* 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;
+
+ /* Unbound interfaces are always runtime-PM-disabled and -suspended */
+ if (driver->supports_autosuspend)
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+ /* Undo any residual pm_autopm_get_interface_* calls */
+ for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
+ usb_autopm_put_interface_no_suspend(intf);
+ atomic_set(&intf->pm_usage_cnt, 0);
+
+ 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.
+ */
+int usb_driver_claim_interface(struct usb_driver *driver,
+ struct usb_interface *iface, void *priv)
+{
+ struct device *dev = &iface->dev;
+ int retval = 0;
+
+ if (dev->driver)
+ return -EBUSY;
+
+ 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);
+
+ 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(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;
+
+ /* The interface class, subclass, and protocol 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)))
+ 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;
+
+ return 1;
+}
+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.
+ *
+ * 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;
+}
+
+#ifdef CONFIG_HOTPLUG
+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;
+ }
+
+#ifdef CONFIG_USB_DEVICEFS
+ /* If this is available, userspace programs can directly read
+ * all the device descriptors we don't tell them about. Or
+ * act as usermode drivers.
+ */
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum))
+ return -ENOMEM;
+#endif
+
+ /* 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;
+}
+
+#else
+
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_HOTPLUG */
+
+/**
+ * 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.
+ * Returns 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 = (char *) 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);
+ usbfs_update_special();
+ } 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);
+ usbfs_update_special();
+}
+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.
+ * Returns 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 = (char *) 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;
+
+ usbfs_update_special();
+
+ 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);
+
+ usbfs_update_special();
+}
+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 its pm_mutex
+ * and not @intf->dev.sem.
+ */
+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;
+}
+
+/* Delayed forced unbinding of a USB interface driver and scan
+ * for rebinding.
+ *
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ *
+ * Note: Rebinds will be skipped if a system sleep transition is in
+ * progress and the PM "complete" callback hasn't occurred yet.
+ */
+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)
+ dev_warn(&intf->dev, "rebind failed: %d\n", rc);
+ }
+}
+
+#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);
+ }
+ }
+ }
+}
+
+/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
+ * These interfaces have the needs_binding flag set by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_reset_resume_drivers_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);
+ }
+ }
+}
+
+static void do_rebind_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);
+ }
+ }
+}
+
+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_warn(&intf->dev, "no %s for driver %s?\n",
+ "reset_resume", 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. 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.
+ *
+ * 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.
+ */
+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 suspend failed, resume interfaces that did get suspended */
+ if (status != 0) {
+ 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.
+ */
+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 (!(&udev->dev))
+ printk("(NULL device *): %s: status %d\n", __func__, status);
+ else
+ printk("%s%s : %s: status %d\n",dev_driver_string(&udev->dev), dev_name(&udev->dev), __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);
+
+ 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);
+ return usb_suspend_both(udev, msg);
+}
+
+/* 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)
+ do_rebind_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_no_reset_resume_drivers_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;
+}
+
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+
+/**
+ * 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.
+ */
+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);
+ atomic_dec(&intf->pm_usage_cnt);
+ 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);
+ atomic_dec(&intf->pm_usage_cnt);
+ 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);
+ atomic_dec(&intf->pm_usage_cnt);
+ 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.
+ */
+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);
+ else
+ atomic_inc(&intf->pm_usage_cnt);
+ 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.
+ */
+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);
+ else
+ atomic_inc(&intf->pm_usage_cnt);
+ 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);
+ atomic_inc(&intf->pm_usage_cnt);
+ 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;
+
+ /* 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;
+ }
+ 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.
+ */
+ if (status != 0)
+ 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);
+ return 0;
+}
+
+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;
+}
+
+#endif /* CONFIG_USB_SUSPEND */
+
+struct bus_type usb_bus_type = {
+ .name = "usb",
+ .match = usb_device_match,
+ .uevent = usb_uevent,
+};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
new file mode 100644
index 00000000..db7fe50c
--- /dev/null
+++ b/drivers/usb/core/endpoint.c
@@ -0,0 +1,218 @@
+/*
+ * drivers/usb/core/endpoint.c
+ *
+ * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
+ * (C) Copyright 2002,2004 IBM Corp.
+ * (C) Copyright 2006 Novell Inc.
+ *
+ * Endpoint sysfs stuff
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/idr.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 device_type usb_ep_device_type = {
+ .name = "usb_endpoint",
+};
+
+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 show_ep_##field(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(field, S_IRUGO, show_ep_##field, NULL);
+
+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 show_ep_wMaxPacketSize(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) & 0x07ff);
+}
+static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
+
+static ssize_t show_ep_type(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(type, S_IRUGO, show_ep_type, NULL);
+
+static ssize_t show_ep_interval(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(interval, S_IRUGO, show_ep_interval, NULL);
+
+static ssize_t show_ep_direction(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(direction, S_IRUGO, show_ep_direction, NULL);
+
+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);
+}
+
+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;
+ ep_dev->dev.release = ep_device_release;
+ 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 00000000..d95760de
--- /dev/null
+++ b/drivers/usb/core/file.c
@@ -0,0 +1,253 @@
+/*
+ * 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
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/rwsem.h>
+#include <linux/slab.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 int usb_open(struct inode * inode, struct file * file)
+{
+ int minor = iminor(inode);
+ const struct file_operations *c;
+ int err = -ENODEV;
+ const struct file_operations *old_fops, *new_fops = NULL;
+
+ down_read(&minor_rwsem);
+ c = usb_minors[minor];
+
+ if (!c || !(new_fops = fops_get(c)))
+ goto done;
+
+ old_fops = file->f_op;
+ file->f_op = new_fops;
+ /* Curiouser and curiouser... NULL ->open() as "no device" ? */
+ if (file->f_op->open)
+ err = file->f_op->open(inode,file);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
+ }
+ fops_put(old_fops);
+ 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, "usb");
+ if (IS_ERR(usb_class->class)) {
+ result = IS_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)
+{
+ if (usb_class)
+ kref_put(&usb_class->kref, release_usb_class);
+}
+
+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.
+ *
+ * Returns -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];
+ char *temp;
+
+#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;
+
+ retval = init_usb_class();
+ if (retval)
+ return retval;
+
+ dev_dbg(&intf->dev, "looking for a minor, starting at %d", 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;
+ }
+ up_write(&minor_rwsem);
+ if (intf->minor < 0)
+ return -EXFULL;
+
+ /* create a usb class device for this usb interface */
+ snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
+ temp = strrchr(name, '/');
+ if (temp && (temp[1] != '\0'))
+ ++temp;
+ else
+ temp = name;
+ intf->usb_dev = device_create(usb_class->class, &intf->dev,
+ MKDEV(USB_MAJOR, minor), class_driver,
+ "%s", temp);
+ if (IS_ERR(intf->usb_dev)) {
+ down_write(&minor_rwsem);
+ usb_minors[minor] = NULL;
+ intf->minor = -1;
+ up_write(&minor_rwsem);
+ retval = PTR_ERR(intf->usb_dev);
+ }
+ 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;
+
+ dbg ("removing %d minor", intf->minor);
+
+ down_write(&minor_rwsem);
+ usb_minors[intf->minor] = NULL;
+ up_write(&minor_rwsem);
+
+ device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ 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 00000000..ec4bfde3
--- /dev/null
+++ b/drivers/usb/core/generic.c
@@ -0,0 +1,247 @@
+/*
+ * 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
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+extern int usb_power_insuf_skip=0; //read from uboot,default is false;
+
+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;
+
+ 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_power_insuf_skip)
+ if (c->desc.bMaxPower * 2 > 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;
+}
+
+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 (usb_device_is_owned(udev))
+ ; /* Don't configure if the device is owned */
+ else 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) {
+ 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 devices don't need to do anything for FREEZE or PRETHAW */
+ else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ 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 00000000..622b4a48
--- /dev/null
+++ b/drivers/usb/core/hcd-pci.c
@@ -0,0 +1,602 @@
+/*
+ * (C) Copyright David Brownell 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#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/pci-bridge.h>
+#include <asm/prom.h>
+#endif
+
+#include "usb.h"
+
+
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+
+#ifdef CONFIG_PM_SLEEP
+
+/* Coordinate handoffs between EHCI and companion controllers
+ * during system resume
+ */
+
+static DEFINE_MUTEX(companions_mutex);
+
+#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
+#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
+#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
+
+enum companion_action {
+ SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
+};
+
+static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
+ enum companion_action action)
+{
+ 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 pdev is OHCI or UHCI then we are looking for EHCI, and
+ * vice versa.
+ */
+ companion = NULL;
+ for_each_pci_dev(companion) {
+ if (companion->bus != pdev->bus ||
+ PCI_SLOT(companion->devfn) != slot)
+ continue;
+
+ companion_hcd = pci_get_drvdata(companion);
+ if (!companion_hcd)
+ continue;
+
+ /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
+ * the OHCI/UHCI companion bus structure.
+ * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
+ * in the OHCI/UHCI companion bus structure.
+ * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
+ * companion controllers have fully resumed.
+ */
+
+ if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
+ companion->class == CL_EHCI) {
+ /* action must be SET_HS_COMPANION */
+ dev_dbg(&companion->dev, "HS companion for %s\n",
+ dev_name(&pdev->dev));
+ hcd->self.hs_companion = &companion_hcd->self;
+
+ } else if (pdev->class == CL_EHCI &&
+ (companion->class == CL_OHCI ||
+ companion->class == CL_UHCI)) {
+ switch (action) {
+ case SET_HS_COMPANION:
+ dev_dbg(&pdev->dev, "HS companion for %s\n",
+ dev_name(&companion->dev));
+ companion_hcd->self.hs_companion = &hcd->self;
+ break;
+ case CLEAR_HS_COMPANION:
+ companion_hcd->self.hs_companion = NULL;
+ break;
+ case WAIT_FOR_COMPANIONS:
+ device_pm_wait_for_dev(&pdev->dev,
+ &companion->dev);
+ break;
+ }
+ }
+ }
+}
+
+static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ mutex_lock(&companions_mutex);
+ dev_set_drvdata(&pdev->dev, hcd);
+ companion_common(pdev, hcd, SET_HS_COMPANION);
+ mutex_unlock(&companions_mutex);
+}
+
+static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ mutex_lock(&companions_mutex);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
+ if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
+ hcd->self.hs_companion = NULL;
+
+ /* Otherwise search for companion buses and clear their pointers */
+ else
+ companion_common(pdev, hcd, CLEAR_HS_COMPANION);
+ mutex_unlock(&companions_mutex);
+}
+
+static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
+{
+ /* Only EHCI controllers need to wait.
+ * No locking is needed because a controller cannot be resumed
+ * while one of its companions is getting unbound.
+ */
+ if (pdev->class == CL_EHCI)
+ companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
+}
+
+#else /* !CONFIG_PM_SLEEP */
+
+static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
+static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
+static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
+
+#endif /* !CONFIG_PM_SLEEP */
+
+/*-------------------------------------------------------------------------*/
+
+/* 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().
+ */
+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;
+
+ 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;
+ dev->current_state = PCI_D0;
+
+ /* The xHCI driver supports MSI and MSI-X,
+ * so don't fail if the BIOS doesn't provide a legacy IRQ.
+ */
+ if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) {
+ dev_err(&dev->dev,
+ "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
+ pci_name(dev));
+ retval = -ENODEV;
+ goto disable_pci;
+ }
+
+ hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto disable_pci;
+ }
+
+ if (driver->flags & HCD_MEMORY) {
+ /* EHCI, OHCI */
+ hcd->rsrc_start = pci_resource_start(dev, 0);
+ hcd->rsrc_len = pci_resource_len(dev, 0);
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&dev->dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto clear_companion;
+ }
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&dev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto release_mem_region;
+ }
+
+ } 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 (request_region(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 clear_companion;
+ }
+ }
+
+ pci_set_master(dev);
+
+ retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+ if (retval != 0)
+ goto unmap_registers;
+ set_hs_companion(dev, hcd);
+
+ if (pci_dev_run_wake(dev))
+ pm_runtime_put_noidle(&dev->dev);
+ return retval;
+
+unmap_registers:
+ if (driver->flags & HCD_MEMORY) {
+ iounmap(hcd->regs);
+release_mem_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ } else
+ release_region(hcd->rsrc_start, hcd->rsrc_len);
+clear_companion:
+ clear_hs_companion(dev, 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();
+
+ usb_remove_hcd(hcd);
+ if (hcd->driver->flags & HCD_MEMORY) {
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ } else {
+ release_region(hcd->rsrc_start, hcd->rsrc_len);
+ }
+ clear_hs_companion(dev, hcd);
+ 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);
+ 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;
+}
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+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)) {
+ if (event != PM_EVENT_AUTO_RESUME)
+ wait_for_companions(pci_dev, hcd);
+
+ retval = hcd->driver->pci_resume(hcd,
+ event == PM_EVENT_RESTORE);
+ if (retval) {
+ dev_err(dev, "PCI post-resume error %d!\n", retval);
+ if (hcd->shared_hcd)
+ usb_hc_died(hcd->shared_hcd);
+ usb_hc_died(hcd);
+ }
+ }
+ return retval;
+}
+#endif /* SLEEP || RUNTIME */
+
+#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)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+
+ powermac_set_asic(pci_dev, 1);
+
+ /* Go back to D0 and disable remote wakeup */
+ pci_back_from_sleep(pci_dev);
+ 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 */
+
+#ifdef CONFIG_PM_RUNTIME
+
+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;
+}
+
+#else
+
+#define hcd_pci_runtime_suspend NULL
+#define hcd_pci_runtime_resume NULL
+
+#endif /* CONFIG_PM_RUNTIME */
+
+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 = check_root_hub_suspended,
+ .freeze_noirq = check_root_hub_suspended,
+ .thaw_noirq = NULL,
+ .thaw = NULL,
+ .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 00000000..8318901f
--- /dev/null
+++ b/drivers/usb/core/hcd.c
@@ -0,0 +1,2656 @@
+/*
+ * (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
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.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/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "usb.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 */
+LIST_HEAD (usb_bus_list);
+EXPORT_SYMBOL_GPL (usb_bus_list);
+
+/* used when allocating bus numbers */
+#define USB_MAXBUS 64
+struct usb_busmap {
+ unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
+};
+static struct usb_busmap busmap;
+
+/* used when updating list of hcds */
+DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_list_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 ((LINUX_VERSION_CODE >> 16) & 0x0ff)
+#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
+
+/* usb 3.0 root hub device descriptor */
+static const u8 usb3_rh_dev_descriptor[18] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __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 */
+ 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.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __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 */
+ 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; */
+ 0x01, /* __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 */
+ 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; */
+ 0x02, /* __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; */
+ 0x04, /* __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; */
+ 0x05, /* __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; */
+ 0x02, /* __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; */
+ 0x04, /* __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; */
+ 0x05, /* __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; */
+ 0x02, /* __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; */
+ 0x04, /* __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; */
+ 0x05, /* __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 */
+ 0x30, /* __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.
+ *
+ * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
+ * buflen, whichever is less.
+ *
+ * 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.
+ * Returns 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;
+ /*
+ * tbuf should be as big as the BOS descriptor and
+ * the USB hub descriptor.
+ */
+ u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
+ __attribute__((aligned(4)));
+ const u8 *bufp = tbuf;
+ unsigned len = 0;
+ int status;
+ u8 patch_wakeup = 0;
+ u8 patch_protocol = 0;
+
+ 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;
+
+ 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_USB3:
+ bufp = usb3_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_USB3:
+ bufp = ss_rh_config_descriptor;
+ len = sizeof ss_rh_config_descriptor;
+ break;
+ 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:
+ case GetPortStatus:
+ len = 4;
+ 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);
+ 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;
+ }
+
+ /* any errors get returned through the urb completion */
+ spin_lock_irq(&hcd_root_hub_lock);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ /* This peculiar use of spinlocks echoes what real HC drivers do.
+ * Avoiding calls to local_irq_disable/enable makes the code
+ * RT-friendly.
+ */
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+
+ 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;
+ 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;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, 0);
+ spin_lock(&hcd_root_hub_lock);
+ } 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 (unsigned long _hcd)
+{
+ usb_hcd_poll_rh_status((struct usb_hcd *) _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);
+
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+ }
+ }
+ done:
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ return rc;
+}
+
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_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 *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_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 *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ result = sscanf(buf, "%u\n", &val);
+ if (result == 1) {
+ usb_hcd->authorized_default = val? 1 : 0;
+ result = size;
+ }
+ else
+ result = -EINVAL;
+ return result;
+}
+
+static DEVICE_ATTR(authorized_default, 0644,
+ usb_host_authorized_default_show,
+ usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+ &dev_attr_authorized_default.attr,
+ NULL,
+};
+
+static 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;
+
+ INIT_LIST_HEAD (&bus->bus_list);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * 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.
+ */
+static int usb_register_bus(struct usb_bus *bus)
+{
+ int result = -E2BIG;
+ int busnum;
+
+ mutex_lock(&usb_bus_list_lock);
+ busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
+ if (busnum >= USB_MAXBUS) {
+ printk (KERN_ERR "%s: too many buses\n", usbcore_name);
+ goto error_find_busnum;
+ }
+ set_bit (busnum, busmap.busmap);
+ bus->busnum = busnum;
+
+ /* Add it to the local list of buses */
+ list_add (&bus->bus_list, &usb_bus_list);
+ mutex_unlock(&usb_bus_list_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_list_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_list_lock);
+ list_del (&bus->bus_list);
+ mutex_unlock(&usb_bus_list_lock);
+
+ usb_notify_remove_bus(bus);
+
+ clear_bit (bus->busnum, busmap.busmap);
+}
+
+/**
+ * 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).
+ */
+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_list_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_list_lock);
+ dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
+ dev_name(&usb_dev->dev), retval);
+ return (retval < 0) ? retval : -EMSGSIZE;
+ }
+
+ 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);
+ }
+ mutex_unlock(&usb_bus_list_lock);
+
+ if (retval == 0) {
+ 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 */
+ }
+
+ return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * 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.
+ *
+ * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * 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.
+ *
+ * Returns 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.
+ *
+ * Returns 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 capabilites 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 addressible
+ * 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 (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
+ dma_unmap_single(hcd->self.controller,
+ 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 (urb->transfer_flags & URB_DMA_MAP_SG)
+ dma_unmap_sg(hcd->self.controller,
+ urb->sg,
+ urb->num_sgs,
+ dir);
+ else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
+ dma_unmap_page(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+ else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
+ dma_unmap_single(hcd->self.controller,
+ 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 (hcd->self.uses_dma) {
+ urb->setup_dma = dma_map_single(
+ hcd->self.controller,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(hcd->self.controller,
+ 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 (hcd->self.uses_dma) {
+ if (urb->num_sgs) {
+ int n = dma_map_sg(
+ hcd->self.controller,
+ 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.controller,
+ sg_page(sg),
+ sg->offset,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.controller,
+ urb->transfer_dma))
+ ret = -EAGAIN;
+ else
+ urb->transfer_flags |= URB_DMA_MAP_PAGE;
+ } else {
+ urb->transfer_dma = dma_map_single(
+ hcd->self.controller,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+ if (dma_mapping_error(hcd->self.controller,
+ 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);
+ 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;
+ 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(urb->dev);
+ }
+ spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
+ if (retval == 0) {
+ hcd = bus_to_hcd(urb->dev->bus);
+ retval = unlink1(hcd, urb, status);
+ usb_put_dev(urb->dev);
+ }
+
+ if (retval == 0)
+ retval = -EINPROGRESS;
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+ urb, retval);
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * 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)
+{
+ urb->hcpriv = NULL;
+ if (unlikely(urb->unlinked))
+ status = urb->unlinked;
+ else 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_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->status = status;
+ urb->complete (urb);
+ atomic_dec (&urb->use_count);
+ if (unlikely(atomic_read(&urb->reject)))
+ wake_up (&usb_kill_urb_queue);
+ usb_put_urb (urb);
+}
+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 (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 %p 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.
+ *
+ * Returns 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.
+ */
+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;
+
+ 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;
+
+ /* Streams only apply to bulk endpoints. */
+ for (i = 0; i < num_eps; i++)
+ if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
+ return -EINVAL;
+
+ return hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
+ num_streams, mem_flags);
+}
+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.
+ */
+void 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;
+
+ dev = interface_to_usbdev(interface);
+ hcd = bus_to_hcd(dev->bus);
+ if (dev->speed != USB_SPEED_SUPER)
+ return;
+
+ /* Streams only apply to bulk endpoints. */
+ for (i = 0; i < num_eps; i++)
+ if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc))
+ return;
+
+ hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
+}
+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 = container_of(rhdev->bus, struct usb_hcd, self);
+ 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;
+
+ /* 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 = container_of(rhdev->bus, struct usb_hcd, self);
+ 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 (!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) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ 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);
+ } else {
+ hcd->state = old_state;
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
+ "resume", status);
+ if (status != -ESHUTDOWN)
+ usb_hc_died(hcd);
+ }
+ return status;
+}
+
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+
+/* 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_lock_device(udev);
+ usb_remote_wakeup(udev);
+ usb_unlock_device(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) {
+ 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_USB_SUSPEND */
+
+/*-------------------------------------------------------------------------*/
+
+#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
+ * khubd 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.
+ */
+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 = container_of (bus, struct usb_hcd, self);
+ if (port_num && hcd->driver->start_port_reset)
+ status = hcd->driver->start_port_reset(hcd, port_num);
+
+ /* run khubd 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.
+ */
+irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+{
+ struct usb_hcd *hcd = __hcd;
+ unsigned long flags;
+ irqreturn_t rc;
+
+ /* IRQF_DISABLED doesn't work correctly with shared IRQs
+ * when the first handler doesn't use it. So let's just
+ * assume it's never used.
+ */
+ local_irq_save(flags);
+
+ 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;
+
+ local_irq_restore(flags);
+ 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 khubd clean up old urbs and devices */
+ usb_set_device_state (hcd->self.root_hub,
+ USB_STATE_NOTATTACHED);
+ usb_kick_khubd (hcd->self.root_hub);
+ }
+ if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
+ hcd = hcd->shared_hcd;
+ if (hcd->rh_registered) {
+ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+ /* make khubd clean up old urbs and devices */
+ usb_set_device_state(hcd->self.root_hub,
+ USB_STATE_NOTATTACHED);
+ usb_kick_khubd(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);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * 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.
+ *
+ * If memory is unavailable, returns 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)
+{
+ struct usb_hcd *hcd;
+
+ hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
+ if (!hcd) {
+ dev_dbg (dev, "hcd alloc failed\n");
+ return NULL;
+ }
+ if (primary_hcd == NULL) {
+ hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
+ GFP_KERNEL);
+ if (!hcd->bandwidth_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 {
+ 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;
+ }
+
+ kref_init(&hcd->kref);
+
+ usb_bus_init(&hcd->self);
+ hcd->self.controller = dev;
+ hcd->self.bus_name = bus_name;
+ hcd->self.uses_dma = (dev->dma_mask != NULL);
+
+ init_timer(&hcd->rh_timer);
+ hcd->rh_timer.function = rh_timer_func;
+ hcd->rh_timer.data = (unsigned long) hcd;
+#ifdef CONFIG_USB_SUSPEND
+ 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_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.
+ *
+ * If memory is unavailable, returns NULL.
+ */
+struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
+ struct device *dev, const char *bus_name)
+{
+ return usb_create_shared_hcd(driver, 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 only deallocate the bandwidth_mutex when the primary HCD is
+ * freed. When hcd_release() is called for the non-primary HCD, set the
+ * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be
+ * freed shortly).
+ */
+static void hcd_release (struct kref *kref)
+{
+ struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
+
+ if (usb_hcd_is_primary_hcd(hcd))
+ kfree(hcd->bandwidth_mutex);
+ else
+ hcd->shared_hcd->shared_hcd = NULL;
+ 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);
+
+static int usb_hcd_request_irqs(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ int retval;
+
+ if (hcd->driver->irq) {
+
+ /* IRQF_DISABLED doesn't work as advertised when used together
+ * with IRQF_SHARED. As usb_hcd_irq() will always disable
+ * interrupts we can remove it here.
+ */
+ if (irqflags & IRQF_SHARED)
+ irqflags &= ~IRQF_DISABLED;
+
+ 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;
+}
+
+/**
+ * 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.
+ */
+extern char enable_ehci_wake;
+
+int usb_add_hcd(struct usb_hcd *hcd,
+ unsigned int irqnum, unsigned long irqflags)
+{
+ int retval;
+ struct usb_device *rhdev;
+
+ 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)
+ hcd->authorized_default = hcd->wireless? 0 : 1;
+ else
+ hcd->authorized_default = authorized_default;
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &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 khubd
+ * starts talking to them. (Note, bus id is assigned early too.)
+ */
+ if ((retval = hcd_buffer_create(hcd)) != 0) {
+ dev_dbg(hcd->self.controller, "pool alloc failed\n");
+ return retval;
+ }
+
+ if ((retval = usb_register_bus(&hcd->self)) < 0)
+ goto err_register_bus;
+
+ if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+ dev_err(hcd->self.controller, "unable to allocate root hub\n");
+ retval = -ENOMEM;
+ goto err_allocate_root_hub;
+ }
+ hcd->self.root_hub = rhdev;
+
+ switch (hcd->speed) {
+ case HCD_USB11:
+ rhdev->speed = USB_SPEED_FULL;
+ break;
+ case HCD_USB2:
+ rhdev->speed = USB_SPEED_HIGH;
+ break;
+ case HCD_USB3:
+ rhdev->speed = USB_SPEED_SUPER;
+ 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.
+ */
+ if (enable_ehci_wake) {
+ device_init_wakeup(&rhdev->dev, 1);
+ }
+
+ //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)) < 0) {
+ dev_err(hcd->self.controller, "can't setup\n");
+ 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");
+
+ /* 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 */
+ rhdev->bus_mA = min(500u, hcd->power_budget);
+ if ((retval = register_root_hub(hcd)) != 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);
+
+ /*
+ * Host controllers don't generate their own wakeup requests;
+ * they only forward requests from the root hub. Therefore
+ * controllers should always be enabled for remote wakeup.
+ */
+
+ if (enable_ehci_wake) {
+ device_wakeup_enable(hcd->self.controller);
+ }
+
+ 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_USB_SUSPEND
+ cancel_work_sync(&hcd->wakeup_work);
+#endif
+ mutex_lock(&usb_bus_list_lock);
+ usb_disconnect(&rhdev); /* Sets rhdev to NULL */
+ mutex_unlock(&usb_bus_list_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_dev(hcd->self.root_hub);
+err_allocate_root_hub:
+ usb_deregister_bus(&hcd->self);
+err_register_bus:
+ hcd_buffer_destroy(hcd);
+ 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_USB_SUSPEND
+ cancel_work_sync(&hcd->wakeup_work);
+#endif
+
+ mutex_lock(&usb_bus_list_lock);
+ usb_disconnect(&rhdev); /* Sets rhdev to NULL */
+ mutex_unlock(&usb_bus_list_lock);
+
+ /* 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_put_dev(hcd->self.root_hub);
+ usb_deregister_bus(&hcd->self);
+ hcd_buffer_destroy(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_remove_hcd);
+
+void
+usb_hcd_platform_shutdown(struct platform_device* dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
+
+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 (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 00000000..d6dab03a
--- /dev/null
+++ b/drivers/usb/core/hub.c
@@ -0,0 +1,4284 @@
+/*
+ * 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)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/completion.h>
+#include <linux/sched.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/quirks.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/freezer.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "usb.h"
+
+/* if we are in debug mode, always announce new devices */
+#ifdef DEBUG
+#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#define CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#endif
+#endif
+
+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 */
+ char (*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 */
+
+ struct list_head event_list; /* hubs w/data or errs ready */
+ unsigned long event_bits[1]; /* status change bitmask */
+ unsigned long change_bits[1]; /* ports with logical connect
+ status change */
+ unsigned long busy_bits[1]; /* ports being reset or
+ resumed */
+ unsigned long removed_bits[1]; /* ports with a "removed"
+ device present */
+ unsigned long wakeup_bits[1]; /* ports that have signaled
+ remote wakeup */
+#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 */
+
+ unsigned limited_power:1;
+ unsigned quiescing:1;
+ unsigned disconnected:1;
+
+ unsigned has_indicators:1;
+ u8 indicator[USB_MAXCHILDREN];
+ struct delayed_work leds;
+ struct delayed_work init_work;
+ void **port_owners;
+};
+
+static inline int hub_is_superspeed(struct usb_device *hdev)
+{
+ return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
+}
+
+/* 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);
+
+/* khubd's worklist and its lock */
+static DEFINE_SPINLOCK(hub_event_lock);
+static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
+
+/* Wakes up khubd */
+static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+
+static struct task_struct *khubd_task;
+
+/* cycle leds on hubs that aren't blinking for attention */
+static bool blinkenlights = 0;
+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 = 0;
+module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(old_scheme_first,
+ "start with the old device initialization scheme");
+
+static 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 1500
+#define HUB_DEBOUNCE_STEP 25
+#define HUB_DEBOUNCE_STABLE 100
+unsigned int usb_storage_id = 0;
+
+static int usb_reset_and_verify_device(struct usb_device *udev);
+
+static inline char *portspeed(struct usb_hub *hub, int portstatus)
+{
+ 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! */
+static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
+{
+ if (!hdev || !hdev->actconfig)
+ return NULL;
+ return usb_get_intfdata(hdev->actconfig->interface[0]);
+}
+
+/* USB 2.0 spec Section 11.24.4.5 */
+static int get_hub_descriptor(struct usb_device *hdev, void *data)
+{
+ 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, data, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
+ 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
+ */
+static int 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);
+}
+
+/*
+ * 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
+)
+{
+ int status = set_port_feature(hub->hdev, (selector << 8) | port1,
+ USB_PORT_FEAT_INDICATOR);
+ if (status < 0)
+ dev_dbg (hub->intfdev,
+ "port %d indicator %s status %d\n",
+ port1,
+ ({ char *s; switch (selector) {
+ case HUB_LED_AMBER: s = "amber"; break;
+ case HUB_LED_GREEN: s = "green"; break;
+ case HUB_LED_OFF: s = "off"; break;
+ case HUB_LED_AUTO: s = "auto"; break;
+ default: s = "??"; break;
+ }; s; }),
+ 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 < hub->descriptor->bNbrPorts; 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 %= hub->descriptor->bNbrPorts;
+ set_port_led(hub, cursor + 1, HUB_LED_GREEN);
+ hub->indicator[cursor] = INDICATOR_CYCLE;
+ changed++;
+ }
+ if (changed)
+ schedule_delayed_work(&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
+ */
+static int get_port_status(struct usb_device *hdev, int port1,
+ struct usb_port_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_PORT, 0, port1,
+ data, sizeof(*data), USB_STS_TIMEOUT);
+ }
+ return status;
+}
+
+static int hub_port_status(struct usb_hub *hub, int port1,
+ u16 *status, u16 *change)
+{
+ int ret;
+
+ mutex_lock(&hub->status_mutex);
+ ret = get_port_status(hub->hdev, port1, &hub->status->port);
+ if (ret < 4) {
+ 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);
+
+ ret = 0;
+ }
+ mutex_unlock(&hub->status_mutex);
+ return ret;
+}
+
+static void kick_khubd(struct usb_hub *hub)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (!hub->disconnected && list_empty(&hub->event_list)) {
+ list_add_tail(&hub->event_list, &hub_event_list);
+
+ /* Suppress autosuspend until khubd runs */
+ usb_autopm_get_interface_no_resume(
+ to_usb_interface(hub->intfdev));
+ wake_up(&khubd_wait);
+ }
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+void usb_kick_khubd(struct usb_device *hdev)
+{
+ struct usb_hub *hub = hdev_to_hub(hdev);
+
+ if (hub)
+ kick_khubd(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;
+
+ if (!hdev)
+ return;
+
+ hub = hdev_to_hub(hdev);
+ if (hub) {
+ set_bit(portnum, hub->wakeup_bits);
+ kick_khubd(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 khubd 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 khubd figure it out */
+ kick_khubd(hub);
+
+resubmit:
+ if (hub->quiescing)
+ return;
+
+ if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 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)
+{
+ return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
+ tt, NULL, 0, 1000);
+}
+
+/*
+ * enumeration blocks khubd 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;
+ int limit = 100;
+
+ spin_lock_irqsave (&hub->tt.lock, flags);
+ while (--limit && !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)
+ 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_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.
+ */
+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.
+ */
+ if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == 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);
+
+/* If do_delay is false, return the number of milliseconds the caller
+ * needs to delay.
+ */
+/*CharlesTu,2012.09.14,improve resume time*/
+unsigned char usb_resume_flag=0;
+static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
+{
+ int port1;
+ unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
+ unsigned delay;
+ u16 wHubCharacteristics =
+ le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ /* 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 ((wHubCharacteristics & HUB_CHAR_LPSM) < 2)
+ 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->descriptor->bNbrPorts; port1++)
+ set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+
+ /* Wait at least 100 msec for power to become stable */
+ delay = max(pgood_delay, (unsigned) 100);
+ if (do_delay)
+ if (!usb_resume_flag) {
+ msleep(delay);
+ }
+ return delay;
+}
+
+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)
+ 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_port_disable(struct usb_hub *hub, int port1, int set_state)
+{
+ struct usb_device *hdev = hub->hdev;
+ int ret = 0;
+
+ if (hdev->children[port1-1] && set_state)
+ usb_set_device_state(hdev->children[port1-1],
+ USB_STATE_NOTATTACHED);
+ if (!hub->error && !hub_is_superspeed(hub->hdev))
+ ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
+ if (ret)
+ dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
+ port1, ret);
+ return ret;
+}
+
+/*
+ * Disable a port and mark a logical connect-change event, so that some
+ * time later khubd 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->intfdev, "logical disconnect on port %d\n", port1);
+ 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
+ * khubd reactivates the port later (timer, SRP, etc).
+ * Powerdown must be optional, because of reset/DFU.
+ */
+
+ set_bit(port1, hub->change_bits);
+ kick_khubd(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, khubd 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.
+ */
+int usb_remove_device(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+ struct usb_interface *intf;
+
+ if (!udev->parent) /* Can't remove a root hub */
+ return -EINVAL;
+ hub = hdev_to_hub(udev->parent);
+ intf = to_usb_interface(hub->intfdev);
+
+ usb_autopm_get_interface(intf);
+ 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)
+ goto init2;
+ if (type == HUB_INIT3)
+ goto init3;
+
+ /* 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(hub, false);
+ PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
+ schedule_delayed_work(&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);
+ }
+ }
+ init2:
+
+ /* Check each port and set hub->change_bits to let khubd know
+ * which ports need attention.
+ */
+ for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+ struct usb_device *udev = hdev->children[port1-1];
+ u16 portstatus, portchange;
+
+ portstatus = portchange = 0;
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
+ dev_dbg(hub->intfdev,
+ "port %d: status %04x change %04x\n",
+ port1, 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.
+ */
+ if (!hub_is_superspeed(hdev)) {
+ clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_ENABLE);
+ portstatus &= ~USB_PORT_STAT_ENABLE;
+ } else {
+ /* Pretend that power was lost for USB3 devs */
+ portstatus &= ~USB_PORT_STAT_ENABLE;
+ }
+ }
+
+ /* Clear status-change flags; we'll debounce later */
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ if (!usb_resume_flag) {
+ need_debounce_delay = true;
+ }
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+
+ if (!usb_resume_flag) {
+ need_debounce_delay = true;
+ }
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+ }
+ if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
+ hub_is_superspeed(hub->hdev)) {
+ need_debounce_delay = true;
+ 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 khubd to disconnect the device or
+ * check for a new connection
+ */
+ if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
+ 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 khubd
+ * 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->change_bits);
+
+ } else if (udev->persist_enabled) {
+#ifdef CONFIG_PM
+ udev->reset_resume = 1;
+#endif
+ set_bit(port1, hub->change_bits);
+
+ } else {
+ /* The power session is gone; tell khubd */
+ 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 khubd do them
+ * one at a time later on.
+ *
+ * If any port-status changes do occur during this delay, khubd
+ * 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) {
+ PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3);
+ schedule_delayed_work(&hub->init_work,
+ msecs_to_jiffies(delay));
+ 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)
+ schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
+
+ /* Scan all ports that need attention */
+ kick_khubd(hub);
+
+ /* Allow autosuspend if it was suppressed */
+ if (type <= HUB_INIT3)
+ usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
+}
+
+/* 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;
+
+ cancel_delayed_work_sync(&hub->init_work);
+
+ /* khubd 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 (hdev->children[i])
+ usb_disconnect(&hdev->children[i]);
+ }
+ }
+
+ /* Stop khubd and related activity */
+ usb_kill_urb(hub->urb);
+ if (hub->has_indicators)
+ cancel_delayed_work_sync(&hub->leds);
+ if (hub->tt.hub)
+ cancel_work_sync(&hub->tt.clear_work);
+}
+
+/* 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);
+ 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_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;
+ char *message = "out of memory";
+
+ 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 = kmalloc(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 the 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;
+ } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+ message = "hub has too many ports!";
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ hdev->maxchild = hub->descriptor->bNbrPorts;
+ dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
+ (hdev->maxchild == 1) ? "" : "s");
+
+ hdev->children = kzalloc(hdev->maxchild *
+ sizeof(struct usb_device *), GFP_KERNEL);
+ hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
+ if (!hdev->children || !hub->port_owners) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ /* FIXME for USB 3.0, skip for now */
+ if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
+ !(hub_is_superspeed(hdev))) {
+ int i;
+ char portstr [USB_MAXCHILDREN + 1];
+
+ for (i = 0; i < hdev->maxchild; i++)
+ portstr[i] = hub->descriptor->u.hs.DeviceRemovable
+ [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+ ? 'F' : 'R';
+ portstr[hdev->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_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
+ if (ret < 2) {
+ message = "can't get hub status";
+ goto fail;
+ }
+ le16_to_cpus(&hubstatus);
+ if (hdev == hdev->bus->root_hub) {
+ if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
+ hub->mA_per_port = 500;
+ else {
+ hub->mA_per_port = hdev->bus_mA;
+ hub->limited_power = 1;
+ }
+ } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
+ hub->descriptor->bHubContrCurrent);
+ hub->limited_power = 1;
+ if (hdev->maxchild > 0) {
+ int remaining = hdev->bus_mA -
+ hub->descriptor->bHubContrCurrent;
+
+ if (remaining < hdev->maxchild * 100)
+ dev_warn(hub_dev,
+ "insufficient power available "
+ "to use all downstream ports\n");
+ hub->mA_per_port = 100; /* 7.2.1.1 */
+ }
+ } else { /* Self-powered external hub */
+ /* FIXME: What about battery-powered external hubs that
+ * provide less current per port? */
+ hub->mA_per_port = 500;
+ }
+ if (hub->mA_per_port < 500)
+ dev_dbg(hub_dev, "%umA bus power budget for each child\n",
+ hub->mA_per_port);
+
+ /* Update the HCD's internal representation of this hub before khubd
+ * starts getting port status changes for devices under the hub.
+ */
+ hcd = bus_to_hcd(hdev->bus);
+ 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;
+ }
+ }
+
+ 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;
+
+ 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_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);
+
+ /* Take the hub off the event list and don't let it be added again */
+ spin_lock_irq(&hub_event_lock);
+ if (!list_empty(&hub->event_list)) {
+ list_del_init(&hub->event_list);
+ usb_autopm_put_interface_no_suspend(intf);
+ }
+ hub->disconnected = 1;
+ spin_unlock_irq(&hub_event_lock);
+
+ /* Disconnect all children and quiesce the hub */
+ hub->error = 0;
+ hub_quiesce(hub, HUB_DISCONNECT);
+
+ usb_set_intfdata (intf, NULL);
+ hub->hdev->maxchild = 0;
+
+ if (hub->hdev->speed == USB_SPEED_HIGH)
+ highspeed_hubs--;
+
+ usb_free_urb(hub->urb);
+ kfree(hdev->children);
+ kfree(hub->port_owners);
+ kfree(hub->descriptor);
+ kfree(hub->status);
+ kfree(hub->buffer);
+
+ kref_put(&hub->kref, hub_release);
+}
+
+static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_host_interface *desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *hdev;
+ struct usb_hub *hub;
+
+ desc = intf->cur_altsetting;
+ hdev = interface_to_usbdev(intf);
+
+ /* Hubs have proper suspend/resume support. */
+ 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
+
+ /* 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)) {
+descriptor_error:
+ dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
+ return -EIO;
+ }
+
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (desc->desc.bNumEndpoints != 1)
+ goto descriptor_error;
+
+ endpoint = &desc->endpoint[0].desc;
+
+ /* If it's not an interrupt in endpoint, we'd better punt! */
+ if (!usb_endpoint_is_int_in(endpoint))
+ goto descriptor_error;
+
+ /* We found a hub */
+ dev_info (&intf->dev, "USB hub found\n");
+
+ hub = kzalloc(sizeof(*hub), GFP_KERNEL);
+ if (!hub) {
+ dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
+ return -ENOMEM;
+ }
+
+ kref_init(&hub->kref);
+ INIT_LIST_HEAD(&hub->event_list);
+ hub->intfdev = &intf->dev;
+ hub->hdev = hdev;
+ INIT_DELAYED_WORK(&hub->leds, led_work);
+ INIT_DELAYED_WORK(&hub->init_work, NULL);
+ usb_get_intf(intf);
+
+ usb_set_intfdata (intf, hub);
+ intf->needs_remote_wakeup = 1;
+
+ if (hdev->speed == USB_SPEED_HIGH)
+ highspeed_hubs++;
+
+ if (hub_configure(hub, endpoint) >= 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);
+
+ /* 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 (hdev->children[i] == NULL)
+ info->port[i] = 0;
+ else
+ info->port[i] =
+ hdev->children[i]->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,
+ void ***ppowner)
+{
+ if (hdev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (port1 == 0 || port1 > hdev->maxchild)
+ return -EINVAL;
+
+ /* This assumes that devices not managed by the hub driver
+ * will always have maxchild equal to 0.
+ */
+ *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
+ 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, void *owner)
+{
+ int rc;
+ void **powner;
+
+ rc = find_port_owner(hdev, port1, &powner);
+ if (rc)
+ return rc;
+ if (*powner)
+ return -EBUSY;
+ *powner = owner;
+ return rc;
+}
+
+int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
+{
+ int rc;
+ void **powner;
+
+ rc = find_port_owner(hdev, port1, &powner);
+ if (rc)
+ return rc;
+ if (*powner != owner)
+ return -ENOENT;
+ *powner = NULL;
+ return rc;
+}
+
+void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
+{
+ int n;
+ void **powner;
+
+ n = find_port_owner(hdev, 1, &powner);
+ if (n == 0) {
+ for (; n < hdev->maxchild; (++n, ++powner)) {
+ if (*powner == owner)
+ *powner = 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 = hdev_to_hub(udev->parent);
+ return !!hub->port_owners[udev->portnum - 1];
+}
+
+
+static void recursively_mark_NOTATTACHED(struct usb_device *udev)
+{
+ int i;
+
+ for (i = 0; i < udev->maxchild; ++i) {
+ if (udev->children[i])
+ recursively_mark_NOTATTACHED(udev->children[i]);
+ }
+ 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.
+ */
+
+extern char enable_ehci_wake;
+
+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->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);
+ if (enable_ehci_wake)
+ device_wakeup_enable(&udev->dev);//gri
+ }
+}
+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;
+
+ /* If khubd ever becomes multithreaded, this will need a lock */
+ 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;
+ }
+}
+
+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);
+}
+
+/**
+ * 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 this routine will acquire the
+ * usb_bus_list_lock on behalf of the caller.
+ *
+ * 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_device *udev = *pdev;
+ int i;
+
+ int wmt_usb_patch = 0;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub)
+ && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00)))
+ wmt_usb_patch = 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);
+
+ usb_lock_device(udev);
+
+ /* Free up all the children before we remove this device */
+ for (i = 0; i < udev->maxchild; i++) {
+ if (udev->children[i])
+ usb_disconnect(&udev->children[i]);
+ }
+
+ /* 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);
+
+ 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);
+
+ hub_free_dev(udev);
+
+ put_device(&udev->dev);
+
+ if (wmt_usb_patch)
+ *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x2);
+}
+
+#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+static void show_string(struct usb_device *udev, char *id, char *string)
+{
+ if (!string)
+ return;
+ dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
+}
+
+static void announce_device(struct usb_device *udev)
+{
+ dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ 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
+
+#ifdef CONFIG_USB_OTG
+#include "otg_whitelist.h"
+#endif
+
+/**
+ * usb_enumerate_device_otg - FIXME (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * Finish enumeration for On-The-Go devices
+ */
+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;
+
+ /* descriptor may appear anywhere in config */
+ if (__usb_get_extra_descriptor (udev->rawdescriptors[0],
+ le16_to_cpu(udev->config[0].desc.wTotalLength),
+ USB_DT_OTG, (void **) &desc) == 0) {
+ if (desc->bmAttributes & USB_OTG_HNP) {
+ unsigned port1 = udev->portnum;
+
+ 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,
+ bus->b_hnp_enable
+ ? USB_DEVICE_B_HNP_ENABLE
+ : USB_DEVICE_A_ALT_HNP_SUPPORT,
+ 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
+ /* OTG MESSAGE: report errors here,
+ * customize to match your product.
+ */
+ dev_info(&udev->dev,
+ "can't set HNP mode: %d\n",
+ err);
+ bus->b_hnp_enable = 0;
+ }
+ }
+ }
+ }
+
+ if (!is_targeted(udev)) {
+
+ /* Maybe it can talk to us, though we can't talk to it.
+ * (Includes HNP test device.)
+ */
+ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
+ err = usb_port_suspend(udev, PMSG_SUSPEND);
+ if (err < 0)
+ dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ }
+ err = -ENOTSUPP;
+ goto fail;
+ }
+fail:
+#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.
+ */
+static int usb_enumerate_device(struct usb_device *udev)
+{
+ int err;
+
+ if (udev->config == NULL) {
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+ }
+ if (udev->wusb == 1 && udev->authorized == 0) {
+ udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ }
+ else {
+ /* 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);
+fail:
+ return err;
+}
+
+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 = hdev_to_hub(udev->parent);
+
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+ return;
+
+ if (hub_is_superspeed(hdev)) {
+ if (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_list_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.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * 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.
+ */
+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);
+
+ device_enable_async_suspend(&udev->dev);
+
+ /*
+ * check whether the hub marks this port as non-removable. Do it
+ * now so that platform-specific data can override it in
+ * device_add()
+ */
+ 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;
+ }
+
+ (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
+ usb_mark_last_busy(udev);
+ pm_runtime_put_sync_autosuspend(&udev->dev);
+
+ {
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub)
+ && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00)))
+ *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x1);
+ }
+ 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.
+ */
+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);
+
+ kfree(usb_dev->product);
+ usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->serial);
+ usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+
+ usb_destroy_configuration(usb_dev);
+ usb_dev->descriptor.bNumConfigurations = 0;
+
+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;
+ }
+ 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;
+ }
+
+ kfree(usb_dev->product);
+ usb_dev->product = NULL;
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = NULL;
+ kfree(usb_dev->serial);
+ usb_dev->serial = NULL;
+
+ usb_dev->authorized = 1;
+ result = usb_enumerate_device(usb_dev);
+ if (result < 0)
+ goto error_enumerate;
+ /* 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_enumerate:
+error_device_descriptor:
+ usb_autosuspend_device(usb_dev);
+error_autoresume:
+out_authorized:
+ usb_unlock_device(usb_dev); // complements locktree
+ return result;
+}
+
+
+/* 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 = container_of(hub->hdev->bus, struct usb_hcd, self);
+ 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) ((i) / 2 == (int)old_scheme_first)
+
+#define HUB_ROOT_RESET_TIME 50 /* 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 500
+
+static int hub_port_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay, bool warm);
+
+/* Is a USB 3.0 port in the Inactive or Complinance Mode state?
+ * Port worm reset is required to recover
+ */
+static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)
+{
+ return hub_is_superspeed(hub->hdev) &&
+ (((portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_SS_INACTIVE) ||
+ ((portstatus & USB_PORT_STAT_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;
+
+ 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 */
+ ret = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Some buggy devices require a warm reset to be issued even
+ * when the port appears not to be connected.
+ */
+ if (!warm) {
+ /*
+ * Some buggy devices can cause an NEC host controller
+ * to transition to the "Error" state after a hot port
+ * reset. This will show up as the port state in
+ * "Inactive", and the port may also report a
+ * disconnect. Forcing a warm port reset seems to make
+ * the device work.
+ *
+ * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
+ */
+ if (hub_port_warm_reset_required(hub, portstatus)) {
+ int ret;
+
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ if (portchange & USB_PORT_STAT_C_RESET)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_RESET);
+ dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
+ port1);
+ ret = hub_port_reset(hub, port1,
+ udev, HUB_BH_RESET_TIME,
+ true);
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ return ret;
+ }
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return -ENOTCONN;
+
+ /* bomb out completely if the connection bounced */
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ return -ENOTCONN;
+
+ /* if we`ve finished resetting, then break out of
+ * the loop
+ */
+ if (!(portstatus & USB_PORT_STAT_RESET) &&
+ (portstatus & USB_PORT_STAT_ENABLE)) {
+ if (hub_is_wusb(hub))
+ udev->speed = USB_SPEED_WIRELESS;
+ 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;
+ }
+ } else {
+ if (portchange & USB_PORT_STAT_C_BH_RESET)
+ return 0;
+ }
+
+ /* 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->intfdev,
+ "port %d not %sreset yet, waiting %dms\n",
+ port1, warm ? "warm " : "", delay);
+ }
+
+ return -EBUSY;
+}
+
+static void hub_port_finish_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, int *status, bool warm)
+{
+ switch (*status) {
+ case 0:
+ if (!warm) {
+ struct usb_hcd *hcd;
+ /* TRSTRCY = 10 ms; plus some extra */
+ msleep(10); /*CharlesTu,2012.09.14,improve resume time*/
+ update_devnum(udev, 0);
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->reset_device) {
+ *status = hcd->driver->reset_device(hcd, udev);
+ if (*status < 0) {
+ dev_err(&udev->dev, "Cannot reset "
+ "HCD device state\n");
+ break;
+ }
+ }
+ }
+ /* FALL THROUGH */
+ case -ENOTCONN:
+ case -ENODEV:
+ clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_C_RESET);
+ /* FIXME need disconnect() for NOTATTACHED device */
+ if (warm) {
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ } else {
+ usb_set_device_state(udev, *status
+ ? USB_STATE_NOTATTACHED
+ : USB_STATE_DEFAULT);
+ }
+ break;
+ }
+}
+
+/* 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;
+
+ if (!warm) {
+ /* 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 (!hub_is_superspeed(hub->hdev)) {
+ dev_err(hub->intfdev, "only USB3 hub support "
+ "warm reset\n");
+ return -EINVAL;
+ }
+ }
+
+ /* 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) {
+ dev_err(hub->intfdev,
+ "cannot %sreset port %d (err = %d)\n",
+ warm ? "warm " : "", port1, status);
+ } else {
+ status = hub_port_wait_reset(hub, port1, udev, delay,
+ warm);
+ if (status && status != -ENOTCONN)
+ dev_dbg(hub->intfdev,
+ "port_wait_reset: err = %d\n",
+ status);
+ }
+
+ /* return on disconnect or reset */
+ if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
+ hub_port_finish_reset(hub, port1, udev, &status, warm);
+ goto done;
+ }
+
+ dev_dbg (hub->intfdev,
+ "port %d not enabled, trying %sreset again...\n",
+ port1, warm ? "warm " : "");
+ delay = HUB_LONG_RESET_TIME;
+ }
+
+ dev_err (hub->intfdev,
+ "Cannot enable port %i. Maybe the USB cable is bad?\n",
+ port1);
+
+done:
+ if (!warm)
+ 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;
+}
+
+#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, unsigned portchange, unsigned portstatus)
+{
+ /* Is the device still present? */
+ if (status || port_is_suspended(hub, portstatus) ||
+ !port_is_power_on(hub, portstatus) ||
+ !(portstatus & USB_PORT_STAT_CONNECTION)) {
+ if (status >= 0)
+ 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(hub->intfdev,
+ "port %d status %04x.%04x after resume, %d\n",
+ port1, portchange, portstatus, status);
+ } else if (udev->reset_resume) {
+
+ /* Late port handoff can set status-change bits */
+ if (portchange & USB_PORT_STAT_C_CONNECTION)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ if (portchange & USB_PORT_STAT_C_ENABLE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+ }
+
+ return status;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+
+/*
+ * 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 khubd
+ * timer, no SRP, no requests through sysfs.
+ *
+ * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_hub *hub = hdev_to_hub(udev->parent);
+ int port1 = udev->portnum;
+ int status;
+
+ /* 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) {
+ if (!hub_is_superspeed(hub->hdev)) {
+ status = 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 {
+ /* Assume there's only one function on the USB 3.0
+ * device and enable remote wake for the first
+ * interface. FIXME if the interface association
+ * descriptor shows there's more than one function.
+ */
+ status = 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);
+ }
+ if (status) {
+ dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
+ status);
+ /* bail if autosuspend is requested */
+ if (PMSG_IS_AUTO(msg))
+ return status;
+ }
+ }
+
+ /* disable USB2 hardware LPM */
+ if (udev->usb2_hw_lpm_enabled == 1)
+ usb_set_usb2_hardware_lpm(udev, 0);
+
+ /* see 7.1.7.6 */
+ if (hub_is_superspeed(hub->hdev))
+ status = set_port_feature(hub->hdev,
+ port1 | (USB_SS_PORT_LS_U3 << 3),
+ USB_PORT_FEAT_LINK_STATE);
+ else
+ status = set_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_SUSPEND);
+ if (status) {
+ dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
+ port1, status);
+ /* paranoia: "should not happen" */
+ if (udev->do_remote_wakeup)
+ (void) 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);
+
+ /* Try to enable USB2 hardware LPM again */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
+
+ /* System sleep transitions should never fail */
+ if (!PMSG_IS_AUTO(msg))
+ status = 0;
+ } else {
+ /* device has up to 10 msec to fully suspend */
+ dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""),
+ udev->do_remote_wakeup);
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ msleep(10);
+ }
+ usb_mark_last_busy(hub->hdev);
+ 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;
+
+ /* 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 khubd 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)
+ retry_reset_resume:
+ 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_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
+ if (status >= 0)
+ status = (status > 0 ? 0 : -ENODEV);
+
+ /* 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);
+ } else if (udev->actconfig) {
+ le16_to_cpus(&devstatus);
+ if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+ status = 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);
+ if (status)
+ dev_dbg(&udev->dev,
+ "disable remote wakeup, status %d\n",
+ status);
+ }
+ status = 0;
+ }
+ 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 = hdev_to_hub(udev->parent);
+ int port1 = udev->portnum;
+ int status;
+ u16 portchange, portstatus;
+
+ /* 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))
+ goto SuspendCleared;
+
+ // dev_dbg(hub->intfdev, "resume port %d\n", port1);
+
+ set_bit(port1, hub->busy_bits);
+
+ /* see 7.1.7.7; affects power usage, but not budgeting */
+ if (hub_is_superspeed(hub->hdev))
+ status = set_port_feature(hub->hdev,
+ port1 | (USB_SS_PORT_LS_U0 << 3),
+ USB_PORT_FEAT_LINK_STATE);
+ else
+ status = clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_SUSPEND);
+ if (status) {
+ dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
+ port1, status);
+ } else {
+ /* drive resume for at least 20 msec */
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""));
+ msleep(25);
+
+ /* 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);
+
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ }
+
+ SuspendCleared:
+ if (status == 0) {
+ if (hub_is_superspeed(hub->hdev)) {
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ } else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
+ }
+ }
+
+ clear_bit(port1, hub->busy_bits);
+
+ 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 */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
+ }
+
+ return status;
+}
+
+/* caller has locked udev */
+int usb_remote_wakeup(struct usb_device *udev)
+{
+ int status = 0;
+
+ 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);
+ }
+ }
+ return status;
+}
+
+#else /* CONFIG_USB_SUSPEND */
+
+/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
+
+int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ return 0;
+}
+
+/* However we may need to do a reset-resume */
+
+int usb_port_resume(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_hub *hub = hdev_to_hub(udev->parent);
+ int port1 = udev->portnum;
+ int status;
+ u16 portchange, portstatus;
+
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
+ status = check_port_resume_type(udev,
+ hub, port1, status, portchange, portstatus);
+
+ if (status) {
+ dev_dbg(&udev->dev, "can't resume, status %d\n", status);
+ hub_port_logical_disconnect(hub, port1);
+ } else if (udev->reset_resume) {
+ dev_dbg(&udev->dev, "reset-resume\n");
+ status = usb_reset_and_verify_device(udev);
+ }
+ return status;
+}
+
+#endif
+
+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 */
+ for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+ struct usb_device *udev;
+
+ udev = hdev->children [port1-1];
+ if (udev && udev->can_submit) {
+ dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
+ if (PMSG_IS_AUTO(msg))
+ return -EBUSY;
+ }
+ }
+ 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 khubd and related activity */
+ hub_quiesce(hub, HUB_SUSPEND);
+ return 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);
+ return 0;
+}
+
+static int hub_reset_resume(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+ usb_resume_flag = 1;
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_activate(hub, HUB_RESET_RESUME);
+ usb_resume_flag = 0;
+ 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_warn(&rhdev->dev, "root hub lost power or was reset\n");
+ rhdev->reset_resume = 1;
+}
+EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
+#else /* CONFIG_PM */
+
+#define hub_suspend NULL
+#define hub_resume NULL
+#define hub_reset_resume NULL
+#endif
+
+
+/* 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.
+ */
+static int hub_port_debounce(struct usb_hub *hub, int port1)
+{
+ int ret;
+ int total_time, stable_time = 0;
+ u16 portchange, portstatus;
+ unsigned connection = 0xffff;
+
+ 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) {
+ 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) {
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ }
+
+ if (total_time >= HUB_DEBOUNCE_TIMEOUT)
+ break;
+ msleep(HUB_DEBOUNCE_STEP);
+ }
+
+ dev_dbg (hub->intfdev,
+ "debounce: port %d: total %dms stable %dms status 0x%x\n",
+ port1, 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;
+}
+
+/* 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. For a
+ * newly detected device that is not accessible through any global
+ * pointers, it's not necessary to lock the device.
+ */
+static int
+hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ int retry_counter)
+{
+ static DEFINE_MUTEX(usb_address0_mutex);
+
+ struct usb_device *hdev = hub->hdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ int i, j, retval;
+ unsigned delay = HUB_SHORT_RESET_TIME;
+ enum usb_device_speed oldspeed = udev->speed;
+ const char *speed;
+ int devnum = udev->devnum;
+
+ /* 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;
+
+ mutex_lock(&usb_address0_mutex);
+
+ /* 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;
+
+ if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+ 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:
+ 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);
+
+ 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, udev->bus->controller->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 (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
+ if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
+ struct usb_device_descriptor *buf;
+ int r = 0;
+
+#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 (j = 0; j < 3; ++j) {
+ 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;
+ }
+ if (r == 0)
+ 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) {
+ 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 (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+ retval = hub_set_address(udev, devnum);
+ if (retval >= 0)
+ break;
+ msleep(200);
+ }
+ if (retval < 0) {
+ 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 USB device number %d using %s\n",
+ (udev->config) ? "reset" : "new",
+ devnum, udev->bus->controller->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);
+ if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
+ break;
+ }
+
+ retval = usb_get_device_descriptor(udev, 8);
+ if (retval < 8) {
+ dev_err(&udev->dev,
+ "device descriptor read/8, error %d\n",
+ retval);
+ if (retval >= 0)
+ retval = -EMSGSIZE;
+ } else {
+ 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)) {
+ dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+ retval);
+ if (retval >= 0)
+ retval = -ENOMSG;
+ goto fail;
+ }
+
+ if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
+ retval = usb_get_bos_descriptor(udev);
+ if (!retval) {
+ if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
+ le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+ udev->lpm_capable = 1;
+ }
+ }
+
+ retval = 0;
+ /* notify HCD that we have a device connected and addressed */
+ if (hcd->driver->update_device)
+ hcd->driver->update_device(hcd, udev);
+fail:
+ if (retval) {
+ hub_port_disable(hub, port1, 0);
+ update_devnum(udev, devnum); /* for disconnect processing */
+ }
+ mutex_unlock(&usb_address0_mutex);
+ return retval;
+}
+
+static void
+check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
+{
+ struct usb_qualifier_descriptor *qual;
+ int status;
+
+ 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;
+ schedule_delayed_work (&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_device *udev = hdev->children[port1 - 1];
+ int delta;
+
+ if (!udev)
+ continue;
+
+ /* Unconfigured devices may not use more than 100mA,
+ * or 8mA for OTG ports */
+ if (udev->actconfig)
+ delta = udev->actconfig->desc.bMaxPower * 2;
+ else if (port1 != udev->bus->otg_port || hdev->parent)
+ delta = 100;
+ else
+ delta = 8;
+ if (delta > hub->mA_per_port)
+ dev_warn(&udev->dev,
+ "%dmA is over %umA budget for port %d!\n",
+ delta, hub->mA_per_port, port1);
+ remaining -= delta;
+ }
+ if (remaining < 0) {
+ dev_warn(hub->intfdev, "%dmA over power budget!\n",
+ - remaining);
+ remaining = 0;
+ }
+ return remaining;
+}
+
+/* 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)
+{
+ struct usb_device *hdev = hub->hdev;
+ struct device *hub_dev = hub->intfdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ unsigned wHubCharacteristics =
+ le16_to_cpu(hub->descriptor->wHubCharacteristics);
+ struct usb_device *udev;
+ int status, i;
+
+ dev_dbg (hub_dev,
+ "port %d, status %04x, change %04x, %s\n",
+ port1, 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 (hdev->bus->is_b_host)
+ portchange &= ~(USB_PORT_STAT_C_CONNECTION |
+ USB_PORT_STAT_C_ENABLE);
+#endif
+
+ /* Try to resuscitate an existing device */
+ udev = hdev->children[port1-1];
+ if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
+ udev->state != USB_STATE_NOTATTACHED) {
+ usb_lock_device(udev);
+ if (portstatus & USB_PORT_STAT_ENABLE) {
+ status = 0; /* Nothing to do */
+
+#ifdef CONFIG_USB_SUSPEND
+ } else if (udev->state == USB_STATE_SUSPENDED &&
+ udev->persist_enabled) {
+ /* For a suspended device, treat this as a
+ * remote wakeup event.
+ */
+ status = usb_remote_wakeup(udev);
+#endif
+
+ } else {
+ status = -ENODEV; /* Don't resuscitate */
+ }
+ usb_unlock_device(udev);
+
+ if (status == 0) {
+ clear_bit(port1, hub->change_bits);
+ return;
+ }
+ }
+
+ /* Disconnect any existing devices under this port */
+ if (udev)
+ usb_disconnect(&hdev->children[port1-1]);
+ clear_bit(port1, hub->change_bits);
+
+ /* 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(hub, port1);
+ if (status < 0) {
+ if (printk_ratelimit())
+ dev_err(hub_dev, "connect-debounce failed, "
+ "port %d disabled\n", port1);
+ portstatus &= ~USB_PORT_STAT_CONNECTION;
+ } 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) */
+ if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
+ && !port_is_power_on(hub, portstatus))
+ set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ goto done;
+ return;
+ }
+
+ for (i = 0; i < SET_CONFIG_TRIES; i++) {
+
+ /* 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 (hub_dev,
+ "couldn't allocate port %d usb_device\n",
+ port1);
+ 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);
+
+ /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
+ 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;
+
+ usb_detect_quirks(udev);
+ if (udev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(1000);
+
+ /* 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 <= 100) {
+ u16 devstat;
+
+ status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
+ &devstat);
+ if (status < 2) {
+ dev_dbg(&udev->dev, "get status %d ?\n", status);
+ goto loop_disable;
+ }
+ le16_to_cpus(&devstat);
+ 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;
+ schedule_delayed_work (&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;
+
+ /* 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
+ hdev->children[port1-1] = udev;
+ spin_unlock_irq(&device_state_lock);
+
+ /* Run it through the hoops (find a driver, etc) */
+ if (!status) {
+ status = usb_new_device(udev);
+ if (status) {
+ spin_lock_irq(&device_state_lock);
+ hdev->children[port1-1] = NULL;
+ spin_unlock_irq(&device_state_lock);
+ }
+ }
+
+ if (status)
+ goto loop_disable;
+
+ status = hub_power_remaining(hub);
+ if (status)
+ dev_dbg(hub_dev, "%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);
+ usb_put_dev(udev);
+ if ((status == -ENOTCONN) || (status == -ENOTSUPP))
+ break;
+ }
+ if (hub->hdev->parent ||
+ !hcd->driver->port_handed_over ||
+ !(hcd->driver->port_handed_over)(hcd, port1))
+ dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
+ port1);
+
+done:
+ hub_port_disable(hub, port1, 1);
+ if (hcd->driver->relinquish_port && !hub->hdev->parent)
+ hcd->driver->relinquish_port(hcd, port1);
+}
+
+/* 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)
+{
+ struct usb_device *hdev;
+ struct usb_device *udev;
+ int connect_change = 0;
+ int ret;
+
+ hdev = hub->hdev;
+ udev = hdev->children[port-1];
+ if (!hub_is_superspeed(hdev)) {
+ if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+ return 0;
+ clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+ } else {
+ if (!udev || udev->state != USB_STATE_SUSPENDED ||
+ (portstatus & USB_PORT_STAT_LINK_STATE) !=
+ USB_SS_PORT_LS_U0)
+ return 0;
+ }
+
+ if (udev) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+
+ usb_lock_device(udev);
+ ret = usb_remote_wakeup(udev);
+ usb_unlock_device(udev);
+ if (ret < 0)
+ connect_change = 1;
+ } else {
+ ret = -ENODEV;
+ hub_port_disable(hub, port, 1);
+ }
+ dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
+ port, ret);
+ return connect_change;
+}
+
+static void hub_events(void)
+{
+ struct list_head *tmp;
+ struct usb_device *hdev;
+ struct usb_interface *intf;
+ struct usb_hub *hub;
+ struct device *hub_dev;
+ u16 hubstatus;
+ u16 hubchange;
+ u16 portstatus;
+ u16 portchange;
+ int i, ret,j = 0;
+ int connect_change, wakeup_change;
+
+ /*
+ * We restart the list every time to avoid a deadlock with
+ * deleting hubs downstream from this one. This should be
+ * safe since we delete the hub from the event list.
+ * Not the most efficient, but avoids deadlocks.
+ */
+ while (1) {
+
+ /* Grab the first entry at the beginning of the list */
+ spin_lock_irq(&hub_event_lock);
+ if (list_empty(&hub_event_list)) {
+ spin_unlock_irq(&hub_event_lock);
+ break;
+ }
+
+ tmp = hub_event_list.next;
+ list_del_init(tmp);
+
+ hub = list_entry(tmp, struct usb_hub, event_list);
+ kref_get(&hub->kref);
+ spin_unlock_irq(&hub_event_lock);
+
+ 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, hub->descriptor
+ ? hub->descriptor->bNbrPorts
+ : 0,
+ /* 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 loop_disconnected;
+
+ /* If the hub has died, clean up after it */
+ if (hdev->state == USB_STATE_NOTATTACHED) {
+ hub->error = -ENODEV;
+ hub_quiesce(hub, HUB_DISCONNECT);
+ goto loop;
+ }
+
+ /* Autoresume */
+ ret = usb_autopm_get_interface(intf);
+ if (ret) {
+ dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
+ goto loop;
+ }
+
+ /* If this is an inactive hub, do nothing */
+ if (hub->quiescing)
+ goto loop_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 loop_autopm;
+ }
+
+ hub->nerrors = 0;
+ hub->error = 0;
+ }
+
+ /* deal with other port status changes */
+
+ //for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+ for (j = 1; j <= hub->descriptor->bNbrPorts; j++) {
+ i = j;
+ if (hub->descriptor->bNbrPorts > 2 ) {
+ if (usb_storage_id)
+ i = (j + usb_storage_id -2 ) % hub->descriptor->bNbrPorts + 1 ;
+
+ };
+
+
+ if (test_bit(i, hub->busy_bits))
+ continue;
+ connect_change = test_bit(i, hub->change_bits);
+ wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
+ if (!test_and_clear_bit(i, hub->event_bits) &&
+ !connect_change && !wakeup_change)
+ continue;
+
+ ret = hub_port_status(hub, i,
+ &portstatus, &portchange);
+ if (ret < 0)
+ continue;
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ clear_port_feature(hdev, i,
+ USB_PORT_FEAT_C_CONNECTION);
+ connect_change = 1;
+ }
+
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ if (!connect_change)
+ dev_dbg (hub_dev,
+ "port %d enable change, "
+ "status %08x\n",
+ i, portstatus);
+ clear_port_feature(hdev, i,
+ 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
+ && hdev->children[i-1]) {
+ dev_err (hub_dev,
+ "port %i "
+ "disabled by hub (EMI?), "
+ "re-enabling...\n",
+ i);
+ connect_change = 1;
+ }
+ }
+
+ if (hub_handle_remote_wakeup(hub, i,
+ portstatus, portchange))
+ connect_change = 1;
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ u16 status = 0;
+ u16 unused;
+
+ dev_dbg(hub_dev, "over-current change on port "
+ "%d\n", i);
+ clear_port_feature(hdev, i,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ msleep(100); /* Cool down */
+ hub_power_on(hub, true);
+ hub_port_status(hub, i, &status, &unused);
+ if (status & USB_PORT_STAT_OVERCURRENT)
+ dev_err(hub_dev, "over-current "
+ "condition on port %d\n", i);
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ dev_dbg (hub_dev,
+ "reset change on port %d\n",
+ i);
+ clear_port_feature(hdev, i,
+ USB_PORT_FEAT_C_RESET);
+ }
+ if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
+ hub_is_superspeed(hub->hdev)) {
+ dev_dbg(hub_dev,
+ "warm reset change on port %d\n",
+ i);
+ clear_port_feature(hdev, i,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ }
+ if (portchange & USB_PORT_STAT_C_LINK_STATE) {
+ clear_port_feature(hub->hdev, i,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ }
+ if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
+ dev_warn(hub_dev,
+ "config error on port %d\n",
+ i);
+ clear_port_feature(hub->hdev, i,
+ USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
+ }
+
+ /* Warm reset a USB3 protocol port if it's in
+ * SS.Inactive state.
+ */
+ if (hub_port_warm_reset_required(hub, portstatus)) {
+ dev_dbg(hub_dev, "warm reset port %d\n", i);
+ hub_port_reset(hub, i, NULL,
+ HUB_BH_RESET_TIME, true);
+ }
+
+ if (connect_change)
+ hub_port_connect_change(hub, i,
+ portstatus, portchange);
+ } /* end for i */
+
+ /* 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");
+ }
+ }
+
+ loop_autopm:
+ /* Balance the usb_autopm_get_interface() above */
+ usb_autopm_put_interface_no_suspend(intf);
+ loop:
+ /* Balance the usb_autopm_get_interface_no_resume() in
+ * kick_khubd() and allow autosuspend.
+ */
+ usb_autopm_put_interface(intf);
+ loop_disconnected:
+ usb_unlock_device(hdev);
+ kref_put(&hub->kref, hub_release);
+
+ } /* end while (1) */
+}
+
+static int hub_thread(void *__unused)
+{
+ /* khubd needs to be freezable to avoid intefering 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.
+ */
+ set_freezable();
+
+ do {
+ hub_events();
+ wait_event_freezable(khubd_wait,
+ !list_empty(&hub_event_list) ||
+ kthread_should_stop());
+ } while (!kthread_should_stop() || !list_empty(&hub_event_list));
+
+ pr_debug("%s: khubd exiting\n", usbcore_name);
+ return 0;
+}
+
+static const struct usb_device_id hub_id_table[] = {
+ { .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;
+ }
+
+ khubd_task = kthread_run(hub_thread, NULL, "khubd");
+ if (!IS_ERR(khubd_task))
+ return 0;
+
+ /* Fall through if kernel_thread failed */
+ usb_deregister(&hub_driver);
+ printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
+
+ return -1;
+}
+
+void usb_hub_cleanup(void)
+{
+ kthread_stop(khubd_task);
+
+ /*
+ * 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)
+{
+ 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;
+
+ /* 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 == NULL) {
+ dev_err(&udev->dev, "no mem to re-read configs after reset\n");
+ /* 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 khubd 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.
+ *
+ * Returns 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.
+ *
+ * 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().
+ *
+ * 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.
+ */
+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;
+ int i, 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) {
+ /* this requires hcd-specific logic; see ohci_restart() */
+ dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
+ return -EISDIR;
+ }
+ parent_hub = hdev_to_hub(parent_hdev);
+
+ set_bit(port1, parent_hub->busy_bits);
+ 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;
+ }
+ clear_bit(port1, parent_hub->busy_bits);
+
+ if (ret < 0)
+ goto re_enumerate;
+
+ /* Device might have changed firmware (DFU or similar) */
+ if (descriptors_changed(udev, &descriptor)) {
+ 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;
+ }
+ }
+
+done:
+ return 0;
+
+re_enumerate:
+ 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 SUSPENDED or 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 value is the same as for usb_reset_and_verify_device().
+ *
+ * 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;
+ struct usb_host_config *config = udev->actconfig;
+
+ 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;
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ ret = usb_reset_and_verify_device(udev);
+
+ 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 (ret == 0 && rebind)
+ usb_rebind_intf(cintf);
+ }
+ }
+
+ usb_autosuspend_device(udev);
+ 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 a driver is unbound and it had a pending reset, the reset will
+ * be cancelled.
+ *
+ * - This function can be called during .probe() or .disconnect()
+ * times. On return from .disconnect(), any pending resets will be
+ * cancelled.
+ *
+ * There is no no need to lock/unlock the @reset_ws as schedule_work()
+ * does its own.
+ *
+ * NOTE: We don't do any reference count tracking because it is not
+ * needed. The lifecycle of the work_struct is tied to the
+ * usb_interface. Before destroying the interface we cancel the
+ * work_struct, so the fact that work_struct is queued and or
+ * running means the interface (and thus, the device) exist and
+ * are referenced.
+ */
+void usb_queue_reset_device(struct usb_interface *iface)
+{
+ schedule_work(&iface->reset_ws);
+}
+EXPORT_SYMBOL_GPL(usb_queue_reset_device);
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
new file mode 100644
index 00000000..d2b9af59
--- /dev/null
+++ b/drivers/usb/core/inode.c
@@ -0,0 +1,748 @@
+/*****************************************************************************/
+
+/*
+ * inode.c -- Inode/Dentry functions for the USB device file system.
+ *
+ * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ * 0.1 04.01.2000 Created
+ * 0.2 10.12.2001 converted to use the vfs layer better
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+#include <linux/namei.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/parser.h>
+#include <linux/notifier.h>
+#include <linux/seq_file.h>
+#include <linux/usb/hcd.h>
+#include <asm/byteorder.h>
+#include "usb.h"
+
+#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
+#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
+#define USBFS_DEFAULT_LISTMODE S_IRUGO
+
+static const struct file_operations default_file_operations;
+static struct vfsmount *usbfs_mount;
+static int usbfs_mount_count; /* = 0 */
+
+static struct dentry *devices_usbfs_dentry;
+static int num_buses; /* = 0 */
+
+static uid_t devuid; /* = 0 */
+static uid_t busuid; /* = 0 */
+static uid_t listuid; /* = 0 */
+static gid_t devgid; /* = 0 */
+static gid_t busgid; /* = 0 */
+static gid_t listgid; /* = 0 */
+static umode_t devmode = USBFS_DEFAULT_DEVMODE;
+static umode_t busmode = USBFS_DEFAULT_BUSMODE;
+static umode_t listmode = USBFS_DEFAULT_LISTMODE;
+
+static int usbfs_show_options(struct seq_file *seq, struct dentry *root)
+{
+ if (devuid != 0)
+ seq_printf(seq, ",devuid=%u", devuid);
+ if (devgid != 0)
+ seq_printf(seq, ",devgid=%u", devgid);
+ if (devmode != USBFS_DEFAULT_DEVMODE)
+ seq_printf(seq, ",devmode=%o", devmode);
+ if (busuid != 0)
+ seq_printf(seq, ",busuid=%u", busuid);
+ if (busgid != 0)
+ seq_printf(seq, ",busgid=%u", busgid);
+ if (busmode != USBFS_DEFAULT_BUSMODE)
+ seq_printf(seq, ",busmode=%o", busmode);
+ if (listuid != 0)
+ seq_printf(seq, ",listuid=%u", listuid);
+ if (listgid != 0)
+ seq_printf(seq, ",listgid=%u", listgid);
+ if (listmode != USBFS_DEFAULT_LISTMODE)
+ seq_printf(seq, ",listmode=%o", listmode);
+
+ return 0;
+}
+
+enum {
+ Opt_devuid, Opt_devgid, Opt_devmode,
+ Opt_busuid, Opt_busgid, Opt_busmode,
+ Opt_listuid, Opt_listgid, Opt_listmode,
+ Opt_err,
+};
+
+static const match_table_t tokens = {
+ {Opt_devuid, "devuid=%u"},
+ {Opt_devgid, "devgid=%u"},
+ {Opt_devmode, "devmode=%o"},
+ {Opt_busuid, "busuid=%u"},
+ {Opt_busgid, "busgid=%u"},
+ {Opt_busmode, "busmode=%o"},
+ {Opt_listuid, "listuid=%u"},
+ {Opt_listgid, "listgid=%u"},
+ {Opt_listmode, "listmode=%o"},
+ {Opt_err, NULL}
+};
+
+static int parse_options(struct super_block *s, char *data)
+{
+ char *p;
+ int option;
+
+ /* (re)set to defaults. */
+ devuid = 0;
+ busuid = 0;
+ listuid = 0;
+ devgid = 0;
+ busgid = 0;
+ listgid = 0;
+ devmode = USBFS_DEFAULT_DEVMODE;
+ busmode = USBFS_DEFAULT_BUSMODE;
+ listmode = USBFS_DEFAULT_LISTMODE;
+
+ while ((p = strsep(&data, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ int token;
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_devuid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ devuid = option;
+ break;
+ case Opt_devgid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ devgid = option;
+ break;
+ case Opt_devmode:
+ if (match_octal(&args[0], &option))
+ return -EINVAL;
+ devmode = option & S_IRWXUGO;
+ break;
+ case Opt_busuid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ busuid = option;
+ break;
+ case Opt_busgid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ busgid = option;
+ break;
+ case Opt_busmode:
+ if (match_octal(&args[0], &option))
+ return -EINVAL;
+ busmode = option & S_IRWXUGO;
+ break;
+ case Opt_listuid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ listuid = option;
+ break;
+ case Opt_listgid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ listgid = option;
+ break;
+ case Opt_listmode:
+ if (match_octal(&args[0], &option))
+ return -EINVAL;
+ listmode = option & S_IRWXUGO;
+ break;
+ default:
+ printk(KERN_ERR "usbfs: unrecognised mount option "
+ "\"%s\" or missing value\n", p);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void update_special(struct dentry *special)
+{
+ special->d_inode->i_uid = listuid;
+ special->d_inode->i_gid = listgid;
+ special->d_inode->i_mode = S_IFREG | listmode;
+}
+
+static void update_dev(struct dentry *dev)
+{
+ dev->d_inode->i_uid = devuid;
+ dev->d_inode->i_gid = devgid;
+ dev->d_inode->i_mode = S_IFREG | devmode;
+}
+
+static void update_bus(struct dentry *bus)
+{
+ struct dentry *dev = NULL;
+
+ bus->d_inode->i_uid = busuid;
+ bus->d_inode->i_gid = busgid;
+ bus->d_inode->i_mode = S_IFDIR | busmode;
+
+ mutex_lock(&bus->d_inode->i_mutex);
+
+ list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
+ if (dev->d_inode)
+ update_dev(dev);
+
+ mutex_unlock(&bus->d_inode->i_mutex);
+}
+
+static void update_sb(struct super_block *sb)
+{
+ struct dentry *root = sb->s_root;
+ struct dentry *bus = NULL;
+
+ if (!root)
+ return;
+
+ mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
+
+ list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
+ if (bus->d_inode) {
+ switch (S_IFMT & bus->d_inode->i_mode) {
+ case S_IFDIR:
+ update_bus(bus);
+ break;
+ case S_IFREG:
+ update_special(bus);
+ break;
+ default:
+ printk(KERN_WARNING "usbfs: Unknown node %s "
+ "mode %x found on remount!\n",
+ bus->d_name.name, bus->d_inode->i_mode);
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&root->d_inode->i_mutex);
+}
+
+static int remount(struct super_block *sb, int *flags, char *data)
+{
+ /* If this is not a real mount,
+ * i.e. it's a simple_pin_fs from create_special_files,
+ * then ignore it.
+ */
+ if (*flags & MS_KERNMOUNT)
+ return 0;
+
+ if (parse_options(sb, data)) {
+ printk(KERN_WARNING "usbfs: mount parameter error.\n");
+ return -EINVAL;
+ }
+
+ if (usbfs_mount)
+ update_sb(usbfs_mount->mnt_sb);
+
+ return 0;
+}
+
+static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode) {
+ inode->i_ino = get_next_ino();
+ inode_init_owner(inode, NULL, mode);
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ default:
+ init_special_inode(inode, mode, dev);
+ break;
+ case S_IFREG:
+ inode->i_fop = &default_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inc_nlink(inode);
+ break;
+ }
+ }
+ return inode;
+}
+
+/* SMP-safe */
+static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t dev)
+{
+ struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
+ int error = -EPERM;
+
+ if (dentry->d_inode)
+ return -EEXIST;
+
+ if (inode) {
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ error = 0;
+ }
+ return error;
+}
+
+static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ int res;
+
+ mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ res = usbfs_mknod (dir, dentry, mode, 0);
+ if (!res)
+ inc_nlink(dir);
+ return res;
+}
+
+static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+ mode = (mode & S_IALLUGO) | S_IFREG;
+ return usbfs_mknod (dir, dentry, mode, 0);
+}
+
+static inline int usbfs_positive (struct dentry *dentry)
+{
+ return dentry->d_inode && !d_unhashed(dentry);
+}
+
+static int usbfs_empty (struct dentry *dentry)
+{
+ struct list_head *list;
+
+ spin_lock(&dentry->d_lock);
+ list_for_each(list, &dentry->d_subdirs) {
+ struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
+
+ spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
+ if (usbfs_positive(de)) {
+ spin_unlock(&de->d_lock);
+ spin_unlock(&dentry->d_lock);
+ return 0;
+ }
+ spin_unlock(&de->d_lock);
+ }
+ spin_unlock(&dentry->d_lock);
+ return 1;
+}
+
+static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ mutex_lock(&inode->i_mutex);
+ drop_nlink(dentry->d_inode);
+ dput(dentry);
+ mutex_unlock(&inode->i_mutex);
+ d_delete(dentry);
+ return 0;
+}
+
+static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int error = -ENOTEMPTY;
+ struct inode * inode = dentry->d_inode;
+
+ mutex_lock(&inode->i_mutex);
+ dentry_unhash(dentry);
+ if (usbfs_empty(dentry)) {
+ dont_mount(dentry);
+ drop_nlink(dentry->d_inode);
+ drop_nlink(dentry->d_inode);
+ dput(dentry);
+ inode->i_flags |= S_DEAD;
+ drop_nlink(dir);
+ error = 0;
+ }
+ mutex_unlock(&inode->i_mutex);
+ if (!error)
+ d_delete(dentry);
+ return error;
+}
+
+
+/* default file operations */
+static ssize_t default_read_file (struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static ssize_t default_write_file (struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
+{
+ loff_t retval = -EINVAL;
+
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
+ switch(orig) {
+ case 0:
+ if (offset > 0) {
+ file->f_pos = offset;
+ retval = file->f_pos;
+ }
+ break;
+ case 1:
+ if ((offset + file->f_pos) > 0) {
+ file->f_pos += offset;
+ retval = file->f_pos;
+ }
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
+ return retval;
+}
+
+static const struct file_operations default_file_operations = {
+ .read = default_read_file,
+ .write = default_write_file,
+ .open = simple_open,
+ .llseek = default_file_lseek,
+};
+
+static const struct super_operations usbfs_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+ .remount_fs = remount,
+ .show_options = usbfs_show_options,
+};
+
+static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *inode;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = USBDEVICE_SUPER_MAGIC;
+ sb->s_op = &usbfs_ops;
+ sb->s_time_gran = 1;
+ inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
+ sb->s_root = d_make_root(inode);
+ if (!sb->s_root) {
+ dbg("%s: could not get root dentry!",__func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * fs_create_by_name - create a file, given a name
+ * @name: name of file
+ * @mode: type of file
+ * @parent: dentry of directory to create it in
+ * @dentry: resulting dentry of file
+ *
+ * This function handles both regular files and directories.
+ */
+static int fs_create_by_name (const char *name, umode_t mode,
+ struct dentry *parent, struct dentry **dentry)
+{
+ int error = 0;
+
+ /* If the parent is not specified, we create it in the root.
+ * We need the root dentry to do this, which is in the super
+ * block. A pointer to that is in the struct vfsmount that we
+ * have around.
+ */
+ if (!parent ) {
+ if (usbfs_mount)
+ parent = usbfs_mount->mnt_root;
+ }
+
+ if (!parent) {
+ dbg("Ah! can not find a parent!");
+ return -EFAULT;
+ }
+
+ *dentry = NULL;
+ mutex_lock(&parent->d_inode->i_mutex);
+ *dentry = lookup_one_len(name, parent, strlen(name));
+ if (!IS_ERR(*dentry)) {
+ if (S_ISDIR(mode))
+ error = usbfs_mkdir (parent->d_inode, *dentry, mode);
+ else
+ error = usbfs_create (parent->d_inode, *dentry, mode);
+ } else
+ error = PTR_ERR(*dentry);
+ mutex_unlock(&parent->d_inode->i_mutex);
+
+ return error;
+}
+
+static struct dentry *fs_create_file (const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ uid_t uid, gid_t gid)
+{
+ struct dentry *dentry;
+ int error;
+
+ dbg("creating file '%s'",name);
+
+ error = fs_create_by_name (name, mode, parent, &dentry);
+ if (error) {
+ dentry = NULL;
+ } else {
+ if (dentry->d_inode) {
+ if (data)
+ dentry->d_inode->i_private = data;
+ if (fops)
+ dentry->d_inode->i_fop = fops;
+ dentry->d_inode->i_uid = uid;
+ dentry->d_inode->i_gid = gid;
+ }
+ }
+
+ return dentry;
+}
+
+static void fs_remove_file (struct dentry *dentry)
+{
+ struct dentry *parent = dentry->d_parent;
+
+ if (!parent || !parent->d_inode)
+ return;
+
+ mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT);
+ if (usbfs_positive(dentry)) {
+ if (dentry->d_inode) {
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ usbfs_rmdir(parent->d_inode, dentry);
+ else
+ usbfs_unlink(parent->d_inode, dentry);
+ dput(dentry);
+ }
+ }
+ mutex_unlock(&parent->d_inode->i_mutex);
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct dentry *usb_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ return mount_single(fs_type, flags, data, usbfs_fill_super);
+}
+
+static struct file_system_type usb_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "usbfs",
+ .mount = usb_mount,
+ .kill_sb = kill_litter_super,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int create_special_files (void)
+{
+ struct dentry *parent;
+ int retval;
+
+ /* create the devices special file */
+ retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
+ if (retval) {
+ printk(KERN_ERR "Unable to get usbfs mount\n");
+ goto exit;
+ }
+
+ parent = usbfs_mount->mnt_root;
+ devices_usbfs_dentry = fs_create_file ("devices",
+ listmode | S_IFREG, parent,
+ NULL, &usbfs_devices_fops,
+ listuid, listgid);
+ if (devices_usbfs_dentry == NULL) {
+ printk(KERN_ERR "Unable to create devices usbfs file\n");
+ retval = -ENODEV;
+ goto error_clean_mounts;
+ }
+
+ goto exit;
+
+error_clean_mounts:
+ simple_release_fs(&usbfs_mount, &usbfs_mount_count);
+exit:
+ return retval;
+}
+
+static void remove_special_files (void)
+{
+ if (devices_usbfs_dentry)
+ fs_remove_file (devices_usbfs_dentry);
+ devices_usbfs_dentry = NULL;
+ simple_release_fs(&usbfs_mount, &usbfs_mount_count);
+}
+
+void usbfs_update_special (void)
+{
+ struct inode *inode;
+
+ if (devices_usbfs_dentry) {
+ inode = devices_usbfs_dentry->d_inode;
+ if (inode)
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
+}
+
+static void usbfs_add_bus(struct usb_bus *bus)
+{
+ struct dentry *parent;
+ char name[8];
+ int retval;
+
+ /* create the special files if this is the first bus added */
+ if (num_buses == 0) {
+ retval = create_special_files();
+ if (retval)
+ return;
+ }
+ ++num_buses;
+
+ sprintf (name, "%03d", bus->busnum);
+
+ parent = usbfs_mount->mnt_root;
+ bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
+ bus, NULL, busuid, busgid);
+ if (bus->usbfs_dentry == NULL) {
+ printk(KERN_ERR "Error creating usbfs bus entry\n");
+ return;
+ }
+}
+
+static void usbfs_remove_bus(struct usb_bus *bus)
+{
+ if (bus->usbfs_dentry) {
+ fs_remove_file (bus->usbfs_dentry);
+ bus->usbfs_dentry = NULL;
+ }
+
+ --num_buses;
+ if (num_buses <= 0) {
+ remove_special_files();
+ num_buses = 0;
+ }
+}
+
+static void usbfs_add_device(struct usb_device *dev)
+{
+ char name[8];
+ int i;
+ int i_size;
+
+ sprintf (name, "%03d", dev->devnum);
+ dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
+ dev->bus->usbfs_dentry, dev,
+ &usbdev_file_operations,
+ devuid, devgid);
+ if (dev->usbfs_dentry == NULL) {
+ printk(KERN_ERR "Error creating usbfs device entry\n");
+ return;
+ }
+
+ /* Set the size of the device's file to be
+ * equal to the size of the device descriptors. */
+ i_size = sizeof (struct usb_device_descriptor);
+ for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
+ struct usb_config_descriptor *config =
+ (struct usb_config_descriptor *)dev->rawdescriptors[i];
+ i_size += le16_to_cpu(config->wTotalLength);
+ }
+ if (dev->usbfs_dentry->d_inode)
+ dev->usbfs_dentry->d_inode->i_size = i_size;
+}
+
+static void usbfs_remove_device(struct usb_device *dev)
+{
+ if (dev->usbfs_dentry) {
+ fs_remove_file (dev->usbfs_dentry);
+ dev->usbfs_dentry = NULL;
+ }
+}
+
+static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
+{
+ switch (action) {
+ case USB_DEVICE_ADD:
+ usbfs_add_device(dev);
+ break;
+ case USB_DEVICE_REMOVE:
+ usbfs_remove_device(dev);
+ break;
+ case USB_BUS_ADD:
+ usbfs_add_bus(dev);
+ break;
+ case USB_BUS_REMOVE:
+ usbfs_remove_bus(dev);
+ }
+
+ usbfs_update_special();
+ usbfs_conn_disc_event();
+ return NOTIFY_OK;
+}
+
+static struct notifier_block usbfs_nb = {
+ .notifier_call = usbfs_notify,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct proc_dir_entry *usbdir = NULL;
+
+int __init usbfs_init(void)
+{
+ int retval;
+
+ retval = register_filesystem(&usb_fs_type);
+ if (retval)
+ return retval;
+
+ usb_register_notify(&usbfs_nb);
+
+ /* create mount point for usbfs */
+ usbdir = proc_mkdir("bus/usb", NULL);
+
+ return 0;
+}
+
+void usbfs_cleanup(void)
+{
+ usb_unregister_notify(&usbfs_nb);
+ unregister_filesystem(&usb_fs_type);
+ if (usbdir)
+ remove_proc_entry("bus/usb", NULL);
+}
+
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
new file mode 100644
index 00000000..ef116a55
--- /dev/null
+++ b/drivers/usb/core/message.c
@@ -0,0 +1,1952 @@
+/*
+ * message.c - synchronous message handling
+ */
+
+#include <linux/pci.h> /* for scatterlist macros */
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.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/quirks.h>
+#include <linux/usb/hcd.h> /* for usbcore internals */
+#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.
+ *
+ * If successful, it returns the number of bytes transferred, otherwise a
+ * negative error number.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler. 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.
+ */
+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);
+
+ /* dbg("usb_control_msg"); */
+
+ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+ 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.
+ *
+ * If successful, it returns 0, otherwise a negative error number. The number
+ * of actual bytes transferred will be stored in the actual_length paramater.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler. 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.
+ */
+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.
+ *
+ * If successful, it returns 0, otherwise a negative error number. The number
+ * of actual bytes transferred will be stored in the actual_length paramater.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler. 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.
+ */
+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)
+{
+ struct usb_sg_request *io = urb->context;
+ int status = urb->status;
+
+ spin_lock(&io->lock);
+
+ /* 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(&io->lock);
+ for (i = 0, found = 0; i < io->entries; i++) {
+ if (!io->urbs [i] || !io->urbs [i]->dev)
+ continue;
+ if (found) {
+ 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(&io->lock);
+ }
+
+ /* on the last completion, signal usb_sg_wait() */
+ io->bytes += urb->actual_length;
+ io->count--;
+ if (!io->count)
+ complete(&io->complete);
+
+ spin_unlock(&io->lock);
+}
+
+
+/**
+ * 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
+ *
+ * Returns zero for success, else a negative errno value. 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.
+ */
+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(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;
+ retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
+
+ /* after we submit, let completions or cancelations fire;
+ * we handshake using io->status.
+ */
+ spin_unlock_irq(&io->lock);
+ 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;
+
+ spin_lock_irqsave(&io->lock, flags);
+
+ /* shut everything down, if it didn't already */
+ if (!io->status) {
+ int i;
+
+ io->status = -ECONNRESET;
+ spin_unlock(&io->lock);
+ for (i = 0; i < io->entries; i++) {
+ int retval;
+
+ if (!io->urbs [i]->dev)
+ continue;
+ 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(&io->lock);
+ }
+ 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.
+ *
+ * Returns 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.
+ *
+ * Returns 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,
+ "string descriptor 0 malformed (err = %d), "
+ "defaulting to 0x%04x\n",
+ err, dev->string_langid);
+ 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_err(&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.
+ *
+ * Returns 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 || !index)
+ return -EINVAL;
+ buf[0] = 0;
+ 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
+ *
+ * Returns 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.
+ *
+ * Returns 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_get_status - issues a GET_STATUS call
+ * @dev: the device whose status is being checked
+ * @type: USB_RECIP_*; for device, interface, or endpoint
+ * @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 the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_status(struct usb_device *dev, int type, int target, void *data)
+{
+ int ret;
+ u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+
+ if (!status)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
+ sizeof(*status), USB_CTRL_GET_TIMEOUT);
+
+ *(u16 *)data = *status;
+ 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.
+ *
+ * Returns 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)
+ dev->ep_out[epnum] = NULL;
+ } else {
+ ep = dev->ep_in[epnum];
+ if (reset_hardware)
+ 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 - 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;
+ struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+
+ /* 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;
+ }
+ 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");
+ 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_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.
+ *
+ * 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).
+ *
+ * Returns 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 ret;
+ int 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;
+ }
+
+ /* 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);
+ 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);
+ 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);
+ 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;
+
+ /* 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) {
+ int i;
+
+ 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.
+ *
+ * Returns zero on success, else a negative error code.
+ */
+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
+ */
+
+ for (i = 1; i < 16; ++i) {
+ usb_disable_endpoint(dev, i, true);
+ usb_disable_endpoint(dev, i + USB_DIR_IN, true);
+ }
+
+ config = dev->actconfig;
+ retval = 0;
+ mutex_lock(hcd->bandwidth_mutex);
+ /* Make sure we have enough bandwidth for each alternate setting 0 */
+ 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);
+ if (!alt)
+ alt = &intf->altsetting[0];
+ if (alt != intf->cur_altsetting)
+ retval = usb_hcd_alloc_bandwidth(dev, NULL,
+ intf->cur_altsetting, alt);
+ if (retval < 0)
+ break;
+ }
+ /* If not, reinstate the old alternate settings */
+ if (retval < 0) {
+reset_old_alts:
+ for (i--; i >= 0; i--) {
+ struct usb_interface *intf = config->interface[i];
+ struct usb_host_interface *alt;
+
+ alt = usb_altnum_to_altsetting(intf, 0);
+ if (!alt)
+ alt = &intf->altsetting[0];
+ if (alt != intf->cur_altsetting)
+ usb_hcd_alloc_bandwidth(dev, NULL,
+ alt, intf->cur_altsetting);
+ }
+ 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)
+ goto reset_old_alts;
+ 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);
+ }
+ }
+ 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);
+ kfree(intf);
+}
+
+#ifdef CONFIG_HOTPLUG
+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%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))
+ return -ENOMEM;
+
+ return 0;
+}
+
+#else
+
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_HOTPLUG */
+
+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
+ *
+ * This is initialized into the workstruct in 'struct
+ * usb_device->reset_ws' that is launched by
+ * message.c:usb_set_configuration() when initializing each 'struct
+ * usb_interface'.
+ *
+ * It is safe to get the USB device without reference counts because
+ * the life cycle of @iface is bound to the life cycle of @udev. Then,
+ * this function will be ran only if @iface is alive (and before
+ * freeing it any scheduled instances of it will have been cancelled).
+ *
+ * We need to set a flag (usb_dev->reset_running) because when we call
+ * the reset, the interfaces might be unbound. The current interface
+ * cannot try to remove the queued work as it would cause a deadlock
+ * (you cannot remove your work from within your executing
+ * workqueue). This flag lets it know, so that
+ * usb_cancel_queued_reset() doesn't try to do it.
+ *
+ * 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) {
+ iface->reset_running = 1;
+ usb_reset_device(udev);
+ iface->reset_running = 0;
+ usb_unlock_device(udev);
+ }
+}
+
+
+/*
+ * 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(nintf * sizeof(*new_interfaces),
+ GFP_NOIO);
+ if (!new_interfaces) {
+ dev_err(&dev->dev, "Out of memory\n");
+ return -ENOMEM;
+ }
+
+ for (; n < nintf; ++n) {
+ new_interfaces[n] = kzalloc(
+ sizeof(struct usb_interface),
+ GFP_NOIO);
+ if (!new_interfaces[n]) {
+ dev_err(&dev->dev, "Out of memory\n");
+ ret = -ENOMEM;
+free_interfaces:
+ while (--n >= 0)
+ kfree(new_interfaces[n]);
+ kfree(new_interfaces);
+ return ret;
+ }
+ }
+
+ i = dev->bus_mA - cp->desc.bMaxPower * 2;
+ 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);
+ ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
+ if (ret < 0) {
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_autosuspend_device(dev);
+ goto free_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) {
+ /* All the old state is gone, so what else can we do?
+ * The device is probably useless now anyway.
+ */
+ cp = NULL;
+ }
+
+ dev->actconfig = cp;
+ if (!cp) {
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
+ usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_autosuspend_device(dev);
+ goto free_interfaces;
+ }
+ mutex_unlock(hcd->bandwidth_mutex);
+ usb_set_device_state(dev, USB_STATE_CONFIGURED);
+
+ /* 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;
+
+ cp->interface[i] = intf = new_interfaces[i];
+ intfc = cp->intf_cache[i];
+ intf->altsetting = intfc->altsetting;
+ intf->num_altsetting = intfc->num_altsetting;
+ 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];
+
+ intf->intf_assoc =
+ find_iad(dev, cp, alt->desc.bInterfaceNumber);
+ intf->cur_altsetting = alt;
+ usb_enable_interface(dev, intf, true);
+ intf->dev.parent = &dev->dev;
+ intf->dev.driver = NULL;
+ intf->dev.bus = &usb_bus_type;
+ intf->dev.type = &usb_if_device_type;
+ intf->dev.groups = usb_interface_groups;
+ intf->dev.dma_mask = dev->dev.dma_mask;
+ 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, alt->desc.bInterfaceNumber);
+ }
+ kfree(new_interfaces);
+
+ if (cp->string == NULL &&
+ !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+ cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
+
+ /* 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;
+}
+
+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.
+ *
+ * Returns 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);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
new file mode 100644
index 00000000..7728c91d
--- /dev/null
+++ b/drivers/usb/core/notify.c
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ */
+
+
+#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/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
new file mode 100644
index 00000000..e8cdce57
--- /dev/null
+++ b/drivers/usb/core/otg_whitelist.h
@@ -0,0 +1,112 @@
+/*
+ * drivers/usb/core/otg_whitelist.h
+ *
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * This OTG Whitelist is the OTG "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 defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
+/* 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;
+
+ /* possible in developer configs only! */
+ if (!dev->bus->otg_port)
+ return 1;
+
+ /* 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;
+
+ /* 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));
+#ifdef CONFIG_USB_OTG_WHITELIST
+ return 0;
+#else
+ return 1;
+#endif
+}
+
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644
index 00000000..32d3adc3
--- /dev/null
+++ b/drivers/usb/core/quirks.c
@@ -0,0 +1,199 @@
+/*
+ * USB device quirk handling logic and table
+ *
+ * Copyright (c) 2007 Oliver Neukum
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* List of quirky USB devices. Please keep this list ordered by:
+ * 1) Vendor ID
+ * 2) Product ID
+ * 3) Class ID
+ *
+ * as we want specific devices to be overridden first, and only after that, any
+ * class specific quirks.
+ *
+ * Right now the logic aborts if it finds a valid device in the table, we might
+ * want to change that in the future if it turns out that a whole class of
+ * devices is broken...
+ */
+static const struct usb_device_id usb_quirk_list[] = {
+ /* CBM - Flash disk */
+ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* HP 5300/5370C scanner */
+ { USB_DEVICE(0x03f0, 0x0701), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
+ /* Creative SB Audigy 2 NX */
+ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C200 */
+ { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C250 */
+ { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C300 */
+ { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam B/C500 */
+ { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C600 */
+ { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam Pro 9000 */
+ { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C905 */
+ { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C210 */
+ { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C260 */
+ { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C310 */
+ { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C910 */
+ { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C160 */
+ { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C270 */
+ { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam Pro 9000 */
+ { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam E3500 */
+ { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Quickcam Vision Pro */
+ { USB_DEVICE(0x046d, 0x09a6), .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 },
+
+ /* Artisman Watchdog Dongle */
+ { USB_DEVICE(0x04b4, 0x0526), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* Samsung Android phone modem - ID conflict with SPH-I500 */
+ { USB_DEVICE(0x04e8, 0x6601), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* 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 },
+
+ /* appletouch */
+ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* 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 },
+
+ /* 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 },
+
+ /* Midiman M-Audio Keystation 88es */
+ { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* M-Systems Flash Disk Pioneers */
+ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Keytouch QWERTY Panel keyboard */
+ { USB_DEVICE(0x0926, 0x3333), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
+ /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
+ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
+
+ /* Broadcom BCM92035DGROM BT dongle */
+ { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Action Semiconductor flash disk */
+ { USB_DEVICE(0x10d6, 0x2200), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
+ /* SKYMEDI USB_DRIVE */
+ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* BUILDWIN Photo Frame */
+ { USB_DEVICE(0x1908, 0x1315), .driver_info =
+ USB_QUIRK_HONOR_BNUMINTERFACES },
+
+ /* INTEL VALUE SSD */
+ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ { } /* terminating entry must be last */
+};
+
+static const struct usb_device_id *find_id(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+ id->driver_info; id++) {
+ if (usb_match_device(udev, id))
+ return id;
+ }
+ return NULL;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ id = find_id(udev);
+ if (id)
+ udev->quirks = (u32)(id->driver_info);
+ if (udev->quirks)
+ dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+ udev->quirks);
+
+ /* For the present, all devices default to USB-PERSIST enabled */
+#if 0 /* was: #ifdef CONFIG_PM */
+ /* Hubs are automatically enabled for USB-PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ udev->persist_enabled = 1;
+
+#else
+ /* In the absence of PM, we can safely enable USB-PERSIST
+ * for all devices. It will affect things like hub resets
+ * and EMF-related port disables.
+ */
+ if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+ udev->persist_enabled = 1;
+#endif /* CONFIG_PM */
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
new file mode 100644
index 00000000..566d9f94
--- /dev/null
+++ b/drivers/usb/core/sysfs.c
@@ -0,0 +1,947 @@
+/*
+ * 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.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* Active configuration fields */
+#define usb_actconfig_show(field, multiplier, format_string) \
+static ssize_t show_##field(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_device *udev; \
+ struct usb_host_config *actconfig; \
+ \
+ udev = to_usb_device(dev); \
+ actconfig = udev->actconfig; \
+ if (actconfig) \
+ return sprintf(buf, format_string, \
+ actconfig->desc.field * multiplier); \
+ else \
+ return 0; \
+} \
+
+#define usb_actconfig_attr(field, multiplier, format_string) \
+usb_actconfig_show(field, multiplier, format_string) \
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
+
+static ssize_t show_configuration_string(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+ struct usb_host_config *actconfig;
+
+ udev = to_usb_device(dev);
+ actconfig = udev->actconfig;
+ if ((!actconfig) || (!actconfig->string))
+ return 0;
+ return sprintf(buf, "%s\n", actconfig->string);
+}
+static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
+
+/* configuration value is always present, and r/w */
+usb_actconfig_show(bConfigurationValue, 1, "%u\n");
+
+static ssize_t
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int config, value;
+
+ if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
+ return -EINVAL;
+ usb_lock_device(udev);
+ value = usb_set_configuration(udev, config);
+ usb_unlock_device(udev);
+ return (value < 0) ? value : count;
+}
+
+static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+ show_bConfigurationValue, set_bConfigurationValue);
+
+/* String fields */
+#define usb_string_attr(name) \
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_device *udev; \
+ int retval; \
+ \
+ udev = to_usb_device(dev); \
+ usb_lock_device(udev); \
+ retval = sprintf(buf, "%s\n", udev->name); \
+ usb_unlock_device(udev); \
+ return retval; \
+} \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+usb_string_attr(product);
+usb_string_attr(manufacturer);
+usb_string_attr(serial);
+
+static ssize_t
+show_speed(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;
+ default:
+ speed = "unknown";
+ }
+ return sprintf(buf, "%s\n", speed);
+}
+static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
+
+static ssize_t
+show_busnum(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(busnum, S_IRUGO, show_busnum, NULL);
+
+static ssize_t
+show_devnum(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(devnum, S_IRUGO, show_devnum, NULL);
+
+static ssize_t
+show_devpath(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(devpath, S_IRUGO, show_devpath, NULL);
+
+static ssize_t
+show_version(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(version, S_IRUGO, show_version, NULL);
+
+static ssize_t
+show_maxchild(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(maxchild, S_IRUGO, show_maxchild, NULL);
+
+static ssize_t
+show_quirks(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(quirks, S_IRUGO, show_quirks, NULL);
+
+static ssize_t
+show_avoid_reset_quirk(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_MORPHS));
+}
+
+static ssize_t
+set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int config;
+
+ if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+ return -EINVAL;
+ usb_lock_device(udev);
+ if (config)
+ udev->quirks |= USB_QUIRK_RESET_MORPHS;
+ else
+ udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
+ usb_unlock_device(udev);
+ return count;
+}
+
+static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
+ show_avoid_reset_quirk, set_avoid_reset_quirk);
+
+static ssize_t
+show_urbnum(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(urbnum, S_IRUGO, show_urbnum, NULL);
+
+static ssize_t
+show_removable(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(removable, S_IRUGO, show_removable, NULL);
+
+#ifdef CONFIG_PM
+
+static ssize_t
+show_persist(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
+set_persist(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int value;
+
+ /* Hubs are always enabled for USB_PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ return -EPERM;
+
+ if (sscanf(buf, "%d", &value) != 1)
+ return -EINVAL;
+
+ usb_lock_device(udev);
+ udev->persist_enabled = !!value;
+ usb_unlock_device(udev);
+ return count;
+}
+
+static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_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);
+}
+#else
+
+#define add_persist_attributes(dev) 0
+#define remove_persist_attributes(dev) do {} while (0)
+
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+
+static ssize_t
+show_connected_duration(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(connected_duration, S_IRUGO, show_connected_duration, NULL);
+
+/*
+ * 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
+show_active_duration(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(active_duration, S_IRUGO, show_active_duration, NULL);
+
+static ssize_t
+show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
+}
+
+static ssize_t
+set_autosuspend(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(autosuspend, S_IRUGO | S_IWUSR,
+ show_autosuspend, set_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
+show_level(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
+set_level(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;
+
+ warn_level();
+ cp = memchr(buf, '\n', count);
+ if (cp)
+ len = cp - buf;
+
+ usb_lock_device(udev);
+
+ 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(level, S_IRUGO | S_IWUSR, show_level, set_level);
+
+static ssize_t
+show_usb2_hardware_lpm(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_enabled == 1)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t
+set_usb2_hardware_lpm(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;
+
+ usb_lock_device(udev);
+
+ ret = strtobool(buf, &value);
+
+ if (!ret)
+ ret = usb_set_usb2_hardware_lpm(udev, value);
+
+ usb_unlock_device(udev);
+
+ if (!ret)
+ return count;
+
+ return ret;
+}
+
+static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
+ set_usb2_hardware_lpm);
+
+static struct attribute *usb2_hardware_lpm_attr[] = {
+ &dev_attr_usb2_hardware_lpm.attr,
+ NULL,
+};
+static struct attribute_group usb2_hardware_lpm_attr_group = {
+ .name = power_group_name,
+ .attrs = usb2_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);
+ }
+
+ 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_power_attributes(dev) 0
+#define remove_power_attributes(dev) do {} while (0)
+
+#endif /* CONFIG_USB_SUSPEND */
+
+
+/* Descriptor fields */
+#define usb_descriptor_attr_le16(field, format_string) \
+static ssize_t \
+show_##field(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(field, S_IRUGO, show_##field, NULL);
+
+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 \
+show_##field(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(field, S_IRUGO, show_##field, NULL);
+
+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 usb_dev_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 usb_dev_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(authorized, 0644,
+ usb_dev_authorized_show, usb_dev_authorized_store);
+
+/* "Safely remove a device" */
+static ssize_t usb_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(remove, 0200, NULL, usb_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_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,
+ 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;
+
+ /* 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;
+ }
+ }
+ 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 Accociation Descriptor fields */
+#define usb_intf_assoc_attr(field, format_string) \
+static ssize_t \
+show_iad_##field(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(iad_##field, S_IRUGO, show_iad_##field, NULL);
+
+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 \
+show_##field(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(field, S_IRUGO, show_##field, NULL);
+
+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 show_interface_string(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf;
+ char *string;
+
+ intf = to_usb_interface(dev);
+ string = intf->cur_altsetting->string;
+ barrier(); /* The altsetting might change! */
+
+ if (!string)
+ return 0;
+ return sprintf(buf, "%s\n", string);
+}
+static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
+
+static ssize_t show_modalias(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 = intf->cur_altsetting;
+
+ return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
+ "ic%02Xisc%02Xip%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);
+}
+static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static ssize_t show_supports_autosuspend(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ int ret;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
+
+ usb_lock_device(udev);
+ /* Devices will be autosuspended even when an interface isn't claimed */
+ if (!intf->dev.driver ||
+ to_usb_driver(intf->dev.driver)->supports_autosuspend)
+ ret = sprintf(buf, "%u\n", 1);
+ else
+ ret = sprintf(buf, "%u\n", 0);
+ usb_unlock_device(udev);
+
+ return ret;
+}
+static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL);
+
+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,
+ 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 00000000..9d912bfd
--- /dev/null
+++ b/drivers/usb/core/urb.c
@@ -0,0 +1,888 @@
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/log2.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/usb/hcd.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->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, incrementes the usage counter, and returns a pointer to it.
+ *
+ * If no memory is available, NULL is returned.
+ *
+ * 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.
+ */
+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) {
+ printk(KERN_ERR "alloc_urb: kmalloc failed\n");
+ 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.
+ *
+ * A pointer to the urb with the incremented reference counter is returned.
+ */
+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);
+
+/* 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 (list_empty(&anchor->urb_list))
+ 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);
+
+/*-------------------------------------------------------------------*/
+
+/**
+ * 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.
+ *
+ * Successful submissions return 0; otherwise this routine returns a
+ * negative error number. 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.
+ *
+ * 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.
+ *
+ * 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 callacks). 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;
+
+ if (!urb || urb->hcpriv || !urb->complete)
+ return -EINVAL;
+ 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;
+ }
+
+ /* "high bandwidth" mode, 1-3 packets/uframe? */
+ if (dev->speed == USB_SPEED_HIGH) {
+ int mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x07ff;
+ max *= mult;
+ }
+
+ 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;
+ }
+ }
+
+ /* the I/O buffer must be mapped/unmapped, except when length=0 */
+ if (urb->transfer_buffer_length > INT_MAX)
+ return -EMSGSIZE;
+
+#ifdef DEBUG
+ /* stuff that drivers shouldn't do, but which shouldn't
+ * cause problems in HCDs if they get it wrong.
+ */
+ {
+ unsigned int allowed;
+ static int pipetypes[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+ };
+
+ /* Check that the pipe's type matches the endpoint's type */
+ if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+ 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:
+ if (is_out)
+ allowed |= URB_ZERO_PACKET;
+ /* FALLTHROUGH */
+ case USB_ENDPOINT_XFER_CONTROL:
+ allowed |= URB_NO_FSBR; /* only affects UHCI */
+ /* FALLTHROUGH */
+ default: /* all non-iso endpoints */
+ if (!is_out)
+ allowed |= URB_SHORT_NOT_OK;
+ 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);
+ }
+#endif
+ /*
+ * 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)
+ return -EINVAL;
+ break;
+ default:
+ if (urb->interval <= 0)
+ return -EINVAL;
+ break;
+ }
+ /* too big? */
+ switch (dev->speed) {
+ 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.
+ *
+ * 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);
+
+ 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 && urb->dev && urb->ep))
+ return;
+ atomic_inc(&urb->reject);
+
+ 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 - cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be killed starting
+ * from the back of the queue
+ *
+ * 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;
+
+ spin_lock_irq(&anchor->lock);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ /* we must 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);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+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;
+
+ 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);
+ /* we must 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);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+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 tiggered. 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_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
+ */
+int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+ unsigned int timeout)
+{
+ return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
+ 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
+ */
+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;
+
+ 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);
+ }
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
+
+/**
+ * usb_anchor_empty - is an anchor empty
+ * @anchor: the anchor you want to query
+ *
+ * returns 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.c b/drivers/usb/core/usb.c
new file mode 100644
index 00000000..0fc63407
--- /dev/null
+++ b/drivers/usb/core/usb.c
@@ -0,0 +1,1131 @@
+/*
+ * 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
+ *
+ * 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 <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 */
+
+#ifdef CONFIG_USB_SUSPEND
+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
+
+
+/**
+ * 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.
+ */
+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;
+
+ 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
+ * and returns a pointer to the interface with that particular interface
+ * number, or null.
+ *
+ * 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!
+ */
+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 and returns a pointer
+ * to that entry, or null.
+ *
+ * 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!
+ */
+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.
+ */
+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);
+
+/**
+ * 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);
+ usb_put_hcd(hcd);
+ kfree(udev->product);
+ kfree(udev->manufacturer);
+ kfree(udev->serial);
+ kfree(udev);
+}
+
+#ifdef CONFIG_HOTPLUG
+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;
+}
+
+#else
+
+static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_HOTPLUG */
+
+#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,
+#ifdef CONFIG_USB_SUSPEND
+ .runtime_suspend = usb_runtime_suspend,
+ .runtime_resume = usb_runtime_resume,
+ .runtime_idle = usb_runtime_idle,
+#endif
+};
+
+#endif /* CONFIG_PM */
+
+
+static char *usb_devnode(struct device *dev, umode_t *mode)
+{
+ 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 = container_of(bus, struct usb_hcd, self);
+ 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.
+ */
+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 = container_of(bus, struct usb_hcd, self);
+ unsigned root_hub = 0;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ if (!usb_get_hcd(bus_to_hcd(bus))) {
+ 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;
+ dev->dev.dma_mask = bus->controller->dma_mask;
+ set_dev_node(&dev->dev, dev_to_node(bus->controller));
+ dev->state = USB_STATE_ATTACHED;
+ 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;
+ 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);
+
+ /* 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 = usb_hcd->authorized_default;
+ dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+ }
+ return 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.
+ *
+ * A pointer to the device with the incremented reference counter is returned.
+ */
+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.
+ *
+ * A pointer to the interface with the incremented reference counter is
+ * returned.
+ */
+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.
+ *
+ * Returns 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
+ *
+ * Returns the current frame number for the USB host controller
+ * used with the given USB device. This can be used when scheduling
+ * isochronous requests.
+ *
+ * Note that 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)
+{
+ struct usb_descriptor_header *header;
+
+ while (size >= sizeof(struct usb_descriptor_header)) {
+ header = (struct usb_descriptor_header *)buffer;
+
+ if (header->bLength < 2) {
+ printk(KERN_ERR
+ "%s: bogus descriptor, type %d length %d\n",
+ usbcore_name,
+ header->bDescriptorType,
+ header->bLength);
+ return -1;
+ }
+
+ if (header->bDescriptorType == type) {
+ *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 value is 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).
+ *
+ * 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
+ *
+ * Return value is either null (indicating no buffer could be mapped), or
+ * the parameter. 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().
+ */
+#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->controller))
+ 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->controller))
+ 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->controller))
+ 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 value is either < 0 (indicating no buffers could be mapped), or
+ * the number of DMA mapping array entries in the scatterlist.
+ *
+ * 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->controller)
+ || !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->controller)
+ || !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->controller)
+ || !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
+
+/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
+#ifdef MODULE
+module_param(nousb, bool, 0444);
+#else
+core_param(nousb, nousb, bool, 0444);
+#endif
+
+/*
+ * for external read access to <nousb>
+ */
+int usb_disabled(void)
+{
+ return nousb;
+}
+EXPORT_SYMBOL_GPL(usb_disabled);
+
+/*
+ * 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 struct dentry *usb_debug_devices;
+
+static int usb_debugfs_init(void)
+{
+ usb_debug_root = debugfs_create_dir("usb", NULL);
+ if (!usb_debug_root)
+ return -ENOENT;
+
+ usb_debug_devices = debugfs_create_file("devices", 0444,
+ usb_debug_root, NULL,
+ &usbfs_devices_fops);
+ if (!usb_debug_devices) {
+ debugfs_remove(usb_debug_root);
+ usb_debug_root = NULL;
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static void usb_debugfs_cleanup(void)
+{
+ debugfs_remove(usb_debug_devices);
+ debugfs_remove(usb_debug_root);
+}
+
+unsigned char usb_sus = 0;
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+/*
+ * Init
+ */
+
+extern char enable_uhci0_wake;
+extern char enable_uhci1_wake;
+extern char enable_ehci_wake ;
+
+char enable_ehci_disc_wakeup = 0;
+
+static int __init usb_init(void)
+{
+
+ int retval;
+
+ char usb_env_pmc_name[] = "wmt.pmc.param";
+ char usb_env_pmc_val[120] = "0";
+ int varpmclen = 120;
+ unsigned int usb_pmc_param[7];
+
+ if(wmt_getsyspara(usb_env_pmc_name, usb_env_pmc_val, &varpmclen) == 0) {
+ sscanf(usb_env_pmc_val,"%X:%X:%X:%X:%X:%X:%X", &usb_pmc_param[0],&usb_pmc_param[1],
+ &usb_pmc_param[2],&usb_pmc_param[3],&usb_pmc_param[4],&usb_pmc_param[5],&usb_pmc_param[6]);
+ printk("*** uhci_hcd_init usb_param[0] =%x ,usb_param[1]=%x ,usb_param[2]=%x ,usb_param[3]=%x ,usb_param[4]=%x, usb_param[5]=%x, usb_param[6]=%x\n"
+ ,usb_pmc_param[0],usb_pmc_param[1],usb_pmc_param[2],usb_pmc_param[3],usb_pmc_param[4]
+ ,usb_pmc_param[5],usb_pmc_param[6]);
+ if (usb_pmc_param[0]) {
+ if(usb_pmc_param[1] & 0x00100000) {
+ enable_ehci_wake = 1;
+ //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id);
+ } else {
+ enable_ehci_wake = 0;// default port B
+ }
+ if (usb_pmc_param[5] & 0x1)
+ enable_uhci0_wake = 1;
+ else
+ enable_uhci0_wake = 0;
+ if (usb_pmc_param[5] & 0x2)
+ enable_uhci1_wake = 1;
+ else
+ enable_uhci1_wake = 0;
+ if (usb_pmc_param[6] & 0x1)
+ enable_ehci_disc_wakeup = 1;
+ } else {
+ enable_ehci_wake = 0;
+ enable_uhci1_wake = 0;
+ enable_uhci0_wake = 0;
+ }
+ }
+
+ if (nousb) {
+ pr_info("%s: USB support disabled\n", usbcore_name);
+ return 0;
+ }
+
+ retval = usb_debugfs_init();
+ if (retval)
+ goto out;
+
+ 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 = usbfs_init();
+ if (retval)
+ goto fs_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:
+ usbfs_cleanup();
+fs_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_debugfs_cleanup();
+out:
+ return retval;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit usb_exit(void)
+{
+ /* This will matter if shutdown/reboot does exitcalls. */
+ if (nousb)
+ return;
+
+ usb_deregister_device_driver(&usb_generic_driver);
+ usb_major_cleanup();
+ usbfs_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_debugfs_cleanup();
+}
+
+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 00000000..71648dcb
--- /dev/null
+++ b/drivers/usb/core/usb.h
@@ -0,0 +1,158 @@
+#include <linux/pm.h>
+
+/* 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_detect_quirks(struct usb_device *udev);
+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_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);
+
+extern void usb_kick_khubd(struct usb_device *dev);
+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_rebind_intf(struct usb_interface *intf);
+
+extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
+ void *owner);
+extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
+ void *owner);
+extern void usb_hub_release_all_ports(struct usb_device *hdev, void *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);
+
+#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);
+
+#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;
+}
+
+#endif
+
+#ifdef CONFIG_USB_SUSPEND
+
+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_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
+
+#else
+
+#define usb_autosuspend_device(udev) do {} while (0)
+static inline int usb_autoresume_device(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int usb_remote_wakeup(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ return 0;
+}
+#endif
+
+extern struct bus_type usb_bus_type;
+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 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;
+}
+
+/* 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);
+
+/* 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);
+