From 6ff10464096540e14d7575a72c50d0316d003714 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 9 Mar 2009 13:44:02 -0400 Subject: USB: usbfs: keep async URBs until the device file is closed The usbfs driver manages a list of completed asynchronous URBs. But it is too eager to free the entries on this list: destroy_async() gets called whenever an interface is unbound or a device is removed, and it deallocates the outstanding struct async entries for all URBs on that interface or device. This is wrong; the user program should be able to reap an URB any time after it has completed, regardless of whether or not the interface is still bound or the device is still present. This patch (as1222) moves the code for deallocating the completed list entries from destroy_async() to usbdev_release(). The outstanding entries won't be freed until the user program has closed the device file, thereby eliminating any possibility that the remaining URBs might still be reaped. This fixes a bug in which a program can hang in the USBDEVFS_REAPURB ioctl when the device is unplugged. Reported-and-tested-by: Martin Poupe Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 7513bb0..6585f52 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -359,11 +359,6 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); - as = async_getcompleted(ps); - while (as) { - free_async(as); - as = async_getcompleted(ps); - } } static void destroy_async_on_interface(struct dev_state *ps, @@ -643,6 +638,7 @@ static int usbdev_release(struct inode *inode, struct file *file) struct dev_state *ps = file->private_data; struct usb_device *dev = ps->dev; unsigned int ifnum; + struct async *as; usb_lock_device(dev); @@ -661,6 +657,12 @@ static int usbdev_release(struct inode *inode, struct file *file) usb_unlock_device(dev); usb_put_dev(dev); put_pid(ps->disc_pid); + + as = async_getcompleted(ps); + while (as) { + free_async(as); + as = async_getcompleted(ps); + } kfree(ps); return 0; } -- cgit v1.1 From 1662e3a7f076e51e3073faf9ce77157b529c475b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 18 Mar 2009 14:28:53 -0400 Subject: USB: add quirk to avoid config and interface strings Apparently the Configuration and Interface strings aren't used as often as the Vendor, Product, and Serial strings. In at least one device (a Saitek Cyborg Gold 3D joystick), attempts to read the Configuration string cause the device to stop responding to Control requests. This patch (as1226) adds a quirks flag, telling the kernel not to read a device's Configuration or Interface strings, together with a new quirk for the offending joystick. Reported-by: Melchior FRANZ Tested-by: Melchior FRANZ Signed-off-by: Alan Stern Cc: stable [2.6.28 and 2.6.29, nothing earlier] Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 3 ++- drivers/usb/core/quirks.c | 4 ++++ drivers/usb/core/sysfs.c | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 49e7f56..3922fa9 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1719,7 +1719,8 @@ free_interfaces: } kfree(new_interfaces); - if (cp->string == NULL) + if (cp->string == NULL && + !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); /* Now that all the interfaces are set up, register them diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index c070b34..ab93918 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -54,6 +54,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0638, 0x0a13), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + /* Saitek Cyborg Gold Joystick */ + { USB_DEVICE(0x06a3, 0x0006), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4cc2456..c667891 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "usb.h" /* Active configuration fields */ @@ -813,7 +814,8 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf) if (intf->sysfs_files_created || intf->unregistering) return 0; - if (alt->string == NULL) + if (alt->string == NULL && + !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) alt->string = usb_cache_string(udev, alt->desc.iInterface); if (alt->string) retval = device_create_file(&intf->dev, &dev_attr_interface); -- cgit v1.1 From 2e0fe709687470637a0709b930ccc9e993d2dad5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 29 Dec 2008 11:22:14 +0100 Subject: USB: drivers: use USB API functions rather than constants This set of patches introduces calls to the following set of functions: usb_endpoint_dir_in(epd) usb_endpoint_dir_out(epd) usb_endpoint_is_bulk_in(epd) usb_endpoint_is_bulk_out(epd) usb_endpoint_is_int_in(epd) usb_endpoint_is_int_out(epd) usb_endpoint_num(epd) usb_endpoint_type(epd) usb_endpoint_xfer_bulk(epd) usb_endpoint_xfer_control(epd) usb_endpoint_xfer_int(epd) usb_endpoint_xfer_isoc(epd) In some cases, introducing one of these functions is not possible, and it just replaces an explicit integer value by one of the following constants: USB_ENDPOINT_XFER_BULK USB_ENDPOINT_XFER_CONTROL USB_ENDPOINT_XFER_INT USB_ENDPOINT_XFER_ISOC An extract of the semantic patch that makes these changes is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r1@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bmAttributes & \(USB_ENDPOINT_XFERTYPE_MASK\|3\)) == - \(USB_ENDPOINT_XFER_CONTROL\|0\)) + usb_endpoint_xfer_control(epd) @r5@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bEndpointAddress & \(USB_ENDPOINT_DIR_MASK\|0x80\)) == - \(USB_DIR_IN\|0x80\)) + usb_endpoint_dir_in(epd) @inc@ @@ #include @depends on !inc && (r1||r5)@ @@ + #include #include // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 2 +- drivers/usb/core/endpoint.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 6ec3817..73c108d 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -187,7 +187,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, } /* this isn't checking for illegal values */ - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: type = "Ctrl"; if (speed == USB_SPEED_HIGH) /* uframes per NAK */ diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e1710f2..40dee2a 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -66,7 +66,7 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, struct ep_device *ep = to_ep_device(dev); char *type = "unknown"; - switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: type = "Control"; break; @@ -94,7 +94,7 @@ static ssize_t show_ep_interval(struct device *dev, in = (ep->desc->bEndpointAddress & USB_DIR_IN); - switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ interval = ep->desc->bInterval; @@ -131,10 +131,9 @@ static ssize_t show_ep_direction(struct device *dev, struct ep_device *ep = to_ep_device(dev); char *direction; - if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL) + if (usb_endpoint_xfer_control(ep->desc)) direction = "both"; - else if (ep->desc->bEndpointAddress & USB_DIR_IN) + else if (usb_endpoint_dir_in(ep->desc)) direction = "in"; else direction = "out"; -- cgit v1.1 From 551509d267905705f6d723e51ec706916f06b859 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 11 Feb 2009 14:11:36 -0800 Subject: USB: replace uses of __constant_{endian} The base versions handle constant folding now. Signed-off-by: Harvey Harrison Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hub.c | 8 ++++---- 2 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 3c711db5..0eee32a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -901,7 +901,7 @@ static int register_root_hub(struct usb_hcd *hcd) mutex_lock(&usb_bus_list_lock); - usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); + 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); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index cd50d86..7e33d63 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2471,20 +2471,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, */ switch (udev->speed) { case USB_SPEED_VARIABLE: /* fixed at 512 */ - udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512); + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); break; case USB_SPEED_HIGH: /* fixed at 64 */ - udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); break; case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ /* to determine the ep0 maxpacket size, try to read * the device descriptor to get bMaxPacketSize0 and * then correct our initial guess. */ - udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); break; case USB_SPEED_LOW: /* fixed at 8 */ - udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8); + udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8); break; default: goto fail; -- cgit v1.1 From 6da9c99059bf24fb1faae6b9613bae64ea50c05e Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 18 Feb 2009 14:43:47 +0000 Subject: USB: allow libusb to talk to unauthenticated WUSB devices To permit a userspace application to associate with WUSB devices using numeric association, control transfers to unauthenticated WUSB devices must be allowed. This requires that wusbcore correctly sets the device state to UNAUTHENTICATED, DEFAULT and ADDRESS and that control transfers can be performed to UNAUTHENTICATED devices. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 3 ++- drivers/usb/core/hub.c | 1 + drivers/usb/core/urb.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6585f52..8f022af 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -525,7 +525,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, { int ret = 0; - if (ps->dev->state != USB_STATE_ADDRESS + if (ps->dev->state != USB_STATE_UNAUTHENTICATED + && ps->dev->state != USB_STATE_ADDRESS && ps->dev->state != USB_STATE_CONFIGURED) return -EHOSTUNREACH; if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7e33d63..f17d9eb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1305,6 +1305,7 @@ void usb_set_device_state(struct usb_device *udev, recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } +EXPORT_SYMBOL_GPL(usb_set_device_state); /* * WUSB devices are simple: they have no hubs behind, so the mapping diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 58bc5e3..7025d80 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -295,7 +295,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; dev = urb->dev; - if ((!dev) || (dev->state < USB_STATE_DEFAULT)) + if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) return -ENODEV; /* For now, get the endpoint from the pipe. Eventually drivers -- cgit v1.1 From 4fe0387afa893b44c5a21b9bfbb0888354ef4656 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 26 Feb 2009 10:21:02 -0500 Subject: USB: don't send Set-Interface after reset This patch (as1221) changes the way usbcore reinitializes a device following a reset or a reset-resume. Currently we call usb_set_interface() for every interface in the active configuration; this is to put the interface into the same altsetting as before the reset and to make sure that the host's endpoint state matches the device's endpoint state. However, sending a Set-Interface request is a waste of time if an interface was already in altsetting 0 before the reset, since it is certainly in altsetting 0 afterward. In addition, many devices can't handle Set-Interface requests -- they crash when they receive them. So instead, the patch adds code to check each interface. If the interface wasn't in altsetting 0 before the reset, we go head with the Set-Interface request as before. But if it was then we skip sending the Set-Interface request, and we clear out the host-side endpoint state by calling usb_disable_interface() followed by usb_enable_interface(). The patch also adds a couple of new comments to explain what's going on. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f17d9eb..81eb3e6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3393,10 +3393,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev) udev->descriptor = descriptor; /* for disconnect() calls */ goto re_enumerate; } - + + /* Restore the device's previous configuration */ if (!udev->actconfig) goto done; - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_CONFIGURATION, 0, udev->actconfig->desc.bConfigurationValue, 0, @@ -3409,16 +3409,25 @@ static int usb_reset_and_verify_device(struct usb_device *udev) } usb_set_device_state(udev, USB_STATE_CONFIGURED); + /* Put interfaces back into the same altsettings as before. + * Don't bother to send the Set-Interface request for interfaces + * that were already in altsetting 0; besides being unnecessary, + * many devices can't handle it. Instead just reset the host-side + * endpoint state. + */ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle even - * for altsetting zero. the interface may have no driver. - */ desc = &intf->cur_altsetting->desc; - ret = usb_set_interface(udev, desc->bInterfaceNumber, - desc->bAlternateSetting); + if (desc->bAlternateSetting == 0) { + usb_disable_interface(udev, intf, true); + usb_enable_interface(udev, intf, true); + ret = 0; + } else { + ret = usb_set_interface(udev, desc->bInterfaceNumber, + desc->bAlternateSetting); + } if (ret < 0) { dev_err(&udev->dev, "failed to restore interface %d " "altsetting %d (error=%d)\n", -- cgit v1.1 From d34d9721a559fd11ec682bd9ef17220de0162060 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 9 Mar 2009 13:44:48 -0400 Subject: USB: usbfs: remove unneeded "inline" annotations This patch (as1223) removes a bunch of unnecessary "inline" annotations from the usbfs driver. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8f022af..d3883f6 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -104,7 +104,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define MAX_USBFS_BUFFER_SIZE 16384 -static inline int connected(struct dev_state *ps) +static int connected(struct dev_state *ps) { return (!list_empty(&ps->list) && ps->dev->state != USB_STATE_NOTATTACHED); @@ -248,7 +248,7 @@ static void free_async(struct async *as) kfree(as); } -static inline void async_newpending(struct async *as) +static void async_newpending(struct async *as) { struct dev_state *ps = as->ps; unsigned long flags; @@ -258,7 +258,7 @@ static inline void async_newpending(struct async *as) spin_unlock_irqrestore(&ps->lock, flags); } -static inline void async_removepending(struct async *as) +static void async_removepending(struct async *as) { struct dev_state *ps = as->ps; unsigned long flags; @@ -268,7 +268,7 @@ static inline void async_removepending(struct async *as) spin_unlock_irqrestore(&ps->lock, flags); } -static inline struct async *async_getcompleted(struct dev_state *ps) +static struct async *async_getcompleted(struct dev_state *ps) { unsigned long flags; struct async *as = NULL; @@ -283,7 +283,7 @@ static inline struct async *async_getcompleted(struct dev_state *ps) return as; } -static inline struct async *async_getpending(struct dev_state *ps, +static struct async *async_getpending(struct dev_state *ps, void __user *userurb) { unsigned long flags; @@ -376,7 +376,7 @@ static void destroy_async_on_interface(struct dev_state *ps, destroy_async(ps, &hitlist); } -static inline void destroy_all_async(struct dev_state *ps) +static void destroy_all_async(struct dev_state *ps) { destroy_async(ps, &ps->async_pending); } -- cgit v1.1 From 71d2718f2507dc17501d04e2bdca7b8e694ce365 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 13 Mar 2009 12:19:18 +0100 Subject: USB: more u32 conversion after transfer_buffer_length and actual_length transfer_buffer_length and actual_length have become unsigned, therefore some additional conversion of local variables, function arguments and print specifications is desired. A test for a negative urb->transfer_buffer_length became obsolete; instead we ensure that it does not exceed INT_MAX. Also, urb->actual_length is always less than urb->transfer_buffer_length. rh_string() does no longer return -EPIPE in the case of an unsupported ID. Instead its only caller, rh_call_control() does the check. Signed-off-by: Roel Kluin Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 6 +++--- drivers/usb/core/hcd.c | 31 ++++++++++++------------------- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 2 +- drivers/usb/core/urb.c | 2 +- 5 files changed, 18 insertions(+), 25 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d3883f6..df3c539 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -302,7 +302,7 @@ static struct async *async_getpending(struct dev_state *ps, static void snoop_urb(struct urb *urb, void __user *userurb) { - int j; + unsigned j; unsigned char *data = urb->transfer_buffer; if (!usbfs_snoop) @@ -311,9 +311,9 @@ static void snoop_urb(struct urb *urb, void __user *userurb) dev_info(&urb->dev->dev, "direction=%s\n", usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); - dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", + dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n", urb->transfer_buffer_length); - dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); + dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length); dev_info(&urb->dev->dev, "data: "); for (j = 0; j < urb->transfer_buffer_length; ++j) printk("%02x ", data[j]); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0eee32a..81fa850 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -279,9 +279,9 @@ static const u8 hs_rh_config_descriptor [] = { * helper routine for returning string descriptors in UTF-16LE * input can actually be ISO-8859-1; ASCII is its 7-bit subset */ -static int ascii2utf (char *s, u8 *utf, int utfmax) +static unsigned ascii2utf(char *s, u8 *utf, int utfmax) { - int retval; + unsigned retval; for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { *utf++ = *s++; @@ -304,19 +304,15 @@ static int ascii2utf (char *s, u8 *utf, int utfmax) * Produces either a manufacturer, product or serial number string for the * virtual root hub device. */ -static int rh_string ( - int id, - struct usb_hcd *hcd, - u8 *data, - int len -) { +static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) +{ char buf [100]; // language ids if (id == 0) { buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ - len = min (len, 4); + len = min_t(unsigned, len, 4); memcpy (data, buf, len); return len; @@ -332,10 +328,7 @@ static int rh_string ( } else if (id == 3) { snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, init_utsname()->release, hcd->driver->description); - - // unsupported IDs --> "protocol stall" - } else - return -EPIPE; + } switch (len) { /* All cases fall through */ default: @@ -360,9 +353,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) u8 tbuf [sizeof (struct usb_hub_descriptor)] __attribute__((aligned(4))); const u8 *bufp = tbuf; - int len = 0; + unsigned len = 0; int status; - int n; u8 patch_wakeup = 0; u8 patch_protocol = 0; @@ -456,10 +448,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) patch_wakeup = 1; break; case USB_DT_STRING << 8: - n = rh_string (wValue & 0xff, hcd, ubuf, wLength); - if (n < 0) + if ((wValue & 0xff) < 4) + urb->actual_length = rh_string(wValue & 0xff, + hcd, ubuf, wLength); + else /* unsupported IDs --> "protocol stall" */ goto error; - urb->actual_length = n; break; default: goto error; @@ -629,7 +622,7 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) { int retval; unsigned long flags; - int len = 1 + (urb->dev->maxchild / 8); + unsigned len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->status_urb || urb->transfer_buffer_length < len) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 81eb3e6..be86ae3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -392,7 +392,7 @@ static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; int status = urb->status; - int i; + unsigned i; unsigned long bits; switch (status) { diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3922fa9..293a30d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,7 +59,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status); dev_dbg(&urb->dev->dev, - "%s timed out on ep%d%s len=%d/%d\n", + "%s timed out on ep%d%s len=%u/%u\n", current->comm, usb_endpoint_num(&urb->ep->desc), usb_urb_dir_in(urb) ? "in" : "out", diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 7025d80..3376055 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -370,7 +370,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) } /* the I/O buffer must be mapped/unmapped, except when length=0 */ - if (urb->transfer_buffer_length < 0) + if (urb->transfer_buffer_length > INT_MAX) return -EMSGSIZE; #ifdef DEBUG -- cgit v1.1 From b7af0bb26899bb47ae16fb41d2296111b0784a56 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 20 Mar 2009 19:58:57 +0100 Subject: USB: allow malformed LANGID descriptors When an USB hardware does not provide a valid LANGID, fall back to value zero which is still a reasonable default for most devices. Signed-off-by: Daniel Mack Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/usb/core') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 293a30d..30a0690 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -804,18 +804,16 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) dev_err(&dev->dev, "string descriptor 0 read error: %d\n", err); - goto errout; } else if (err < 4) { dev_err(&dev->dev, "string descriptor 0 too short\n"); - err = -EINVAL; - goto errout; } else { - dev->have_langid = 1; dev->string_langid = tbuf[2] | (tbuf[3] << 8); /* always use the first langid listed */ dev_dbg(&dev->dev, "default language 0x%04x\n", dev->string_langid); } + + dev->have_langid = 1; } err = usb_string_sub(dev, dev->string_langid, index, tbuf); -- cgit v1.1