USB: allow interrupt transfers to WUSB devices
authorDavid Vrabel <david.vrabel@csr.com>
Tue, 18 Aug 2009 15:11:24 +0000 (16:11 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 19:55:14 +0000 (11:55 -0800)
Check urb->interval on interrupt transfers and allow those with valid
values (6 <= interval <= 16).

Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/urb.c

index 0885d4abdc6265d0b7775da9b9f5503fc2be0dff..e7cae1334693cf6a88327c331104411ce8092880 100644 (file)
@@ -429,8 +429,16 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
        case USB_ENDPOINT_XFER_ISOC:
        case USB_ENDPOINT_XFER_INT:
                /* too small? */
-               if (urb->interval <= 0)
-                       return -EINVAL;
+               switch (dev->speed) {
+               case USB_SPEED_VARIABLE:
+                       if (urb->interval < 6)
+                               return -EINVAL;
+                       break;
+               default:
+                       if (urb->interval <= 0)
+                               return -EINVAL;
+                       break;
+               }
                /* too big? */
                switch (dev->speed) {
                case USB_SPEED_SUPER:   /* units are 125us */
@@ -438,6 +446,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        if (urb->interval > (1 << 15))
                                return -EINVAL;
                        max = 1 << 15;
+               case USB_SPEED_VARIABLE:
+                       if (urb->interval > 16)
+                               return -EINVAL;
+                       break;
                case USB_SPEED_HIGH:    /* units are microframes */
                        /* NOTE usb handles 2^15 */
                        if (urb->interval > (1024 * 8))
@@ -461,8 +473,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                default:
                        return -EINVAL;
                }
-               /* Round down to a power of 2, no more than max */
-               urb->interval = min(max, 1 << ilog2(urb->interval));
+               if (dev->speed != USB_SPEED_VARIABLE) {
+                       /* Round down to a power of 2, no more than max */
+                       urb->interval = min(max, 1 << ilog2(urb->interval));
+               }
        }
 
        return usb_hcd_submit_urb(urb, mem_flags);