USB: Fix usb_fill_int_urb for SuperSpeed devices
Matthew Wilcox [Tue, 16 Mar 2010 19:55:44 +0000 (12:55 -0700)]
USB 3 and Wireless USB specify a logarithmic encoding of the endpoint
interval that matches the USB 2 specification.  usb_fill_int_urb() didn't
know that and was filling in the interval as if it was USB 1.1.  Fix
usb_fill_int_urb() for SuperSpeed devices, but leave the wireless case
alone, because David Vrabel wants to keep the old encoding.

Update the struct urb kernel doc to note that SuperSpeed URBs must have
urb->interval specified in microframes.

Add a missing break statement in the usb_submit_urb() interrupt URB
checking, since wireless USB and SuperSpeed USB encode urb->interval
differently.  This allows xHCI roothubs to actually register with khubd.

Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/usb/core/urb.c
include/linux/usb.h

index 2708056..45a32da 100644 (file)
@@ -453,6 +453,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        if (urb->interval > (1 << 15))
                                return -EINVAL;
                        max = 1 << 15;
+                       break;
                case USB_SPEED_WIRELESS:
                        if (urb->interval > 16)
                                return -EINVAL;
index 8c9f053..ce1323c 100644 (file)
@@ -1055,7 +1055,8 @@ typedef void (*usb_complete_t)(struct urb *);
  * @number_of_packets: Lists the number of ISO transfer buffers.
  * @interval: Specifies the polling interval for interrupt or isochronous
  *     transfers.  The units are frames (milliseconds) for full and low
- *     speed devices, and microframes (1/8 millisecond) for highspeed ones.
+ *     speed devices, and microframes (1/8 millisecond) for highspeed
+ *     and SuperSpeed devices.
  * @error_count: Returns the number of ISO transfers that reported errors.
  * @context: For use in completion functions.  This normally points to
  *     request-specific driver context.
@@ -1286,9 +1287,16 @@ static inline void usb_fill_bulk_urb(struct urb *urb,
  *
  * Initializes a interrupt urb with the proper information needed to submit
  * it to a device.
- * Note that high speed interrupt endpoints use a logarithmic encoding of
- * the endpoint interval, and express polling intervals in microframes
- * (eight per millisecond) rather than in frames (one per millisecond).
+ *
+ * Note that High Speed and SuperSpeed interrupt endpoints use a logarithmic
+ * encoding of the endpoint interval, and express polling intervals in
+ * microframes (eight per millisecond) rather than in frames (one per
+ * millisecond).
+ *
+ * Wireless USB also uses the logarithmic encoding, but specifies it in units of
+ * 128us instead of 125us.  For Wireless USB devices, the interval is passed
+ * through to the host controller, rather than being translated into microframe
+ * units.
  */
 static inline void usb_fill_int_urb(struct urb *urb,
                                    struct usb_device *dev,
@@ -1305,7 +1313,7 @@ static inline void usb_fill_int_urb(struct urb *urb,
        urb->transfer_buffer_length = buffer_length;
        urb->complete = complete_fn;
        urb->context = context;
-       if (dev->speed == USB_SPEED_HIGH)
+       if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER)
                urb->interval = 1 << (interval - 1);
        else
                urb->interval = interval;