Commit b37d83a6 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman

usb: Parse the new USB 3.1 SuperSpeedPlus Isoc endpoint companion descriptor

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: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c8b1d897
...@@ -43,6 +43,27 @@ static int find_next_descriptor(unsigned char *buffer, int size, ...@@ -43,6 +43,27 @@ static int find_next_descriptor(unsigned char *buffer, int size,
return buffer - buffer0; 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, static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int inum, int asnum, struct usb_host_endpoint *ep, int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size) unsigned char *buffer, int size)
...@@ -54,6 +75,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -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. * be the first thing immediately following the endpoint descriptor.
*/ */
desc = (struct usb_ss_ep_comp_descriptor *) buffer; desc = (struct usb_ss_ep_comp_descriptor *) buffer;
buffer += desc->bLength;
size -= desc->bLength;
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
size < USB_DT_SS_EP_COMP_SIZE) { size < USB_DT_SS_EP_COMP_SIZE) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " 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, ...@@ -112,6 +136,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
cfgno, inum, asnum, ep->desc.bEndpointAddress); cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 16; ep->ss_ep_comp.bmAttributes = 16;
} else if (usb_endpoint_xfer_isoc(&ep->desc) && } else if (usb_endpoint_xfer_isoc(&ep->desc) &&
!USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) { USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in " dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: " "config %d interface %d altsetting %d ep %d: "
...@@ -121,6 +146,12 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -121,6 +146,12 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp.bmAttributes = 2; 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)) if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) * max_tx = (desc->bMaxBurst + 1) *
(USB_SS_MULT(desc->bmAttributes)) * (USB_SS_MULT(desc->bmAttributes)) *
......
...@@ -50,6 +50,7 @@ struct ep_device; ...@@ -50,6 +50,7 @@ struct ep_device;
* struct usb_host_endpoint - host-side endpoint descriptor and queue * struct usb_host_endpoint - host-side endpoint descriptor and queue
* @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
* @ss_ep_comp: SuperSpeed companion descriptor for this endpoint * @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 * @urb_list: urbs queued to this endpoint; maintained by usbcore
* @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
* with one or more transfer descriptors (TDs) per urb * with one or more transfer descriptors (TDs) per urb
...@@ -65,6 +66,7 @@ struct ep_device; ...@@ -65,6 +66,7 @@ struct ep_device;
struct usb_host_endpoint { struct usb_host_endpoint {
struct usb_endpoint_descriptor desc; struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp; 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; struct list_head urb_list;
void *hcpriv; void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */ struct ep_device *ep_dev; /* For sysfs info */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment