Re: [PATCH 1/5] USB: Add parsing of SuperSpeed endpoint companion descriptor.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 7 Apr 2010, Sarah Sharp wrote:

> > > I really struggled with the descriptor parsing code to get it right, so
> > > I really don't ever want to touch that code again.  Maybe someone else
> > > wants to take a shot at it?
> > 
> > I can change it to do this.  Parts of xhci-hcd would have to be changed 
> > too.
> 
> Ok, sure, just CC me on the patches and I'll see if I need to rebase the
> streams patches.

Does this look okay to you?  I don't have any way to test it.

Alan Stern



Index: usb-2.6/include/linux/usb.h
===================================================================
--- usb-2.6.orig/include/linux/usb.h
+++ usb-2.6/include/linux/usb.h
@@ -45,19 +45,6 @@ struct wusb_dev;
 
 struct ep_device;
 
-/* For SS devices */
-/**
- * struct usb_host_ss_ep_comp - Valid for SuperSpeed devices only
- * @desc: endpoint companion descriptor, wMaxPacketSize in native byteorder
- * @extra: descriptors following this endpoint companion descriptor
- * @extralen: how many bytes of "extra" are valid
- */
-struct usb_host_ss_ep_comp {
-	struct usb_ss_ep_comp_descriptor	desc;
-	unsigned char				*extra;   /* Extra descriptors */
-	int					extralen;
-};
-
 /**
  * struct usb_host_endpoint - host-side endpoint descriptor and queue
  * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
@@ -65,7 +52,7 @@ struct usb_host_ss_ep_comp {
  * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
  *	with one or more transfer descriptors (TDs) per urb
  * @ep_dev: ep_device for sysfs info
- * @ss_ep_comp: companion descriptor information for this endpoint
+ * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint
  * @extra: descriptors following this endpoint in the configuration
  * @extralen: how many bytes of "extra" are valid
  * @enabled: URBs may be submitted to this endpoint
@@ -78,7 +65,7 @@ struct usb_host_endpoint {
 	struct list_head		urb_list;
 	void				*hcpriv;
 	struct ep_device 		*ep_dev;	/* For sysfs info */
-	struct usb_host_ss_ep_comp	*ss_ep_comp;	/* For SS devices */
+	struct usb_ss_ep_comp_descriptor	ss_ep_comp;
 
 	unsigned char *extra;   /* Extra descriptors */
 	int extralen;
Index: usb-2.6/drivers/usb/host/xhci-mem.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/xhci-mem.c
+++ usb-2.6/drivers/usb/host/xhci-mem.c
@@ -657,12 +657,9 @@ int xhci_endpoint_init(struct xhci_hcd *
 		max_packet = ep->desc.wMaxPacketSize;
 		ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
 		/* dig out max burst from ep companion desc */
-		if (!ep->ss_ep_comp) {
-			xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n");
-			max_packet = 0;
-		} else {
-			max_packet = ep->ss_ep_comp->desc.bMaxBurst;
-		}
+		max_packet = ep->ss_ep_comp.bMaxBurst;
+		if (!max_packet)
+			xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
 		ep_ctx->ep_info2 |= MAX_BURST(max_packet);
 		break;
 	case USB_SPEED_HIGH:
Index: usb-2.6/drivers/usb/core/config.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/config.c
+++ usb-2.6/drivers/usb/core/config.c
@@ -19,32 +19,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)
 {
@@ -69,47 +43,41 @@ static int find_next_descriptor(unsigned
 	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) {
@@ -117,15 +85,16 @@ static int usb_parse_ss_endpoint_compani
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to zero\n", desc->bMaxBurst,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bMaxBurst = 0;
+		ep->ss_ep_comp.bMaxBurst = 0;
 	}
-	if (desc->bMaxBurst > 15) {
+	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) {
 		dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
@@ -134,30 +103,30 @@ static int usb_parse_ss_endpoint_compani
 				usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
 				desc->bmAttributes,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bmAttributes = 0;
+		ep->ss_ep_comp.bmAttributes = 0;
 	}
-	if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
+	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;
+		ep->ss_ep_comp.bmAttributes = 16;
 	}
-	if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
+	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: "
@@ -166,10 +135,8 @@ static int usb_parse_ss_endpoint_compani
 				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,
@@ -291,61 +258,19 @@ static int usb_parse_endpoint(struct dev
 				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");

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux