|
@@ -974,6 +974,47 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Convert interval expressed as 2^(bInterval - 1) == interval into
|
|
|
+ * straight exponent value 2^n == interval.
|
|
|
+ *
|
|
|
+ */
|
|
|
+static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
|
|
|
+ struct usb_host_endpoint *ep)
|
|
|
+{
|
|
|
+ unsigned int interval;
|
|
|
+
|
|
|
+ interval = clamp_val(ep->desc.bInterval, 1, 16) - 1;
|
|
|
+ if (interval != ep->desc.bInterval - 1)
|
|
|
+ dev_warn(&udev->dev,
|
|
|
+ "ep %#x - rounding interval to %d microframes\n",
|
|
|
+ ep->desc.bEndpointAddress,
|
|
|
+ 1 << interval);
|
|
|
+
|
|
|
+ return interval;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Convert bInterval expressed in frames (in 1-255 range) to exponent of
|
|
|
+ * microframes, rounded down to nearest power of 2.
|
|
|
+ */
|
|
|
+static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
|
|
|
+ struct usb_host_endpoint *ep)
|
|
|
+{
|
|
|
+ unsigned int interval;
|
|
|
+
|
|
|
+ interval = fls(8 * ep->desc.bInterval) - 1;
|
|
|
+ interval = clamp_val(interval, 3, 10);
|
|
|
+ if ((1 << interval) != 8 * ep->desc.bInterval)
|
|
|
+ dev_warn(&udev->dev,
|
|
|
+ "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
|
|
|
+ ep->desc.bEndpointAddress,
|
|
|
+ 1 << interval,
|
|
|
+ 8 * ep->desc.bInterval);
|
|
|
+
|
|
|
+ return interval;
|
|
|
+}
|
|
|
+
|
|
|
/* Return the polling or NAK interval.
|
|
|
*
|
|
|
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
|
@@ -991,45 +1032,38 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
|
|
case USB_SPEED_HIGH:
|
|
|
/* Max NAK rate */
|
|
|
if (usb_endpoint_xfer_control(&ep->desc) ||
|
|
|
- usb_endpoint_xfer_bulk(&ep->desc))
|
|
|
+ usb_endpoint_xfer_bulk(&ep->desc)) {
|
|
|
interval = ep->desc.bInterval;
|
|
|
+ break;
|
|
|
+ }
|
|
|
/* Fall through - SS and HS isoc/int have same decoding */
|
|
|
+
|
|
|
case USB_SPEED_SUPER:
|
|
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
|
|
- usb_endpoint_xfer_isoc(&ep->desc)) {
|
|
|
- if (ep->desc.bInterval == 0)
|
|
|
- interval = 0;
|
|
|
- else
|
|
|
- interval = ep->desc.bInterval - 1;
|
|
|
- if (interval > 15)
|
|
|
- interval = 15;
|
|
|
- if (interval != ep->desc.bInterval + 1)
|
|
|
- dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
|
|
|
- ep->desc.bEndpointAddress, 1 << interval);
|
|
|
+ usb_endpoint_xfer_isoc(&ep->desc)) {
|
|
|
+ interval = xhci_parse_exponent_interval(udev, ep);
|
|
|
}
|
|
|
break;
|
|
|
- /* Convert bInterval (in 1-255 frames) to microframes and round down to
|
|
|
- * nearest power of 2.
|
|
|
- */
|
|
|
+
|
|
|
case USB_SPEED_FULL:
|
|
|
+ if (usb_endpoint_xfer_int(&ep->desc)) {
|
|
|
+ interval = xhci_parse_exponent_interval(udev, ep);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * Fall through for isochronous endpoint interval decoding
|
|
|
+ * since it uses the same rules as low speed interrupt
|
|
|
+ * endpoints.
|
|
|
+ */
|
|
|
+
|
|
|
case USB_SPEED_LOW:
|
|
|
if (usb_endpoint_xfer_int(&ep->desc) ||
|
|
|
- usb_endpoint_xfer_isoc(&ep->desc)) {
|
|
|
- interval = fls(8*ep->desc.bInterval) - 1;
|
|
|
- if (interval > 10)
|
|
|
- interval = 10;
|
|
|
- if (interval < 3)
|
|
|
- interval = 3;
|
|
|
- if ((1 << interval) != 8*ep->desc.bInterval)
|
|
|
- dev_warn(&udev->dev,
|
|
|
- "ep %#x - rounding interval"
|
|
|
- " to %d microframes, "
|
|
|
- "ep desc says %d microframes\n",
|
|
|
- ep->desc.bEndpointAddress,
|
|
|
- 1 << interval,
|
|
|
- 8*ep->desc.bInterval);
|
|
|
+ usb_endpoint_xfer_isoc(&ep->desc)) {
|
|
|
+
|
|
|
+ interval = xhci_parse_frame_interval(udev, ep);
|
|
|
}
|
|
|
break;
|
|
|
+
|
|
|
default:
|
|
|
BUG();
|
|
|
}
|