summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-04 18:03:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-04 18:03:51 -0700
commit8f28472a739e8e39adc6e64ee5b460df039f0e4f (patch)
tree979e35f3d1d2be94c06c942bcdc9ee68cbebaacb /drivers/usb/core
parent4ac4d584886a4f47f8ff3bca0f32ff9a2987d3e5 (diff)
parentc034a43e72dda58e4a184d71f5502ef356e04453 (diff)
Merge tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB updates from Greg KH: "Here is the big USB patchset for 4.12-rc1. Lots of good stuff here, after many many many attempts, the kernel finally has a working typeC interface, many thanks to Heikki and Guenter and others who have taken the time to get this merged. It wasn't an easy path for them at all. There's also a staging driver that uses this new api, which is why it's coming in through this tree. Along with that, there's the usual huge number of changes for gadget drivers, xhci, and other stuff. Johan also finally refactored pretty much every driver that was looking at USB endpoints to do it in a common way, which will help prevent any "badly-formed" devices from causing problems in drivers. That too wasn't a simple task. All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (263 commits) staging: typec: Fairchild FUSB302 Type-c chip driver staging: typec: Type-C Port Controller Interface driver (tcpci) staging: typec: USB Type-C Port Manager (tcpm) usb: host: xhci: remove #ifdef around PM functions usb: musb: don't mark of_dev_auxdata as initdata usb: misc: legousbtower: Fix buffers on stack USB: Revert "cdc-wdm: fix "out-of-sync" due to missing notifications" usb: Make sure usb/phy/of gets built-in USB: storage: e-mail update in drivers/usb/storage/unusual_devs.h usb: host: xhci: print correct command ring address usb: host: xhci: delete sp_dma_buffers for scratchpad usb: host: xhci: using correct specification chapter reference for DCBAAP xhci: switch to pci_alloc_irq_vectors usb: host: xhci-plat: set resume_quirk() for R-Car controllers usb: host: xhci-plat: add resume_quirk() usb: host: xhci-plat: enable clk in resume timing usb: host: plat: Enable xHCI plat runtime PM USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit USB: serial: constify static arrays usb: fix some references for /proc/bus/usb ...
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/buffer.c12
-rw-r--r--drivers/usb/core/devices.c4
-rw-r--r--drivers/usb/core/driver.c21
-rw-r--r--drivers/usb/core/file.c9
-rw-r--r--drivers/usb/core/hcd.c82
-rw-r--r--drivers/usb/core/hub.c11
-rw-r--r--drivers/usb/core/of.c23
-rw-r--r--drivers/usb/core/usb.c152
9 files changed, 259 insertions, 57 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index b99b871c4b9d..250ec1d662d9 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -8,7 +8,7 @@ usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-y += port.o
usbcore-$(CONFIG_OF) += of.o
-usbcore-$(CONFIG_PCI) += hcd-pci.o
+usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
usbcore-$(CONFIG_ACPI) += usb-acpi.o
obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index b9bf6e2eb6fe..b64568cf572c 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -66,7 +66,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
int i, size;
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!hcd->self.controller->dma_mask &&
+ (!is_device_dma_capable(hcd->self.sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM)))
return 0;
@@ -75,7 +75,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
if (!size)
continue;
snprintf(name, sizeof(name), "buffer-%d", size);
- hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
+ hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
size, size, 0);
if (!hcd->pool[i]) {
hcd_buffer_destroy(hcd);
@@ -130,7 +130,7 @@ void *hcd_buffer_alloc(
/* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!bus->controller->dma_mask &&
+ (!is_device_dma_capable(bus->sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
@@ -140,7 +140,7 @@ void *hcd_buffer_alloc(
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);
+ return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
}
void hcd_buffer_free(
@@ -157,7 +157,7 @@ void hcd_buffer_free(
return;
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!bus->controller->dma_mask &&
+ (!is_device_dma_capable(bus->sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
kfree(addr);
return;
@@ -169,5 +169,5 @@ void hcd_buffer_free(
return;
}
}
- dma_free_coherent(hcd->self.controller, size, addr, dma);
+ dma_free_coherent(hcd->self.sysdev, size, addr, dma);
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index f2987ddb1cde..55dea2e7828f 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -24,7 +24,7 @@
* <mountpoint>/devices contains USB topology, device, config, class,
* interface, & endpoint data.
*
- * I considered using /proc/bus/usb/devices/device# for each device
+ * I considered using /dev/bus/usb/device# for each device
* as it is attached or detached, but I didn't like this for some
* reason -- maybe it's just too deep of a directory structure.
* I also don't like looking in multiple places to gather and view
@@ -40,7 +40,7 @@
* 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
+ * Added a poll method to /sys/kernel/debug/usb/devices, to wake
* up an eventual usbd
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
* Turned into its own filesystem
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index cdee5130638b..eb87a259d55c 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1331,6 +1331,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
*/
if (udev->parent && !PMSG_IS_AUTO(msg))
status = 0;
+
+ /*
+ * If the device is inaccessible, don't try to resume
+ * suspended interfaces and just return the error.
+ */
+ if (status && status != -EBUSY) {
+ int err;
+ u16 devstat;
+
+ err = usb_get_status(udev, USB_RECIP_DEVICE, 0,
+ &devstat);
+ if (err) {
+ dev_err(&udev->dev,
+ "Failed to suspend device, error %d\n",
+ status);
+ goto done;
+ }
+ }
}
/* If the suspend failed, resume interfaces that did get suspended */
@@ -1763,6 +1781,9 @@ static int autosuspend_check(struct usb_device *udev)
int w, i;
struct usb_interface *intf;
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
*/
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index e26bd5e773ad..87ad6b6bfee8 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -29,6 +29,7 @@
#define MAX_USB_MINORS 256
static const struct file_operations *usb_minors[MAX_USB_MINORS];
static DECLARE_RWSEM(minor_rwsem);
+static DEFINE_MUTEX(init_usb_class_mutex);
static int usb_open(struct inode *inode, struct file *file)
{
@@ -111,8 +112,9 @@ static void release_usb_class(struct kref *kref)
static void destroy_usb_class(void)
{
- if (usb_class)
- kref_put(&usb_class->kref, release_usb_class);
+ mutex_lock(&init_usb_class_mutex);
+ kref_put(&usb_class->kref, release_usb_class);
+ mutex_unlock(&init_usb_class_mutex);
}
int usb_major_init(void)
@@ -173,7 +175,10 @@ int usb_register_dev(struct usb_interface *intf,
if (intf->minor >= 0)
return -EADDRINUSE;
+ mutex_lock(&init_usb_class_mutex);
retval = init_usb_class();
+ mutex_unlock(&init_usb_class_mutex);
+
if (retval)
return retval;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 79bdca5cb9c7..49550790a3cb 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1076,6 +1076,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
+ struct device *sysdev = hcd->self.sysdev;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1;
int retval;
@@ -1122,7 +1123,7 @@ static int register_root_hub(struct usb_hcd *hcd)
/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
- usb_dev->dev.of_node = parent_dev->of_node;
+ usb_dev->dev.of_node = sysdev->of_node;
}
mutex_unlock(&usb_bus_idr_lock);
@@ -1435,7 +1436,7 @@ void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
- dma_unmap_single(hcd->self.controller,
+ dma_unmap_single(hcd->self.sysdev,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
@@ -1468,19 +1469,19 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SG))
- dma_unmap_sg(hcd->self.controller,
+ dma_unmap_sg(hcd->self.sysdev,
urb->sg,
urb->num_sgs,
dir);
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_PAGE))
- dma_unmap_page(hcd->self.controller,
+ dma_unmap_page(hcd->self.sysdev,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
- dma_unmap_single(hcd->self.controller,
+ dma_unmap_single(hcd->self.sysdev,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
@@ -1523,11 +1524,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
return ret;
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->setup_packet,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->setup_dma))
return -EAGAIN;
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
@@ -1558,7 +1559,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
}
n = dma_map_sg(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->sg,
urb->num_sgs,
dir);
@@ -1573,12 +1574,12 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
} else if (urb->sg) {
struct scatterlist *sg = urb->sg;
urb->transfer_dma = dma_map_page(
- hcd->self.controller,
+ hcd->self.sysdev,
sg_page(sg),
sg->offset,
urb->transfer_buffer_length,
dir);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
@@ -1588,11 +1589,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
ret = -EAGAIN;
} else {
urb->transfer_dma = dma_map_single(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->transfer_buffer,
urb->transfer_buffer_length,
dir);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
@@ -2498,24 +2499,8 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
}
-/**
- * usb_create_shared_hcd - create and initialize an HCD structure
- * @driver: HC driver that will use this hcd
- * @dev: device for this HC, stored in hcd->self.controller
- * @bus_name: value to store in hcd->self.bus_name
- * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
- * PCI device. Only allocate certain resources for the primary HCD
- * Context: !in_interrupt()
- *
- * Allocate a struct usb_hcd, with extra space at the end for the
- * HC driver's private data. Initialize the generic members of the
- * hcd structure.
- *
- * Return: On success, a pointer to the created and initialized HCD structure.
- * On failure (e.g. if memory is unavailable), %NULL.
- */
-struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
- struct device *dev, const char *bus_name,
+struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
+ struct device *sysdev, struct device *dev, const char *bus_name,
struct usb_hcd *primary_hcd)
{
struct usb_hcd *hcd;
@@ -2556,8 +2541,9 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
usb_bus_init(&hcd->self);
hcd->self.controller = dev;
+ hcd->self.sysdev = sysdev;
hcd->self.bus_name = bus_name;
- hcd->self.uses_dma = (dev->dma_mask != NULL);
+ hcd->self.uses_dma = (sysdev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
@@ -2572,6 +2558,30 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
"USB Host Controller";
return hcd;
}
+EXPORT_SYMBOL_GPL(__usb_create_hcd);
+
+/**
+ * usb_create_shared_hcd - create and initialize an HCD structure
+ * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
+ * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
+ * PCI device. Only allocate certain resources for the primary HCD
+ * Context: !in_interrupt()
+ *
+ * Allocate a struct usb_hcd, with extra space at the end for the
+ * HC driver's private data. Initialize the generic members of the
+ * hcd structure.
+ *
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
+ */
+struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
+ struct device *dev, const char *bus_name,
+ struct usb_hcd *primary_hcd)
+{
+ return __usb_create_hcd(driver, dev, dev, bus_name, primary_hcd);
+}
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
/**
@@ -2591,7 +2601,7 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
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);
+ return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
}
EXPORT_SYMBOL_GPL(usb_create_hcd);
@@ -2718,7 +2728,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
struct usb_device *rhdev;
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
- struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0);
+ struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
if (IS_ERR(phy)) {
retval = PTR_ERR(phy);
@@ -2736,7 +2746,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
- struct phy *phy = phy_get(hcd->self.controller, "usb");
+ struct phy *phy = phy_get(hcd->self.sysdev, "usb");
if (IS_ERR(phy)) {
retval = PTR_ERR(phy);
@@ -2784,7 +2794,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
*/
retval = hcd_buffer_create(hcd);
if (retval != 0) {
- dev_dbg(hcd->self.controller, "pool alloc failed\n");
+ dev_dbg(hcd->self.sysdev, "pool alloc failed\n");
goto err_create_buf;
}
@@ -2794,7 +2804,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
if (rhdev == NULL) {
- dev_err(hcd->self.controller, "unable to allocate root hub\n");
+ dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5286bf67869a..9dca59ef18b3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1066,6 +1066,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
portstatus = portchange = 0;
status = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (status)
+ goto abort;
+
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
dev_dbg(&port_dev->dev, "status %04x change %04x\n",
portstatus, portchange);
@@ -1198,7 +1201,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
/* Scan all ports that need attention */
kick_hub_wq(hub);
-
+ abort:
if (type == HUB_INIT2 || type == HUB_INIT3) {
/* Allow autosuspend if it was suppressed */
disconnected:
@@ -2084,6 +2087,12 @@ void usb_disconnect(struct usb_device **pdev)
dev_info(&udev->dev, "USB disconnect, device number %d\n",
udev->devnum);
+ /*
+ * Ensure that the pm runtime code knows that the USB device
+ * is in the process of being disconnected.
+ */
+ pm_runtime_barrier(&udev->dev);
+
usb_lock_device(udev);
hub_disconnect_children(udev);
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
index 3de4f8873984..d787f195a9a6 100644
--- a/drivers/usb/core/of.c
+++ b/drivers/usb/core/of.c
@@ -18,6 +18,7 @@
*/
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/usb/of.h>
/**
@@ -46,3 +47,25 @@ struct device_node *usb_of_get_child_node(struct device_node *parent,
}
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
+/**
+ * usb_of_get_companion_dev - Find the companion device
+ * @dev: the device pointer to find a companion
+ *
+ * Find the companion device from platform bus.
+ *
+ * Return: On success, a pointer to the companion device, %NULL on failure.
+ */
+struct device *usb_of_get_companion_dev(struct device *dev)
+{
+ struct device_node *node;
+ struct platform_device *pdev = NULL;
+
+ node = of_parse_phandle(dev->of_node, "companion", 0);
+ if (node)
+ pdev = of_find_device_by_node(node);
+
+ of_node_put(node);
+
+ return pdev ? &pdev->dev : NULL;
+}
+EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index a2ccc69fb45c..28b053cacc90 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -74,6 +74,140 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
#define usb_autosuspend_delay 0
#endif
+static bool match_endpoint(struct usb_endpoint_descriptor *epd,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ switch (usb_endpoint_type(epd)) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (usb_endpoint_dir_in(epd)) {
+ if (bulk_in && !*bulk_in) {
+ *bulk_in = epd;
+ break;
+ }
+ } else {
+ if (bulk_out && !*bulk_out) {
+ *bulk_out = epd;
+ break;
+ }
+ }
+
+ return false;
+ case USB_ENDPOINT_XFER_INT:
+ if (usb_endpoint_dir_in(epd)) {
+ if (int_in && !*int_in) {
+ *int_in = epd;
+ break;
+ }
+ } else {
+ if (int_out && !*int_out) {
+ *int_out = epd;
+ break;
+ }
+ }
+
+ return false;
+ default:
+ return false;
+ }
+
+ return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
+ (!int_in || *int_in) && (!int_out || *int_out);
+}
+
+/**
+ * usb_find_common_endpoints() -- look up common endpoint descriptors
+ * @alt: alternate setting to search
+ * @bulk_in: pointer to descriptor pointer, or NULL
+ * @bulk_out: pointer to descriptor pointer, or NULL
+ * @int_in: pointer to descriptor pointer, or NULL
+ * @int_out: pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the first bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ struct usb_endpoint_descriptor *epd;
+ int i;
+
+ if (bulk_in)
+ *bulk_in = NULL;
+ if (bulk_out)
+ *bulk_out = NULL;
+ if (int_in)
+ *int_in = NULL;
+ if (int_out)
+ *int_out = NULL;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
+ epd = &alt->endpoint[i].desc;
+
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+ return 0;
+ }
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
+
+/**
+ * usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
+ * @alt: alternate setting to search
+ * @bulk_in: pointer to descriptor pointer, or NULL
+ * @bulk_out: pointer to descriptor pointer, or NULL
+ * @int_in: pointer to descriptor pointer, or NULL
+ * @int_out: pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the last bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ struct usb_endpoint_descriptor *epd;
+ int i;
+
+ if (bulk_in)
+ *bulk_in = NULL;
+ if (bulk_out)
+ *bulk_out = NULL;
+ if (int_in)
+ *int_in = NULL;
+ if (int_out)
+ *int_out = NULL;
+
+ for (i = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
+ epd = &alt->endpoint[i].desc;
+
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+ return 0;
+ }
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
/**
* usb_find_alt_setting() - Given a configuration, find the alternate setting
@@ -453,9 +587,9 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
* Note: calling dma_set_mask() on a USB device would set the
* mask for the entire HCD, so don't do that.
*/
- dev->dev.dma_mask = bus->controller->dma_mask;
- dev->dev.dma_pfn_offset = bus->controller->dma_pfn_offset;
- set_dev_node(&dev->dev, dev_to_node(bus->controller));
+ dev->dev.dma_mask = bus->sysdev->dma_mask;
+ dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset;
+ set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
dev->state = USB_STATE_ATTACHED;
dev->lpm_disable_count = 1;
atomic_set(&dev->urbnum, 0);
@@ -803,7 +937,7 @@ struct urb *usb_buffer_map(struct urb *urb)
if (!urb
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return NULL;
if (controller->dma_mask) {
@@ -841,7 +975,7 @@ void usb_buffer_dmasync(struct urb *urb)
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return;
if (controller->dma_mask) {
@@ -875,7 +1009,7 @@ void usb_buffer_unmap(struct urb *urb)
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return;
if (controller->dma_mask) {
@@ -925,7 +1059,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return -EINVAL;
@@ -961,7 +1095,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return;
@@ -989,7 +1123,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return;