From 64f10edf0751727154e843e8bcf59fb659e579a2 Mon Sep 17 00:00:00 2001 From: Chase Metzger Date: Tue, 22 Dec 2015 20:19:45 -0800 Subject: usb: core: devio.c: Removed unnecessary space Removed an unnecessary space between a function name and arguments. Signed-off-by: Chase Metzger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 59e7a3369084..6aac2425dd9f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1903,7 +1903,7 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg) ret = releaseintf(ps, ifnum); if (ret < 0) return ret; - destroy_async_on_interface (ps, ifnum); + destroy_async_on_interface(ps, ifnum); return 0; } -- cgit v1.2.3 From 73a02d32458ecff5b6241e7e7bd6445f70400bad Mon Sep 17 00:00:00 2001 From: Rahul Pathak Date: Fri, 11 Dec 2015 05:40:51 +0000 Subject: usb: Use memdup_user to reuse the code Fixing coccicheck warning which recommends to use memdup_user instead to reimplement its code, using memdup_user simplifies the code ./drivers/usb/core/devio.c:1398:11-18: WARNING opportunity for memdup_user Signed-off-by: Rahul Pathak Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6aac2425dd9f..054eb534c495 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1378,11 +1378,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb number_of_packets = uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * number_of_packets; - isopkt = kmalloc(isofrmlen, GFP_KERNEL); - if (!isopkt) - return -ENOMEM; - if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { - ret = -EFAULT; + isopkt = memdup_user(iso_frame_desc, isofrmlen); + if (IS_ERR(isopkt)) { + ret = PTR_ERR(isopkt); + isopkt = NULL; goto error; } for (totlen = u = 0; u < number_of_packets; u++) { -- cgit v1.2.3 From 8a1b2725a60d3267135c15e80984b4406054f650 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 10 Dec 2015 09:59:25 +0200 Subject: usb: define USB_SPEED_SUPER_PLUS speed for SuperSpeedPlus USB3.1 devices Add a new USB_SPEED_SUPER_PLUS device speed, and make sure usb core can handle the new speed. In most cases the behaviour is the same as with USB_SPEED_SUPER SuperSpeed devices. In a few places we add a "Plus" string to inform the user of the new speed. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 3 ++- drivers/usb/core/devices.c | 10 ++++++---- drivers/usb/core/hcd-pci.c | 2 +- drivers/usb/core/hcd.c | 6 +++--- drivers/usb/core/hub.c | 26 +++++++++++++++----------- drivers/usb/core/urb.c | 3 ++- drivers/usb/core/usb.h | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 5050760f5e17..bbcf4009f99e 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -191,6 +191,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, if (usb_endpoint_xfer_int(d)) { i = 1; switch (to_usb_device(ddev)->speed) { + case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: case USB_SPEED_HIGH: /* Many device manufacturers are using full-speed @@ -274,7 +275,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, } /* Parse a possible SuperSpeed endpoint companion descriptor */ - if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) + if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER) usb_parse_ss_endpoint_companion(ddev, cfgno, inum, asnum, endpoint, buffer, size); diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index cffa0a0d7de2..b35a6a52210f 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER) + if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER) interval = 1 << (desc->bInterval - 1); else interval = desc->bInterval; @@ -230,7 +230,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, return start; } interval *= (speed == USB_SPEED_HIGH || - speed == USB_SPEED_SUPER) ? 125 : 1000; + speed >= USB_SPEED_SUPER) ? 125 : 1000; if (interval % 1000) unit = 'u'; else { @@ -322,7 +322,7 @@ static char *usb_dump_config_descriptor(char *start, char *end, if (start > end) return start; - if (speed == USB_SPEED_SUPER) + if (speed >= USB_SPEED_SUPER) mul = 8; else mul = 2; @@ -534,6 +534,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, speed = "480"; break; case USB_SPEED_SUPER: speed = "5000"; break; + case USB_SPEED_SUPER_PLUS: + speed = "10000"; break; default: speed = "??"; } @@ -553,7 +555,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, /* super/high speed reserves 80%, full/low reserves 90% */ if (usbdev->speed == USB_SPEED_HIGH || - usbdev->speed == USB_SPEED_SUPER) + usbdev->speed >= USB_SPEED_SUPER) max = 800; else max = FRAME_TIME_MAX_USECS_ALLOC; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 9eb1cff28bd4..22a9ac25b850 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -197,7 +197,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) * The xHCI driver has its own irq management * make sure irq setup is not touched for xhci in generic hcd code */ - if ((driver->flags & HCD_MASK) != HCD_USB3) { + if ((driver->flags & HCD_MASK) < HCD_USB3) { if (!dev->irq) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index df0e3b92533a..0e38ce60d7d5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1078,7 +1078,7 @@ static int register_root_hub(struct usb_hcd *hcd) retval = usb_get_bos_descriptor(usb_dev); if (!retval) { usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev); - } else if (usb_dev->speed == USB_SPEED_SUPER) { + } else if (usb_dev->speed >= USB_SPEED_SUPER) { mutex_unlock(&usb_bus_list_lock); dev_dbg(parent_dev, "can't read %s bos descriptor %d\n", dev_name(&usb_dev->dev), retval); @@ -2112,7 +2112,7 @@ int usb_alloc_streams(struct usb_interface *interface, hcd = bus_to_hcd(dev->bus); if (!hcd->driver->alloc_streams || !hcd->driver->free_streams) return -EINVAL; - if (dev->speed != USB_SPEED_SUPER) + if (dev->speed < USB_SPEED_SUPER) return -EINVAL; if (dev->state < USB_STATE_CONFIGURED) return -ENODEV; @@ -2160,7 +2160,7 @@ int usb_free_streams(struct usb_interface *interface, dev = interface_to_usbdev(interface); hcd = bus_to_hcd(dev->bus); - if (dev->speed != USB_SPEED_SUPER) + if (dev->speed < USB_SPEED_SUPER) return -EINVAL; /* Double-free is not allowed */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 51b436918f78..6bdff0ad3930 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -298,7 +298,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev) unsigned int hub_u1_del; unsigned int hub_u2_del; - if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER) + if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER) return; hub = usb_hub_to_struct_hub(udev->parent); @@ -2645,7 +2645,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) */ static bool use_new_scheme(struct usb_device *udev, int retry) { - if (udev->speed == USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER) return false; return USE_NEW_SCHEME(retry); @@ -3989,7 +3989,7 @@ int usb_disable_lpm(struct usb_device *udev) struct usb_hcd *hcd; if (!udev || !udev->parent || - udev->speed != USB_SPEED_SUPER || + udev->speed < USB_SPEED_SUPER || !udev->lpm_capable || udev->state < USB_STATE_DEFAULT) return 0; @@ -4048,7 +4048,7 @@ void usb_enable_lpm(struct usb_device *udev) struct usb_port *port_dev; if (!udev || !udev->parent || - udev->speed != USB_SPEED_SUPER || + udev->speed < USB_SPEED_SUPER || !udev->lpm_capable || udev->state < USB_STATE_DEFAULT) return; @@ -4323,7 +4323,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, retval = -ENODEV; - if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { + /* Don't allow speed changes at reset, except usb 3.0 to faster */ + if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed && + !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) { dev_dbg(&udev->dev, "device reset changed speed!\n"); goto fail; } @@ -4335,6 +4337,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. */ switch (udev->speed) { + case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: case USB_SPEED_WIRELESS: /* fixed at 512 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); @@ -4361,7 +4364,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, else speed = usb_speed_string(udev->speed); - if (udev->speed != USB_SPEED_SUPER) + if (udev->speed < USB_SPEED_SUPER) dev_info(&udev->dev, "%s %s USB device number %d using %s\n", (udev->config) ? "reset" : "new", speed, @@ -4485,11 +4488,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, devnum, retval); goto fail; } - if (udev->speed == USB_SPEED_SUPER) { + if (udev->speed >= USB_SPEED_SUPER) { devnum = udev->devnum; dev_info(&udev->dev, - "%s SuperSpeed USB device number %d using %s\n", + "%s SuperSpeed%s USB device number %d using %s\n", (udev->config) ? "reset" : "new", + (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "", devnum, udev->bus->controller->driver->name); } @@ -4528,7 +4532,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, * 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) && + 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"); @@ -4539,7 +4543,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, } if (udev->descriptor.bMaxPacketSize0 == 0xff || - udev->speed == USB_SPEED_SUPER) + udev->speed >= USB_SPEED_SUPER) i = 512; else i = udev->descriptor.bMaxPacketSize0; @@ -4749,7 +4753,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, udev->level = hdev->level + 1; udev->wusb = hub_is_wusb(hub); - /* Only USB 3.0 devices are connected to SuperSpeed hubs. */ + /* Devices connected to SuperSpeed hubs are USB 3.0 or later */ if (hub_is_superspeed(hub->hdev)) udev->speed = USB_SPEED_SUPER; else diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 3d274778caaf..c601e25b609f 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -401,7 +401,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* SuperSpeed isoc endpoints have up to 16 bursts of up to * 3 packets each */ - if (dev->speed == USB_SPEED_SUPER) { + 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; @@ -499,6 +499,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) } /* too big? */ switch (dev->speed) { + case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER: /* units are 125us */ /* Handle up to 2^(16-1) microframes */ if (urb->interval > (1 << 15)) diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 05b5e17abf92..53318126ed91 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -45,7 +45,7 @@ static inline unsigned usb_get_max_power(struct usb_device *udev, struct usb_host_config *c) { /* SuperSpeed power is in 8 mA units; others are in 2 mA units */ - unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2); + unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2); return c->desc.bMaxPower * mul; } -- cgit v1.2.3 From 5f9c3a668b3f75768aec686901d7a4c8782983df Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 10 Dec 2015 09:59:26 +0200 Subject: usb: set USB 3.1 roothub device speed to USB_SPEED_SUPER_PLUS A hcd roothub that supports HCD_USB31 is running at SuperSpeedPlus speed Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0e38ce60d7d5..ff3073d522a8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2778,9 +2778,11 @@ int usb_add_hcd(struct usb_hcd *hcd, rhdev->speed = USB_SPEED_WIRELESS; break; case HCD_USB3: - case HCD_USB31: rhdev->speed = USB_SPEED_SUPER; break; + case HCD_USB31: + rhdev->speed = USB_SPEED_SUPER_PLUS; + break; default: retval = -EINVAL; goto err_set_rh_speed; -- cgit v1.2.3 From b2316645ca5ea93eb8f637f57199fbbe88bee07d Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 10 Dec 2015 09:59:27 +0200 Subject: usb: show speed "10000" in sysfs for USB 3.1 SuperSpeedPlus devices The same way as SuperSpeed devices show "5000" as device speed we wan't to show "10000" as the default speed for SuperSpeedPlus devices in sysfs. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 65b6e6b84043..f195320d35c0 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -141,6 +141,9 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, case USB_SPEED_SUPER: speed = "5000"; break; + case USB_SPEED_SUPER_PLUS: + speed = "10000"; + break; default: speed = "unknown"; } -- cgit v1.2.3 From 9508e3b7a70c11370d70252147b75d3024754970 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 10 Dec 2015 09:59:28 +0200 Subject: usb: add device descriptor for usb 3.1 root hub Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ff3073d522a8..bca13a0e0326 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -128,6 +128,27 @@ static inline int is_root_hub(struct usb_device *udev) #define KERNEL_REL bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff)) #define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff)) +/* usb 3.1 root hub device descriptor */ +static const u8 usb31_rh_dev_descriptor[18] = { + 0x12, /* __u8 bLength; */ + USB_DT_DEVICE, /* __u8 bDescriptorType; Device */ + 0x10, 0x03, /* __le16 bcdUSB; v3.1 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x03, /* __u8 bDeviceProtocol; USB 3 hub */ + 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */ + + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ + 0x03, 0x00, /* __le16 idProduct; device 0x0003 */ + KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + /* usb 3.0 root hub device descriptor */ static const u8 usb3_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ @@ -557,6 +578,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) case USB_DT_DEVICE << 8: switch (hcd->speed) { case HCD_USB31: + bufp = usb31_rh_dev_descriptor; + break; case HCD_USB3: bufp = usb3_rh_dev_descriptor; break; -- cgit v1.2.3 From 0cdd49a1d1a483d80170d9e592f832274e8bce1b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 10 Dec 2015 09:59:29 +0200 Subject: usb: Support USB 3.1 extended port status request usb 3.1 extend the hub get-port-status request by adding different request types. the new request types return 4 additional bytes called extended port status, these bytes are returned after the regular portstatus and portchange values. The extended port status contains a speed ID for the currently used sublink speed. A table of supported Speed IDs with details about the link is provided by the hub in the device descriptor BOS SuperSpeedPlus device capability Sublink Speed Attributes. Support this new request. Ask for the extended port status after port reset if hub supports USB 3.1. If link is running at SuperSpeedPlus set the device speed to USB_SPEED_SUPER_PLUS Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 8 +++++- drivers/usb/core/hub.c | 70 +++++++++++++++++++++++++++++++++++++++++++------- drivers/usb/core/hub.h | 7 +++++ 3 files changed, 75 insertions(+), 10 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bca13a0e0326..9af9506352f3 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -668,9 +668,15 @@ nongeneric: /* non-generic request */ switch (typeReq) { case GetHubStatus: - case GetPortStatus: len = 4; break; + case GetPortStatus: + if (wValue == HUB_PORT_STATUS) + len = 4; + else + /* other port status types return 8 bytes */ + len = 8; + break; case GetHubDescriptor: len = sizeof (struct usb_hub_descriptor); break; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6bdff0ad3930..3c9b22eb78ca 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -537,29 +537,34 @@ static int get_hub_status(struct usb_device *hdev, /* * USB 2.0 spec Section 11.24.2.7 + * USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6 */ static int get_port_status(struct usb_device *hdev, int port1, - struct usb_port_status *data) + void *data, u16 value, u16 length) { int i, status = -ETIMEDOUT; for (i = 0; i < USB_STS_RETRIES && (status == -ETIMEDOUT || status == -EPIPE); i++) { status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1, - data, sizeof(*data), USB_STS_TIMEOUT); + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value, + port1, data, length, USB_STS_TIMEOUT); } return status; } -static int hub_port_status(struct usb_hub *hub, int port1, - u16 *status, u16 *change) +static int hub_ext_port_status(struct usb_hub *hub, int port1, int type, + u16 *status, u16 *change, u32 *ext_status) { int ret; + int len = 4; + + if (type != HUB_PORT_STATUS) + len = 8; mutex_lock(&hub->status_mutex); - ret = get_port_status(hub->hdev, port1, &hub->status->port); - if (ret < 4) { + ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len); + if (ret < len) { if (ret != -ENODEV) dev_err(hub->intfdev, "%s failed (err = %d)\n", __func__, ret); @@ -568,13 +573,22 @@ static int hub_port_status(struct usb_hub *hub, int port1, } else { *status = le16_to_cpu(hub->status->port.wPortStatus); *change = le16_to_cpu(hub->status->port.wPortChange); - + if (type != HUB_PORT_STATUS && ext_status) + *ext_status = le32_to_cpu( + hub->status->port.dwExtPortStatus); ret = 0; } mutex_unlock(&hub->status_mutex); return ret; } +static int hub_port_status(struct usb_hub *hub, int port1, + u16 *status, u16 *change) +{ + return hub_ext_port_status(hub, port1, HUB_PORT_STATUS, + status, change, NULL); +} + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -2612,6 +2626,32 @@ out_authorized: return result; } +/* + * Return 1 if port speed is SuperSpeedPlus, 0 otherwise + * check it from the link protocol field of the current speed ID attribute. + * current speed ID is got from ext port status request. Sublink speed attribute + * table is returned with the hub BOS SSP device capability descriptor + */ +static int port_speed_is_ssp(struct usb_device *hdev, int speed_id) +{ + int ssa_count; + u32 ss_attr; + int i; + struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap; + + if (!ssp_cap) + return 0; + + ssa_count = le32_to_cpu(ssp_cap->bmAttributes) & + USB_SSP_SUBLINK_SPEED_ATTRIBS; + + for (i = 0; i <= ssa_count; i++) { + ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]); + if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID)) + return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP); + } + return 0; +} /* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ static unsigned hub_is_wusb(struct usb_hub *hub) @@ -2676,6 +2716,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, int delay_time, ret; u16 portstatus; u16 portchange; + u32 ext_portstatus = 0; for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; @@ -2684,7 +2725,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, msleep(delay); /* read and decode port status */ - ret = hub_port_status(hub, port1, &portstatus, &portchange); + if (hub_is_superspeedplus(hub->hdev)) + ret = hub_ext_port_status(hub, port1, + HUB_EXT_PORT_STATUS, + &portstatus, &portchange, + &ext_portstatus); + else + ret = hub_port_status(hub, port1, &portstatus, + &portchange); if (ret < 0) return ret; @@ -2727,6 +2775,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, if (hub_is_wusb(hub)) udev->speed = USB_SPEED_WIRELESS; + else if (hub_is_superspeedplus(hub->hdev) && + port_speed_is_ssp(hub->hdev, ext_portstatus & + USB_EXT_PORT_STAT_RX_SPEED_ID)) + udev->speed = USB_SPEED_SUPER_PLUS; else if (hub_is_superspeed(hub->hdev)) udev->speed = USB_SPEED_SUPER; else if (portstatus & USB_PORT_STAT_HIGH_SPEED) diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 45d070dd1d03..34c1a7e22aae 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -140,6 +140,13 @@ static inline int hub_is_superspeed(struct usb_device *hdev) return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS; } +static inline int hub_is_superspeedplus(struct usb_device *hdev) +{ + return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS && + le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 && + hdev->bos->ssp_cap); +} + static inline unsigned hub_power_on_good_delay(struct usb_hub *hub) { unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2; -- cgit v1.2.3 From f8868ed0078a8456ac725103a97cbe6d833e13f3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 10 Dec 2015 16:49:14 +0200 Subject: usb: core: use kbasename() instead of open-coded variant kbasename() helper is dedicated to find a last part of the filename or pathname. USB core uses open-coded variant of that helper. Replace some lines of code by kbasename() call. The current users do not have trailing slash and we are on the safe side to make such change. I dig a history of the code under question up and found the patch [1] that brought it along with the same to tty layer. The check for trailing slash looks like copy'n'paste thing and I consider it as redundant. [1] http://www.kernel.org/pub/linux/kernel//people/akpm/patches/2.5/2.5.69/2.5.69-mm3/broken-out/linus.patch Signed-off-by: Andy Shevchenko Cc: Greg Kroah-Hartman Cc: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index ea337a718cc1..822ced9639aa 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "usb.h" @@ -155,7 +156,6 @@ int usb_register_dev(struct usb_interface *intf, int minor_base = class_driver->minor_base; int minor; char name[20]; - char *temp; #ifdef CONFIG_USB_DYNAMIC_MINORS /* @@ -192,14 +192,9 @@ int usb_register_dev(struct usb_interface *intf, /* 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); + "%s", kbasename(name)); if (IS_ERR(intf->usb_dev)) { down_write(&minor_rwsem); usb_minors[minor] = NULL; -- cgit v1.2.3 From 69ab55d7be6c3d69fa2e38f2a2bed4e91b9edf8d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Dec 2015 21:26:50 +0800 Subject: USB: core, devio: use to_usb_device Use to_usb_device() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 +- drivers/usb/core/usb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 054eb534c495..13a4b9f48739 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -848,7 +848,7 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt) (void *) (unsigned long) devt, match_devt); if (!dev) return NULL; - return container_of(dev, struct usb_device, dev); + return to_usb_device(dev); } /* diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index ebb29caa3fe4..49b011f951b3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -241,7 +241,7 @@ static int __each_dev(struct device *dev, void *data) if (!is_usb_device(dev)) return 0; - return arg->fn(container_of(dev, struct usb_device, dev), arg->data); + return arg->fn(to_usb_device(dev), arg->data); } /** -- cgit v1.2.3 From 6ae706aeaf42cd2fe6e541c72af6e2c0befe057c Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Dec 2015 21:26:51 +0800 Subject: USB: core, wusbcore: use bus_to_hcd Use bus_to_hcd() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 6 +++--- drivers/usb/core/hub.c | 2 +- drivers/usb/core/usb.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9af9506352f3..232c8c93dd3a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2237,7 +2237,7 @@ int usb_hcd_get_frame_number (struct usb_device *udev) int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) { - struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); + struct usb_hcd *hcd = bus_to_hcd(rhdev->bus); int status; int old_state = hcd->state; @@ -2286,7 +2286,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) { - struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); + struct usb_hcd *hcd = bus_to_hcd(rhdev->bus); int status; int old_state = hcd->state; @@ -2400,7 +2400,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) * 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); + hcd = bus_to_hcd(bus); if (port_num && hcd->driver->start_port_reset) status = hcd->driver->start_port_reset(hcd, port_num); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3c9b22eb78ca..9ec5733b62f4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2659,7 +2659,7 @@ 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); + hcd = bus_to_hcd(hub->hdev->bus); return hcd->wireless; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 49b011f951b3..16ade41759cd 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -397,7 +397,7 @@ struct device_type usb_device_type = { /* 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); + struct usb_hcd *hcd = bus_to_hcd(bus); return hcd->wireless; } -- cgit v1.2.3 From 5363de75307e333d89df7531f9dd8310d973ecdb Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 25 Jan 2016 20:30:30 +0100 Subject: usb: core: switch bus numbering to using idr USB bus numbering is based on directly dealing with bitmaps and defines a separate list of busses. This can be simplified and unified by using existing idr functionality. Signed-off-by: Heiner Kallweit Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 10 ++-------- drivers/usb/core/hcd.c | 21 ++++++--------------- drivers/usb/core/usb.c | 1 + 3 files changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index b35a6a52210f..6118a04f0b84 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -110,13 +110,6 @@ 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 @@ -618,6 +611,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, struct usb_bus *bus; ssize_t ret, total_written = 0; loff_t skip_bytes = *ppos; + int id; if (*ppos < 0) return -EINVAL; @@ -628,7 +622,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, mutex_lock(&usb_bus_list_lock); /* print devices for all busses */ - list_for_each_entry(bus, &usb_bus_list, bus_list) { + idr_for_each_entry(&usb_bus_idr, bus, id) { /* recurse through all children of the root hub */ if (!bus_to_hcd(bus)->rh_registered) continue; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 232c8c93dd3a..cf3eb22dbeb4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -90,12 +90,11 @@ 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); +DEFINE_IDR (usb_bus_idr); +EXPORT_SYMBOL_GPL (usb_bus_idr); /* used when allocating bus numbers */ #define USB_MAXBUS 64 -static DECLARE_BITMAP(busmap, USB_MAXBUS); /* used when updating list of hcds */ DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ @@ -996,8 +995,6 @@ static void usb_bus_init (struct usb_bus *bus) bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; mutex_init(&bus->usb_address0_mutex); - - INIT_LIST_HEAD (&bus->bus_list); } /*-------------------------------------------------------------------------*/ @@ -1018,16 +1015,12 @@ static int usb_register_bus(struct usb_bus *bus) int busnum; mutex_lock(&usb_bus_list_lock); - busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1); - if (busnum >= USB_MAXBUS) { - printk (KERN_ERR "%s: too many buses\n", usbcore_name); + busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL); + if (busnum < 0) { + pr_err("%s: failed to get bus number\n", usbcore_name); goto error_find_busnum; } - set_bit(busnum, 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); @@ -1059,12 +1052,10 @@ static void usb_deregister_bus (struct usb_bus *bus) * itself up */ mutex_lock(&usb_bus_list_lock); - list_del (&bus->bus_list); + idr_remove(&usb_bus_idr, bus->busnum); mutex_unlock(&usb_bus_list_lock); usb_notify_remove_bus(bus); - - clear_bit(bus->busnum, busmap); } /** diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 16ade41759cd..524c9822d2bb 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1115,6 +1115,7 @@ static void __exit usb_exit(void) bus_unregister(&usb_bus_type); usb_acpi_unregister(); usb_debugfs_cleanup(); + idr_destroy(&usb_bus_idr); } subsys_initcall(usb_init); -- cgit v1.2.3 From 7dd9cba5bb90ffa9c60c1533b715dc91c5082cd9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 21 Jan 2016 15:18:47 +0100 Subject: usb: sysfs: make locking interruptible 232275a USB: fix substandard locking for the sysfs files introduced needed locking into sysfs operations on USB devices It, however, uses uninterruptible sleep and if the error handling is on extreme cases of sleep lengths of 10s of seconds are possible. Unless we are removing the device we should use interruptible sleep. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 69 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 20 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index f195320d35c0..7a6209314997 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ - ssize_t rc = 0; \ + ssize_t rc; \ \ udev = to_usb_device(dev); \ - usb_lock_device(udev); \ + rc = usb_lock_device_interruptible(udev); \ + if (rc < 0) \ + return -EINTR; \ actconfig = udev->actconfig; \ if (actconfig) \ rc = sprintf(buf, format_string, \ @@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; - ssize_t rc = 0; + ssize_t rc; udev = to_usb_device(dev); - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; actconfig = udev->actconfig; if (actconfig) rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); @@ -64,10 +68,12 @@ static ssize_t configuration_show(struct device *dev, { struct usb_device *udev; struct usb_host_config *actconfig; - ssize_t rc = 0; + ssize_t rc; udev = to_usb_device(dev); - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; actconfig = udev->actconfig; if (actconfig && actconfig->string) rc = sprintf(buf, "%s\n", actconfig->string); @@ -84,11 +90,13 @@ static ssize_t bConfigurationValue_store(struct device *dev, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int config, value; + int config, value, rc; if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) return -EINVAL; - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; value = usb_set_configuration(udev, config); usb_unlock_device(udev); return (value < 0) ? value : count; @@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \ int retval; \ \ udev = to_usb_device(dev); \ - usb_lock_device(udev); \ + retval = usb_lock_device_interruptible(udev); \ + if (retval < 0) \ + return -EINTR; \ retval = sprintf(buf, "%s\n", udev->name); \ usb_unlock_device(udev); \ return retval; \ @@ -227,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int val; + int val, rc; if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1) return -EINVAL; - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; if (val) udev->quirks |= USB_QUIRK_RESET; else @@ -297,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int value; + int value, rc; /* Hubs are always enabled for USB_PERSIST */ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) @@ -306,7 +318,9 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr, if (sscanf(buf, "%d", &value) != 1) return -EINVAL; - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; udev->persist_enabled = !!value; usb_unlock_device(udev); return count; @@ -423,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr, int len = count; char *cp; int rc = count; + int rv; warn_level(); cp = memchr(buf, '\n', count); if (cp) len = cp - buf; - usb_lock_device(udev); + rv = usb_lock_device_interruptible(udev); + if (rv < 0) + return -EINTR; if (len == sizeof on_string - 1 && strncmp(buf, on_string, len) == 0) @@ -469,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, bool value; int ret; - usb_lock_device(udev); + ret = usb_lock_device_interruptible(udev); + if (ret < 0) + return -EINTR; ret = strtobool(buf, &value); @@ -539,8 +558,11 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, { struct usb_device *udev = to_usb_device(dev); const char *p; + int rc; - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; if (udev->usb3_lpm_u1_enabled) p = "enabled"; @@ -558,8 +580,11 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, { struct usb_device *udev = to_usb_device(dev); const char *p; + int rc; - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; if (udev->usb3_lpm_u2_enabled) p = "enabled"; @@ -818,14 +843,16 @@ read_descriptors(struct file *filp, struct kobject *kobj, struct usb_device *udev = to_usb_device(dev); size_t nleft = count; size_t srclen, n; - int cfgno; + int cfgno, rc; 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). */ - usb_lock_device(udev); + rc = usb_lock_device_interruptible(udev); + if (rc < 0) + return -EINTR; for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && nleft > 0; ++cfgno) { if (cfgno < 0) { @@ -972,7 +999,9 @@ static ssize_t supports_autosuspend_show(struct device *dev, { int s; - device_lock(dev); + s = device_lock_interruptible(dev); + if (s < 0) + return -EINTR; /* Devices will be autosuspended even when an interface isn't claimed */ s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); device_unlock(dev); -- cgit v1.2.3 From b4a90d04ac79349799f65dfd7fa30b2aac6b2a4d Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 21 Jan 2016 15:18:48 +0100 Subject: usb: no locking for reading descriptors in sysfs Quting the relevant thread: > In fact, I suspect the locking added by the kernel 3.13 commit for > read_descriptors() is invalid because read_descriptors() performs no USB > activity; read_descriptors() just reads information from an allocated > memory structure. This structure is protected as the structure is > existing before and after the sysfs vfs descriptors entry is created or > destroyed. You're right. For some reason I thought that usb_deauthorize_device() would destroy the rawdescriptor structures (as mentioned in that commit's Changelog), but it doesn't. The locking in read_descriptors() is unnecessary. > The information is only written at the time of enumeration > and does not change. At least that is my understanding. > > It is noted that in our testing of kernel 3.8 on ARM, that sysfs > read_descriptors() was non-blocking because the kernel 3.13 comment was > not there. > > The pre-kernel 3.13 sysfs read_descriptors() seemed to work OK. > > Proposal: > ========= > > Remove the usb_lock_device(udev) and usb_unlock_device(udev) from > devices/usb/core/sysfs.c in read_descriptors() that was added by the > kernel 3.13 commit > "232275a USB: fix substandard locking for the sysfs files" > > Any comments to this proposal ? It seems okay to me. Please submit a patch. So this removes the locking making the point about -EINTR in the first path moot. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 7a6209314997..c953a0f1c695 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -843,16 +843,13 @@ read_descriptors(struct file *filp, struct kobject *kobj, struct usb_device *udev = to_usb_device(dev); size_t nleft = count; size_t srclen, n; - int cfgno, rc; + 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). */ - rc = usb_lock_device_interruptible(udev); - if (rc < 0) - return -EINTR; for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && nleft > 0; ++cfgno) { if (cfgno < 0) { @@ -873,7 +870,6 @@ read_descriptors(struct file *filp, struct kobject *kobj, off -= srclen; } } - usb_unlock_device(udev); return count - nleft; } -- cgit v1.2.3 From a4b5d606b957c6a58e991de63fe999492de1ab92 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 3 Feb 2016 23:35:23 +0100 Subject: usb: core: rename mutex usb_bus_list_lock to usb_bus_idr_lock Now that usb_bus_list has been removed and switched to idr rename the related mutex accordingly. Signed-off-by: Heiner Kallweit Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 6 +++--- drivers/usb/core/hcd.c | 30 +++++++++++++++--------------- drivers/usb/core/hub.c | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 6118a04f0b84..ef04b50e6bbb 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -620,7 +620,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, if (!access_ok(VERIFY_WRITE, buf, nbytes)) return -EFAULT; - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); /* print devices for all busses */ idr_for_each_entry(&usb_bus_idr, bus, id) { /* recurse through all children of the root hub */ @@ -631,12 +631,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, bus->root_hub, bus, 0, 0, 0); usb_unlock_device(bus->root_hub); if (ret < 0) { - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); return ret; } total_written += ret; } - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); return total_written; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cf3eb22dbeb4..0b8a91004737 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -97,8 +97,8 @@ EXPORT_SYMBOL_GPL (usb_bus_idr); #define USB_MAXBUS 64 /* used when updating list of hcds */ -DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ -EXPORT_SYMBOL_GPL (usb_bus_list_lock); +DEFINE_MUTEX(usb_bus_idr_lock); /* exported only for usbfs */ +EXPORT_SYMBOL_GPL (usb_bus_idr_lock); /* used for controlling access to virtual root hubs */ static DEFINE_SPINLOCK(hcd_root_hub_lock); @@ -1014,14 +1014,14 @@ static int usb_register_bus(struct usb_bus *bus) int result = -E2BIG; int busnum; - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL); if (busnum < 0) { pr_err("%s: failed to get bus number\n", usbcore_name); goto error_find_busnum; } bus->busnum = busnum; - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); usb_notify_add_bus(bus); @@ -1030,7 +1030,7 @@ static int usb_register_bus(struct usb_bus *bus) return 0; error_find_busnum: - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); return result; } @@ -1051,9 +1051,9 @@ static void usb_deregister_bus (struct usb_bus *bus) * controller code, as well as having it call this when cleaning * itself up */ - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); idr_remove(&usb_bus_idr, bus->busnum); - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); usb_notify_remove_bus(bus); } @@ -1083,12 +1083,12 @@ static int register_root_hub(struct usb_hcd *hcd) set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", dev_name(&usb_dev->dev), retval); return (retval < 0) ? retval : -EMSGSIZE; @@ -1099,7 +1099,7 @@ static int register_root_hub(struct usb_hcd *hcd) if (!retval) { usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev); } else if (usb_dev->speed >= USB_SPEED_SUPER) { - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); dev_dbg(parent_dev, "can't read %s bos descriptor %d\n", dev_name(&usb_dev->dev), retval); return retval; @@ -1119,7 +1119,7 @@ static int register_root_hub(struct usb_hcd *hcd) if (HCD_DEAD(hcd)) usb_hc_died (hcd); /* This time clean up */ } - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); return retval; } @@ -2885,9 +2885,9 @@ error_create_attr_group: #ifdef CONFIG_PM cancel_work_sync(&hcd->wakeup_work); #endif - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); usb_disconnect(&rhdev); /* Sets rhdev to NULL */ - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); err_register_root_hub: hcd->rh_pollable = 0; clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); @@ -2954,9 +2954,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif - mutex_lock(&usb_bus_list_lock); + mutex_lock(&usb_bus_idr_lock); usb_disconnect(&rhdev); /* Sets rhdev to NULL */ - mutex_unlock(&usb_bus_list_lock); + mutex_unlock(&usb_bus_idr_lock); /* * tasklet_kill() isn't needed here because: diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f912fe6bbc0b..3d46d03a785b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2145,7 +2145,7 @@ static void hub_disconnect_children(struct usb_device *udev) * Something got disconnected. Get rid of it and all of its children. * * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then the caller must hold the usb_bus_list_lock, + * If *pdev is a root hub then the caller must hold the usb_bus_idr_lock, * which protects the set of root hubs as well as the list of buses. * * Only hub drivers (including virtual root hub drivers for host @@ -2443,7 +2443,7 @@ static void set_usb_port_removable(struct usb_device *udev) * 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 + * usb_bus_idr_lock (if udev is a root hub). The parent's pointer to * udev has already been installed, but udev is not yet visible through * sysfs or other filesystem code. * -- cgit v1.2.3 From a44007a42dfd8e487537c7b1f8045577b28a4d95 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Mon, 26 Oct 2015 09:25:36 +0530 Subject: drivers: usb: removed assignment of 0 to static variables fixing the error reported by script checkpatch.pl static variables blinkenlights and old_scheme_first were initialised to 0, correcting it. Signed-off-by: Saurabh Sengar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3d46d03a785b..681036d00528 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -49,7 +49,7 @@ static void hub_event(struct work_struct *work); DEFINE_MUTEX(usb_port_peer_mutex); /* cycle leds on hubs that aren't blinking for attention */ -static bool blinkenlights = 0; +static bool blinkenlights; module_param(blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs"); @@ -78,7 +78,7 @@ MODULE_PARM_DESC(initial_descriptor_timeout, * 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; +static bool old_scheme_first; module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -- cgit v1.2.3 From b37d83a6a41499d582b8faedff1913ec75d9e70b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 12 Feb 2016 16:40:13 +0200 Subject: usb: Parse the new USB 3.1 SuperSpeedPlus Isoc endpoint companion descriptor USB 3.1 devices can return a new SuperSpeedPlus isoc endpoint companion descriptor for a isochronous endpoint that requires more than 48K bytes per Service Interval. The new descriptor immediately follows the old USB 3.0 SuperSpeed Endpoint Companion and will provide a new BytesPerInterval value. It is parsed and stored in struct usb_host_endpoint with the other endpoint related descriptors, and should be used by USB3.1 capable hosts to reserve bus time in the schedule. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index bbcf4009f99e..58d089802ab3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -43,6 +43,27 @@ static int find_next_descriptor(unsigned char *buffer, int size, return buffer - buffer0; } +static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev, + int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, + unsigned char *buffer, int size) +{ + struct usb_ssp_isoc_ep_comp_descriptor *desc; + + /* + * The SuperSpeedPlus Isoc endpoint companion descriptor immediately + * follows the SuperSpeed Endpoint Companion descriptor + */ + desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer; + if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP || + size < USB_DT_SSP_ISOC_EP_COMP_SIZE) { + dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion" + "for config %d interface %d altsetting %d ep %d.\n", + cfgno, inum, asnum, ep->desc.bEndpointAddress); + return; + } + memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE); +} + static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, unsigned char *buffer, int size) @@ -54,6 +75,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, * be the first thing immediately following the endpoint descriptor. */ desc = (struct usb_ss_ep_comp_descriptor *) buffer; + buffer += desc->bLength; + size -= desc->bLength; + 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 " @@ -112,6 +136,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 16; } else if (usb_endpoint_xfer_isoc(&ep->desc) && + !USB_SS_SSP_ISOC_COMP(desc->bmAttributes) && USB_SS_MULT(desc->bmAttributes) > 3) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " @@ -121,6 +146,12 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ep->ss_ep_comp.bmAttributes = 2; } + /* Parse a possible SuperSpeedPlus isoc ep companion descriptor */ + if (usb_endpoint_xfer_isoc(&ep->desc) && + USB_SS_SSP_ISOC_COMP(desc->bmAttributes)) + usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum, + ep, buffer, size); + if (usb_endpoint_xfer_isoc(&ep->desc)) max_tx = (desc->bMaxBurst + 1) * (USB_SS_MULT(desc->bmAttributes)) * -- cgit v1.2.3 From faee822c5a7ab99de25cd34fcde3f8d37b6b9923 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 12 Feb 2016 16:40:14 +0200 Subject: usb: Add USB 3.1 Precision time measurement capability descriptor support USB 3.1 devices that support precision time measurement have an additional PTM cabaility descriptor as part of the full BOS descriptor Look for this descriptor while parsing the BOS descriptor, and store it in struct usb_hub_bos if it exists. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 58d089802ab3..5eb1a87228b4 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -894,6 +894,9 @@ int usb_get_bos_descriptor(struct usb_device *dev) dev->bos->ss_id = (struct usb_ss_container_id_descriptor *)buffer; break; + case USB_PTM_CAP_TYPE: + dev->bos->ptm_cap = + (struct usb_ptm_cap_descriptor *)buffer; default: break; } -- cgit v1.2.3 From f7d34b445abc00e979b7cf36b9580ac3d1a47cd8 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 3 Feb 2016 22:58:26 +0100 Subject: USB: Add support for usbfs zerocopy. Add a new interface for userspace to preallocate memory that can be used with usbfs. This gives two primary benefits: - Zerocopy; data no longer needs to be copied between the userspace and the kernel, but can instead be read directly by the driver from userspace's buffers. This works for all kinds of transfers (even if nonsensical for control and interrupt transfers); isochronous also no longer need to memset() the buffer to zero to avoid leaking kernel data. - Once the buffers are allocated, USB transfers can no longer fail due to memory fragmentation; previously, long-running programs could run into problems finding a large enough contiguous memory chunk, especially on embedded systems or at high rates. Memory is allocated by using mmap() against the usbfs file descriptor, and similarly deallocated by munmap(). Once memory has been allocated, using it as pointers to a bulk or isochronous operation means you will automatically get zerocopy behavior. Note that this also means you cannot modify outgoing data until the transfer is complete. The same holds for data on the same cache lines as incoming data; DMA modifying them at the same time could lead to your changes being overwritten. There's a new capability USBDEVFS_CAP_MMAP that userspace can query to see if the running kernel supports this functionality, if just trying mmap() is not acceptable. Largely based on a patch by Markus Rechberger with some updates. The original patch can be found at: http://sundtek.de/support/devio_mmap_v0.4.diff Signed-off-by: Steinar H. Gunderson Signed-off-by: Markus Rechberger Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 227 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 202 insertions(+), 25 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 13a4b9f48739..39da1662b76f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,7 @@ struct usb_dev_state { spinlock_t lock; /* protects the async urb lists */ struct list_head async_pending; struct list_head async_completed; + struct list_head memory_list; wait_queue_head_t wait; /* wake up if a request completed */ unsigned int discsignr; struct pid *disc_pid; @@ -79,6 +81,17 @@ struct usb_dev_state { u32 disabled_bulk_eps; }; +struct usb_memory { + struct list_head memlist; + int vma_use_count; + int urb_use_count; + u32 size; + void *mem; + dma_addr_t dma_handle; + unsigned long vm_start; + struct usb_dev_state *ps; +}; + struct async { struct list_head asynclist; struct usb_dev_state *ps; @@ -89,6 +102,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + struct usb_memory *usbm; unsigned int mem_usage; int status; u32 secid; @@ -162,6 +176,111 @@ static int connected(struct usb_dev_state *ps) ps->dev->state != USB_STATE_NOTATTACHED); } +static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) +{ + struct usb_dev_state *ps = usbm->ps; + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); + --*count; + if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) { + list_del(&usbm->memlist); + spin_unlock_irqrestore(&ps->lock, flags); + + usb_free_coherent(ps->dev, usbm->size, usbm->mem, + usbm->dma_handle); + usbfs_decrease_memory_usage( + usbm->size + sizeof(struct usb_memory)); + kfree(usbm); + } else { + spin_unlock_irqrestore(&ps->lock, flags); + } +} + +static void usbdev_vm_open(struct vm_area_struct *vma) +{ + struct usb_memory *usbm = vma->vm_private_data; + unsigned long flags; + + spin_lock_irqsave(&usbm->ps->lock, flags); + ++usbm->vma_use_count; + spin_unlock_irqrestore(&usbm->ps->lock, flags); +} + +static void usbdev_vm_close(struct vm_area_struct *vma) +{ + struct usb_memory *usbm = vma->vm_private_data; + + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); +} + +struct vm_operations_struct usbdev_vm_ops = { + .open = usbdev_vm_open, + .close = usbdev_vm_close +}; + +static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct usb_memory *usbm = NULL; + struct usb_dev_state *ps = file->private_data; + size_t size = vma->vm_end - vma->vm_start; + void *mem; + unsigned long flags; + dma_addr_t dma_handle; + int ret; + + ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory)); + if (ret) + goto error; + + usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL); + if (!usbm) { + ret = -ENOMEM; + goto error_decrease_mem; + } + + mem = usb_alloc_coherent(ps->dev, size, GFP_USER, &dma_handle); + if (!mem) { + ret = -ENOMEM; + goto error_free_usbm; + } + + memset(mem, 0, size); + + usbm->mem = mem; + usbm->dma_handle = dma_handle; + usbm->size = size; + usbm->ps = ps; + usbm->vm_start = vma->vm_start; + usbm->vma_use_count = 1; + INIT_LIST_HEAD(&usbm->memlist); + + if (remap_pfn_range(vma, vma->vm_start, + virt_to_phys(usbm->mem) >> PAGE_SHIFT, + size, vma->vm_page_prot) < 0) { + dec_usb_memory_use_count(usbm, &usbm->vma_use_count); + return -EAGAIN; + } + + vma->vm_flags |= VM_IO; + vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_ops = &usbdev_vm_ops; + vma->vm_private_data = usbm; + + spin_lock_irqsave(&ps->lock, flags); + list_add_tail(&usbm->memlist, &ps->memory_list); + spin_unlock_irqrestore(&ps->lock, flags); + + return 0; + +error_free_usbm: + kfree(usbm); +error_decrease_mem: + usbfs_decrease_memory_usage(size + sizeof(struct usb_memory)); +error: + return ret; +} + static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { @@ -278,8 +397,13 @@ static void free_async(struct async *as) if (sg_page(&as->urb->sg[i])) kfree(sg_virt(&as->urb->sg[i])); } + kfree(as->urb->sg); - kfree(as->urb->transfer_buffer); + if (as->usbm == NULL) + kfree(as->urb->transfer_buffer); + else + dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count); + kfree(as->urb->setup_packet); usb_free_urb(as->urb); usbfs_decrease_memory_usage(as->mem_usage); @@ -893,6 +1017,7 @@ static int usbdev_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&ps->list); INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); + INIT_LIST_HEAD(&ps->memory_list); init_waitqueue_head(&ps->wait); ps->discsignr = 0; ps->disc_pid = get_pid(task_pid(current)); @@ -945,6 +1070,7 @@ static int usbdev_release(struct inode *inode, struct file *file) free_async(as); as = async_getcompleted(ps); } + kfree(ps); return 0; } @@ -1266,6 +1392,31 @@ static int proc_setconfig(struct usb_dev_state *ps, void __user *arg) return status; } +static struct usb_memory * +find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb) +{ + struct usb_memory *usbm = NULL, *iter; + unsigned long flags; + unsigned long uurb_start = (unsigned long)uurb->buffer; + + spin_lock_irqsave(&ps->lock, flags); + list_for_each_entry(iter, &ps->memory_list, memlist) { + if (uurb_start >= iter->vm_start && + uurb_start < iter->vm_start + iter->size) { + if (uurb->buffer_length > iter->vm_start + iter->size - + uurb_start) { + usbm = ERR_PTR(-EINVAL); + } else { + usbm = iter; + usbm->urb_use_count++; + } + break; + } + } + spin_unlock_irqrestore(&ps->lock, flags); + return usbm; +} + static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, struct usbdevfs_iso_packet_desc __user *iso_frame_desc, void __user *arg) @@ -1421,6 +1572,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb goto error; } + as->usbm = find_memory_area(ps, uurb); + if (IS_ERR(as->usbm)) { + ret = PTR_ERR(as