summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 19:30:55 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 19:30:55 -0700
commit362f6729cbb1d6bbab59e069f19441b0622ff7ec (patch)
tree654070221092c34c97f48fbbdef7d5f02ffc7ba4 /drivers/usb/core
parent4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694 (diff)
parent6836796de4019944f4ba4c99a360e8250fd2e735 (diff)
downloadlinux-362f6729cbb1d6bbab59e069f19441b0622ff7ec.tar.bz2
Merge tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH: "Here is the big patchset of USB and PHY driver updates for 4.13-rc1. On the PHY side, they decided to move files around to "make things easier" in their tree. Hopefully that wasn't a mistake, but in linux-next testing, we haven't had any reported problems. There's the usual set of gadget and xhci and musb updates in here as well, along with a number of smaller updates for a raft of different USB drivers. Full details in the shortlog, nothing really major. All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (173 commits) Add USB quirk for HVR-950q to avoid intermittent device resets USB hub_probe: rework ugly goto-into-compound-statement usb: host: ohci-pxa27x: Handle return value of clk_prepare_enable USB: serial: cp210x: add ID for CEL EM3588 USB ZigBee stick usbip: Fix uninitialized variable bug in vhci usb: core: read USB ports from DT in the usbport LED trigger driver dt-bindings: leds: document new trigger-sources property usb: typec: ucsi: Add ACPI driver usb: typec: Add support for UCSI interface usb: musb: compress return logic into one line USB: serial: propagate late probe errors USB: serial: refactor port endpoint setup usb: musb: tusb6010_omap: Convert to DMAengine API ARM: OMAP2+: DMA: Add slave map entries for 24xx external request lines usb: musb: tusb6010: Handle DMA TX completion in DMA callback as well usb: musb: tusb6010_omap: Allocate DMA channels upfront usb: musb: tusb6010_omap: Create new struct for DMA data/parameters usb: musb: tusb6010_omap: Use one musb_ep_select call in tusb_omap_dma_program usb: musb: tusb6010: Add MUSB_G_NO_SKB_RESERVE to quirks usb: musb: Add quirk to avoid skb reserve in gadget mode ...
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/devio.c3
-rw-r--r--drivers/usb/core/hcd.c14
-rw-r--r--drivers/usb/core/hub.c51
-rw-r--r--drivers/usb/core/ledtrig-usbport.c56
-rw-r--r--drivers/usb/core/of.c3
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/core/usb-acpi.c26
-rw-r--r--drivers/usb/core/usb.c2
8 files changed, 125 insertions, 34 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8e6ef671be9b..0e7d0e81a7cb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -2537,6 +2537,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
case USBDEVFS_DROP_PRIVILEGES:
ret = proc_drop_privileges(ps, p);
break;
+ case USBDEVFS_GET_SPEED:
+ ret = ps->dev->speed;
+ break;
}
done:
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 5dea98358c05..ab1bb3b538ac 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/sched/task_stack.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/utsname.h>
@@ -1076,7 +1077,6 @@ 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;
@@ -1123,7 +1123,6 @@ 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 = sysdev->of_node;
}
mutex_unlock(&usb_bus_idr_lock);
@@ -1523,6 +1522,14 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (hcd->self.uses_pio_for_control)
return ret;
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+ if (is_vmalloc_addr(urb->setup_packet)) {
+ WARN_ONCE(1, "setup packet is not dma capable\n");
+ return -EAGAIN;
+ } else if (object_is_on_stack(urb->setup_packet)) {
+ WARN_ONCE(1, "setup packet is on stack\n");
+ return -EAGAIN;
+ }
+
urb->setup_dma = dma_map_single(
hcd->self.sysdev,
urb->setup_packet,
@@ -1587,6 +1594,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
} else if (is_vmalloc_addr(urb->transfer_buffer)) {
WARN_ONCE(1, "transfer buffer not dma capable\n");
ret = -EAGAIN;
+ } else if (object_is_on_stack(urb->transfer_buffer)) {
+ WARN_ONCE(1, "transfer buffer is on stack\n");
+ ret = -EAGAIN;
} else {
urb->transfer_dma = dma_map_single(
hcd->self.sysdev,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b8bb20d7acdb..6e6797d145dd 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1661,10 +1661,28 @@ static void hub_disconnect(struct usb_interface *intf)
kref_put(&hub->kref, hub_release);
}
+static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
+{
+ /* Some hubs have a subclass of 1, which AFAICT according to the */
+ /* specs is not defined, but it works */
+ if (desc->desc.bInterfaceSubClass != 0 &&
+ desc->desc.bInterfaceSubClass != 1)
+ return false;
+
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (desc->desc.bNumEndpoints != 1)
+ return false;
+
+ /* If the first endpoint is not interrupt IN, we'd better punt! */
+ if (!usb_endpoint_is_int_in(&desc->endpoint[0].desc))
+ return false;
+
+ return true;
+}
+
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *desc;
- struct usb_endpoint_descriptor *endpoint;
struct usb_device *hdev;
struct usb_hub *hub;
@@ -1739,25 +1757,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
}
#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:
+ if (!hub_descriptor_is_sane(desc)) {
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");
@@ -1784,7 +1788,7 @@ descriptor_error:
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
hub->quirk_check_port_auto_suspend = 1;
- if (hub_configure(hub, endpoint) >= 0)
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
return 0;
hub_disconnect(intf);
@@ -3155,12 +3159,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (PMSG_IS_AUTO(msg))
goto err_ltm;
}
- if (usb_unlocked_disable_lpm(udev)) {
- dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
- status = -ENOMEM;
- if (PMSG_IS_AUTO(msg))
- goto err_lpm3;
- }
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
@@ -3187,9 +3185,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (status) {
dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
- /* Try to enable USB3 LPM and LTM again */
- usb_unlocked_enable_lpm(udev);
- err_lpm3:
+ /* Try to enable USB3 LTM again */
usb_enable_ltm(udev);
err_ltm:
/* Try to enable USB2 hardware LPM again */
@@ -3473,9 +3469,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
- /* Try to enable USB3 LTM and LPM */
+ /* Try to enable USB3 LTM */
usb_enable_ltm(udev);
- usb_unlocked_enable_lpm(udev);
}
usb_unlock_port(port_dev);
diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c
index 1713248ab15a..16c19a31dad1 100644
--- a/drivers/usb/core/ledtrig-usbport.c
+++ b/drivers/usb/core/ledtrig-usbport.c
@@ -11,8 +11,10 @@
#include <linux/device.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/usb/of.h>
struct usbport_trig_data {
struct led_classdev *led_cdev;
@@ -123,6 +125,57 @@ static const struct attribute_group ports_group = {
* Adding & removing ports
***************************************/
+/**
+ * usbport_trig_port_observed - Check if port should be observed
+ */
+static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data,
+ struct usb_device *usb_dev, int port1)
+{
+ struct device *dev = usbport_data->led_cdev->dev;
+ struct device_node *led_np = dev->of_node;
+ struct of_phandle_args args;
+ struct device_node *port_np;
+ int count, i;
+
+ if (!led_np)
+ return false;
+
+ /* Get node of port being added */
+ port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1);
+ if (!port_np)
+ return false;
+
+ /* Amount of trigger sources for this LED */
+ count = of_count_phandle_with_args(led_np, "trigger-sources",
+ "#trigger-source-cells");
+ if (count < 0) {
+ dev_warn(dev, "Failed to get trigger sources for %s\n",
+ led_np->full_name);
+ return false;
+ }
+
+ /* Check list of sources for this specific port */
+ for (i = 0; i < count; i++) {
+ int err;
+
+ err = of_parse_phandle_with_args(led_np, "trigger-sources",
+ "#trigger-source-cells", i,
+ &args);
+ if (err) {
+ dev_err(dev, "Failed to get trigger source phandle at index %d: %d\n",
+ i, err);
+ continue;
+ }
+
+ of_node_put(args.np);
+
+ if (args.np == port_np)
+ return true;
+ }
+
+ return false;
+}
+
static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
struct usb_device *usb_dev,
const char *hub_name, int portnum)
@@ -141,6 +194,8 @@ static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
port->data = usbport_data;
port->hub = usb_dev;
port->portnum = portnum;
+ port->observed = usbport_trig_port_observed(usbport_data, usb_dev,
+ portnum);
len = strlen(hub_name) + 8;
port->port_name = kzalloc(len, GFP_KERNEL);
@@ -255,6 +310,7 @@ static void usbport_trig_activate(struct led_classdev *led_cdev)
if (err)
goto err_free;
usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
+ usbport_trig_update_count(usbport_data);
/* Notifications */
usbport_data->nb.notifier_call = usbport_trig_notify,
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
index d563cbcf76cf..3863bb1ce8c5 100644
--- a/drivers/usb/core/of.c
+++ b/drivers/usb/core/of.c
@@ -28,7 +28,8 @@
*
* Find the node from device tree according to its port number.
*
- * Return: On success, a pointer to the device node, %NULL on failure.
+ * Return: A pointer to the node with incremented refcount if found, or
+ * %NULL otherwise.
*/
struct device_node *usb_of_get_child_node(struct device_node *parent,
int portnum)
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 96b21b0dac1e..3116edfcdc18 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -223,6 +223,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Blackmagic Design UltraStudio SDI */
{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
+ /* Hauppauge HVR-950q */
+ { USB_DEVICE(0x2040, 0x7200), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 2776cfe64c09..ef9cf4a21afe 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -127,6 +127,22 @@ out:
*/
#define USB_ACPI_LOCATION_VALID (1 << 31)
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+ int raw)
+{
+ struct acpi_device *adev;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ if (acpi_device_adr(adev) == raw)
+ return adev;
+ }
+
+ return acpi_find_child_device(parent, raw, false);
+}
+
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
{
struct usb_device *udev;
@@ -174,8 +190,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
int raw;
raw = usb_hcd_find_raw_port_number(hcd, port1);
- adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev),
- raw, false);
+
+ adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+ raw);
+
if (!adev)
return NULL;
} else {
@@ -186,7 +204,9 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
return NULL;
acpi_bus_get_device(parent_handle, &adev);
- adev = acpi_find_child_device(adev, port1, false);
+
+ adev = usb_acpi_find_port(adev, port1);
+
if (!adev)
return NULL;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 28b053cacc90..17681d5638ac 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -416,6 +416,7 @@ static void usb_release_dev(struct device *dev)
usb_destroy_configuration(udev);
usb_release_bos_descriptor(udev);
+ of_node_put(dev->of_node);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
@@ -614,6 +615,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0;
dev->dev.parent = bus->controller;
+ device_set_of_node_from_dev(&dev->dev, bus->sysdev);
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {