|
@@ -21,32 +21,6 @@ static inline const char *plural(int n)
|
|
|
return (n == 1 ? "" : "s");
|
|
|
}
|
|
|
|
|
|
-/* FIXME: this is a kludge */
|
|
|
-static int find_next_descriptor_more(unsigned char *buffer, int size,
|
|
|
- int dt1, int dt2, int dt3, int *num_skipped)
|
|
|
-{
|
|
|
- struct usb_descriptor_header *h;
|
|
|
- int n = 0;
|
|
|
- unsigned char *buffer0 = buffer;
|
|
|
-
|
|
|
- /* Find the next descriptor of type dt1 or dt2 or dt3 */
|
|
|
- while (size > 0) {
|
|
|
- h = (struct usb_descriptor_header *) buffer;
|
|
|
- if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
|
|
|
- h->bDescriptorType == dt3)
|
|
|
- break;
|
|
|
- buffer += h->bLength;
|
|
|
- size -= h->bLength;
|
|
|
- ++n;
|
|
|
- }
|
|
|
-
|
|
|
- /* Store the number of descriptors skipped and return the
|
|
|
- * number of bytes skipped */
|
|
|
- if (num_skipped)
|
|
|
- *num_skipped = n;
|
|
|
- return buffer - buffer0;
|
|
|
-}
|
|
|
-
|
|
|
static int find_next_descriptor(unsigned char *buffer, int size,
|
|
|
int dt1, int dt2, int *num_skipped)
|
|
|
{
|
|
@@ -71,47 +45,41 @@ static int find_next_descriptor(unsigned char *buffer, int size,
|
|
|
return buffer - buffer0;
|
|
|
}
|
|
|
|
|
|
-static int 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 num_ep, unsigned char *buffer, int size)
|
|
|
+ unsigned char *buffer, int size)
|
|
|
{
|
|
|
- unsigned char *buffer_start = buffer;
|
|
|
- struct usb_ss_ep_comp_descriptor *desc;
|
|
|
- int retval;
|
|
|
- int num_skipped;
|
|
|
+ struct usb_ss_ep_comp_descriptor *desc;
|
|
|
int max_tx;
|
|
|
- int i;
|
|
|
|
|
|
+ /* The SuperSpeed endpoint companion descriptor is supposed to
|
|
|
+ * be the first thing immediately following the endpoint descriptor.
|
|
|
+ */
|
|
|
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
|
|
|
- if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
|
|
|
+ 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 "
|
|
|
" interface %d altsetting %d ep %d: "
|
|
|
"using minimum values\n",
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- /*
|
|
|
- * The next descriptor is for an Endpoint or Interface,
|
|
|
- * no extra descriptors to copy into the companion structure,
|
|
|
- * and we didn't eat up any of the buffer.
|
|
|
+
|
|
|
+ /* Fill in some default values.
|
|
|
+ * Leave bmAttributes as zero, which will mean no streams for
|
|
|
+ * bulk, and isoc won't support multiple bursts of packets.
|
|
|
+ * With bursts of only one packet, and a Mult of 1, the max
|
|
|
+ * amount of data moved per endpoint service interval is one
|
|
|
+ * packet.
|
|
|
*/
|
|
|
- return 0;
|
|
|
+ ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE;
|
|
|
+ ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
|
|
+ if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
|
|
+ usb_endpoint_xfer_int(&ep->desc))
|
|
|
+ ep->ss_ep_comp.wBytesPerInterval =
|
|
|
+ ep->desc.wMaxPacketSize;
|
|
|
+ return;
|
|
|
}
|
|
|
- memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
|
|
|
- desc = &ep->ss_ep_comp->desc;
|
|
|
- buffer += desc->bLength;
|
|
|
- size -= desc->bLength;
|
|
|
|
|
|
- /* Eat up the other descriptors we don't care about */
|
|
|
- ep->ss_ep_comp->extra = buffer;
|
|
|
- i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
|
|
- USB_DT_INTERFACE, &num_skipped);
|
|
|
- ep->ss_ep_comp->extralen = i;
|
|
|
- buffer += i;
|
|
|
- size -= i;
|
|
|
- retval = buffer - buffer_start;
|
|
|
- if (num_skipped > 0)
|
|
|
- dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
|
|
- num_skipped, plural(num_skipped),
|
|
|
- "SuperSpeed endpoint companion");
|
|
|
+ memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
|
|
|
|
|
|
/* Check the various values */
|
|
|
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
|
|
@@ -119,47 +87,48 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
|
"setting to zero\n", desc->bMaxBurst,
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- desc->bMaxBurst = 0;
|
|
|
- }
|
|
|
- if (desc->bMaxBurst > 15) {
|
|
|
+ ep->ss_ep_comp.bMaxBurst = 0;
|
|
|
+ } else if (desc->bMaxBurst > 15) {
|
|
|
dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
|
"setting to 15\n", desc->bMaxBurst,
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- desc->bMaxBurst = 15;
|
|
|
+ ep->ss_ep_comp.bMaxBurst = 15;
|
|
|
}
|
|
|
- if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
|
|
|
- && desc->bmAttributes != 0) {
|
|
|
+
|
|
|
+ if ((usb_endpoint_xfer_control(&ep->desc) ||
|
|
|
+ usb_endpoint_xfer_int(&ep->desc)) &&
|
|
|
+ desc->bmAttributes != 0) {
|
|
|
dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
|
"setting to zero\n",
|
|
|
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
|
|
|
desc->bmAttributes,
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- desc->bmAttributes = 0;
|
|
|
- }
|
|
|
- if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
|
|
|
+ ep->ss_ep_comp.bmAttributes = 0;
|
|
|
+ } else if (usb_endpoint_xfer_bulk(&ep->desc) &&
|
|
|
+ desc->bmAttributes > 16) {
|
|
|
dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
|
"setting to max\n",
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- desc->bmAttributes = 16;
|
|
|
- }
|
|
|
- if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
|
|
|
+ ep->ss_ep_comp.bmAttributes = 16;
|
|
|
+ } else if (usb_endpoint_xfer_isoc(&ep->desc) &&
|
|
|
+ desc->bmAttributes > 2) {
|
|
|
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
|
"setting to 3\n", desc->bmAttributes + 1,
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
|
|
- desc->bmAttributes = 2;
|
|
|
+ ep->ss_ep_comp.bmAttributes = 2;
|
|
|
}
|
|
|
- if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
|
|
+
|
|
|
+ if (usb_endpoint_xfer_isoc(&ep->desc))
|
|
|
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
|
|
|
(desc->bmAttributes + 1);
|
|
|
- } else if (usb_endpoint_xfer_int(&ep->desc)) {
|
|
|
+ else if (usb_endpoint_xfer_int(&ep->desc))
|
|
|
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
|
|
|
- } else {
|
|
|
- goto valid;
|
|
|
- }
|
|
|
+ else
|
|
|
+ max_tx = 999999;
|
|
|
if (desc->wBytesPerInterval > max_tx) {
|
|
|
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
|
|
|
"config %d interface %d altsetting %d ep %d: "
|
|
@@ -168,10 +137,8 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|
|
desc->wBytesPerInterval,
|
|
|
cfgno, inum, asnum, ep->desc.bEndpointAddress,
|
|
|
max_tx);
|
|
|
- desc->wBytesPerInterval = max_tx;
|
|
|
+ ep->ss_ep_comp.wBytesPerInterval = max_tx;
|
|
|
}
|
|
|
-valid:
|
|
|
- return retval;
|
|
|
}
|
|
|
|
|
|
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
|
@@ -293,61 +260,19 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
|
|
cfgno, inum, asnum, d->bEndpointAddress,
|
|
|
maxp);
|
|
|
}
|
|
|
- /* Allocate room for and parse any SS endpoint companion descriptors */
|
|
|
- if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
|
|
|
- endpoint->extra = buffer;
|
|
|
- i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
|
|
|
- USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
|
|
|
- endpoint->extralen = i;
|
|
|
- buffer += i;
|
|
|
- size -= i;
|
|
|
-
|
|
|
- /* Allocate space for the SS endpoint companion descriptor */
|
|
|
- endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!endpoint->ss_ep_comp)
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
- /* Fill in some default values (may be overwritten later) */
|
|
|
- endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
|
|
|
- endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
|
|
- endpoint->ss_ep_comp->desc.bMaxBurst = 0;
|
|
|
- /*
|
|
|
- * Leave bmAttributes as zero, which will mean no streams for
|
|
|
- * bulk, and isoc won't support multiple bursts of packets.
|
|
|
- * With bursts of only one packet, and a Mult of 1, the max
|
|
|
- * amount of data moved per endpoint service interval is one
|
|
|
- * packet.
|
|
|
- */
|
|
|
- if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
|
|
|
- usb_endpoint_xfer_int(&endpoint->desc))
|
|
|
- endpoint->ss_ep_comp->desc.wBytesPerInterval =
|
|
|
- endpoint->desc.wMaxPacketSize;
|
|
|
-
|
|
|
- if (size > 0) {
|
|
|
- retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
|
|
|
- inum, asnum, endpoint, num_ep, buffer,
|
|
|
- size);
|
|
|
- if (retval >= 0) {
|
|
|
- buffer += retval;
|
|
|
- retval = buffer - buffer0;
|
|
|
- }
|
|
|
- } else {
|
|
|
- dev_warn(ddev, "config %d interface %d altsetting %d "
|
|
|
- "endpoint 0x%X has no "
|
|
|
- "SuperSpeed companion descriptor\n",
|
|
|
- cfgno, inum, asnum, d->bEndpointAddress);
|
|
|
- retval = buffer - buffer0;
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* Skip over any Class Specific or Vendor Specific descriptors;
|
|
|
- * find the next endpoint or interface descriptor */
|
|
|
- endpoint->extra = buffer;
|
|
|
- i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
|
|
- USB_DT_INTERFACE, &n);
|
|
|
- endpoint->extralen = i;
|
|
|
- retval = buffer - buffer0 + i;
|
|
|
- }
|
|
|
+ /* Parse a possible SuperSpeed endpoint companion descriptor */
|
|
|
+ if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
|
|
|
+ usb_parse_ss_endpoint_companion(ddev, cfgno,
|
|
|
+ inum, asnum, endpoint, buffer, size);
|
|
|
+
|
|
|
+ /* Skip over any Class Specific or Vendor Specific descriptors;
|
|
|
+ * find the next endpoint or interface descriptor */
|
|
|
+ endpoint->extra = buffer;
|
|
|
+ i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
|
|
+ USB_DT_INTERFACE, &n);
|
|
|
+ endpoint->extralen = i;
|
|
|
+ retval = buffer - buffer0 + i;
|
|
|
if (n > 0)
|
|
|
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
|
|
n, plural(n), "endpoint");
|