usb: Parse the new USB 3.1 SuperSpeedPlus Isoc endpoint companion descriptor
authorMathias Nyman <mathias.nyman@linux.intel.com>
Fri, 12 Feb 2016 14:40:13 +0000 (16:40 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 15 Feb 2016 01:03:23 +0000 (17:03 -0800)
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 <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/config.c
include/linux/usb.h

index bbcf4009f99eaa5c0d6119e3c7016ca640cf7da2..58d089802ab3f18fcf65ec77364c41cb6bbdf4fb 100644 (file)
@@ -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)) *
index dc0ea0de8a81d0a301dce453d16f78a66dff1c51..8fc881af87352798e96731002d3d8ef98591dd9b 100644 (file)
@@ -50,6 +50,7 @@ struct ep_device;
  * struct usb_host_endpoint - host-side endpoint descriptor and queue
  * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
  * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint
+ * @ssp_isoc_ep_comp: SuperSpeedPlus isoc companion descriptor for this endpoint
  * @urb_list: urbs queued to this endpoint; maintained by usbcore
  * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
  *     with one or more transfer descriptors (TDs) per urb
@@ -65,6 +66,7 @@ struct ep_device;
 struct usb_host_endpoint {
        struct usb_endpoint_descriptor          desc;
        struct usb_ss_ep_comp_descriptor        ss_ep_comp;
+       struct usb_ssp_isoc_ep_comp_descriptor  ssp_isoc_ep_comp;
        struct list_head                urb_list;
        void                            *hcpriv;
        struct ep_device                *ep_dev;        /* For sysfs info */