aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-04-27 22:58:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:49 -0400
commit663c30d0829d556efabd5fbd98fb8473da7fe694 (patch)
tree1d2566aff3b6af6e05cf3a7a0fc1c1fb17bfe5db
parentd0e96f5a71a032ced0c35f521c1cbd67e816922a (diff)
USB: Parse and store the SuperSpeed endpoint companion descriptors.
The USB 3.0 bus specification added an "Endpoint Companion" descriptor that is supposed to follow all SuperSpeed Endpoint descriptors. This descriptor is used to extend the bus protocol to allow more packets to be sent to an endpoint per "microframe". The word microframe was removed from the USB 3.0 specification because the host controller does not send Start Of Frame (SOF) symbols down the USB 3.0 wires. The descriptor defines a bMaxBurst field, which indicates the number of packets of wMaxPacketSize that a SuperSpeed device can send or recieve in a service interval. All non-control endpoints may set this value as high as 16 packets (bMaxBurst = 15). The descriptor also allows isochronous endpoints to further specify that they can send and receive multiple bursts per service interval. The bmAttributes allows them to specify a "Mult" of up to 3 (bmAttributes = 2). Bulk endpoints use bmAttributes to report the number of "Streams" they support. This was an extension of the endpoint pipe concept to allow multiple mass storage device commands to be outstanding for one bulk endpoint at a time. This should allow USB 3.0 mass storage devices to support SCSI command queueing. Bulk endpoints can say they support up to 2^16 (65,536) streams. The information in the endpoint companion descriptor must be stored with the other device, config, interface, and endpoint descriptors because the host controller needs to access them quickly, and we need to install some default values if a SuperSpeed device doesn't provide an endpoint companion descriptor. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/config.c189
-rw-r--r--include/linux/usb.h16
-rw-r--r--include/linux/usb/ch9.h16
3 files changed, 212 insertions, 9 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index e9426acf5682..7103758bb486 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -19,6 +19,32 @@ static inline const char *plural(int n)
19 return (n == 1 ? "" : "s"); 19 return (n == 1 ? "" : "s");
20} 20}
21 21
22/* FIXME: this is a kludge */
23static int find_next_descriptor_more(unsigned char *buffer, int size,
24 int dt1, int dt2, int dt3, int *num_skipped)
25{
26 struct usb_descriptor_header *h;
27 int n = 0;
28 unsigned char *buffer0 = buffer;
29
30 /* Find the next descriptor of type dt1 or dt2 or dt3 */
31 while (size > 0) {
32 h = (struct usb_descriptor_header *) buffer;
33 if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
34 h->bDescriptorType == dt3)
35 break;
36 buffer += h->bLength;
37 size -= h->bLength;
38 ++n;
39 }
40
41 /* Store the number of descriptors skipped and return the
42 * number of bytes skipped */
43 if (num_skipped)
44 *num_skipped = n;
45 return buffer - buffer0;
46}
47
22static int find_next_descriptor(unsigned char *buffer, int size, 48static int find_next_descriptor(unsigned char *buffer, int size,
23 int dt1, int dt2, int *num_skipped) 49 int dt1, int dt2, int *num_skipped)
24{ 50{
@@ -43,6 +69,128 @@ static int find_next_descriptor(unsigned char *buffer, int size,
43 return buffer - buffer0; 69 return buffer - buffer0;
44} 70}
45 71
72static int usb_parse_endpoint_companion(struct device *ddev, int cfgno,
73 int inum, int asnum, struct usb_host_endpoint *ep,
74 int num_ep, unsigned char *buffer, int size)
75{
76 unsigned char *buffer_start = buffer;
77 struct usb_ep_comp_descriptor *desc;
78 int retval;
79 int num_skipped;
80 int max_tx;
81 int i;
82
83 /* Allocate space for the companion descriptor */
84 ep->ep_comp = kzalloc(sizeof(struct usb_host_ep_comp), GFP_KERNEL);
85 if (!ep->ep_comp)
86 return -ENOMEM;
87 desc = (struct usb_ep_comp_descriptor *) buffer;
88 if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
89 dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
90 " interface %d altsetting %d ep %d: "
91 "using minimum values\n",
92 cfgno, inum, asnum, ep->desc.bEndpointAddress);
93 ep->ep_comp->desc.bLength = USB_DT_EP_COMP_SIZE;
94 ep->ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
95 ep->ep_comp->desc.bMaxBurst = 0;
96 /*
97 * Leave bmAttributes as zero, which will mean no streams for
98 * bulk, and isoc won't support multiple bursts of packets.
99 * With bursts of only one packet, and a Mult of 1, the max
100 * amount of data moved per endpoint service interval is one
101 * packet.
102 */
103 if (usb_endpoint_xfer_isoc(&ep->desc) ||
104 usb_endpoint_xfer_int(&ep->desc))
105 ep->ep_comp->desc.wBytesPerInterval =
106 ep->desc.wMaxPacketSize;
107 /*
108 * The next descriptor is for an Endpoint or Interface,
109 * no extra descriptors to copy into the companion structure,
110 * and we didn't eat up any of the buffer.
111 */
112 retval = 0;
113 goto valid;
114 }
115 memcpy(&ep->ep_comp->desc, desc, USB_DT_EP_COMP_SIZE);
116 desc = &ep->ep_comp->desc;
117 buffer += desc->bLength;
118 size -= desc->bLength;
119
120 /* Eat up the other descriptors we don't care about */
121 ep->ep_comp->extra = buffer;
122 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
123 USB_DT_INTERFACE, &num_skipped);
124 ep->ep_comp->extralen = i;
125 buffer += i;
126 size -= i;
127 retval = buffer - buffer_start + i;
128 if (num_skipped > 0)
129 dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
130 num_skipped, plural(num_skipped),
131 "SuperSpeed endpoint companion");
132
133 /* Check the various values */
134 if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
135 dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
136 "config %d interface %d altsetting %d ep %d: "
137 "setting to zero\n", desc->bMaxBurst,
138 cfgno, inum, asnum, ep->desc.bEndpointAddress);
139 desc->bMaxBurst = 0;
140 }
141 if (desc->bMaxBurst > 15) {
142 dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
143 "config %d interface %d altsetting %d ep %d: "
144 "setting to 15\n", desc->bMaxBurst,
145 cfgno, inum, asnum, ep->desc.bEndpointAddress);
146 desc->bMaxBurst = 15;
147 }
148 if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
149 && desc->bmAttributes != 0) {
150 dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
151 "config %d interface %d altsetting %d ep %d: "
152 "setting to zero\n",
153 usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
154 desc->bmAttributes,
155 cfgno, inum, asnum, ep->desc.bEndpointAddress);
156 desc->bmAttributes = 0;
157 }
158 if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
159 dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
160 "config %d interface %d altsetting %d ep %d: "
161 "setting to max\n",
162 cfgno, inum, asnum, ep->desc.bEndpointAddress);
163 desc->bmAttributes = 16;
164 }
165 if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
166 dev_warn(ddev, "Isoc endpoint has Mult of %d in "
167 "config %d interface %d altsetting %d ep %d: "
168 "setting to 3\n", desc->bmAttributes + 1,
169 cfgno, inum, asnum, ep->desc.bEndpointAddress);
170 desc->bmAttributes = 2;
171 }
172 if (usb_endpoint_xfer_isoc(&ep->desc)) {
173 max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
174 (desc->bmAttributes + 1);
175 } else if (usb_endpoint_xfer_int(&ep->desc)) {
176 max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
177 } else {
178 goto valid;
179 }
180 if (desc->wBytesPerInterval > max_tx) {
181 dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
182 "config %d interface %d altsetting %d ep %d: "
183 "setting to %d\n",
184 usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
185 desc->wBytesPerInterval,
186 cfgno, inum, asnum, ep->desc.bEndpointAddress,
187 max_tx);
188 desc->wBytesPerInterval = max_tx;
189 }
190valid:
191 return retval;
192}
193
46static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, 194static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
47 int asnum, struct usb_host_interface *ifp, int num_ep, 195 int asnum, struct usb_host_interface *ifp, int num_ep,
48 unsigned char *buffer, int size) 196 unsigned char *buffer, int size)
@@ -50,7 +198,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
50 unsigned char *buffer0 = buffer; 198 unsigned char *buffer0 = buffer;
51 struct usb_endpoint_descriptor *d; 199 struct usb_endpoint_descriptor *d;
52 struct usb_host_endpoint *endpoint; 200 struct usb_host_endpoint *endpoint;
53 int n, i, j; 201 int n, i, j, retval;
54 202
55 d = (struct usb_endpoint_descriptor *) buffer; 203 d = (struct usb_endpoint_descriptor *) buffer;
56 buffer += d->bLength; 204 buffer += d->bLength;
@@ -162,17 +310,38 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
162 cfgno, inum, asnum, d->bEndpointAddress, 310 cfgno, inum, asnum, d->bEndpointAddress,
163 maxp); 311 maxp);
164 } 312 }
165 313 /* Allocate room for and parse any endpoint companion descriptors */
166 /* Skip over any Class Specific or Vendor Specific descriptors; 314 if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
167 * find the next endpoint or interface descriptor */ 315 endpoint->extra = buffer;
168 endpoint->extra = buffer; 316 i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
169 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 317 USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
170 USB_DT_INTERFACE, &n); 318 endpoint->extralen = i;
171 endpoint->extralen = i; 319 buffer += i;
320 size -= i;
321
322 if (size > 0) {
323 retval = usb_parse_endpoint_companion(ddev, cfgno, inum, asnum,
324 endpoint, num_ep, buffer, size);
325 if (retval >= 0) {
326 buffer += retval;
327 retval = buffer - buffer0;
328 }
329 } else {
330 retval = buffer - buffer0;
331 }
332 } else {
333 /* Skip over any Class Specific or Vendor Specific descriptors;
334 * find the next endpoint or interface descriptor */
335 endpoint->extra = buffer;
336 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
337 USB_DT_INTERFACE, &n);
338 endpoint->extralen = i;
339 retval = buffer - buffer0 + i;
340 }
172 if (n > 0) 341 if (n > 0)
173 dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 342 dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
174 n, plural(n), "endpoint"); 343 n, plural(n), "endpoint");
175 return buffer - buffer0 + i; 344 return retval;
176 345
177skip_to_next_endpoint_or_interface_descriptor: 346skip_to_next_endpoint_or_interface_descriptor:
178 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 347 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
@@ -453,6 +622,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
453 kref_init(&intfc->ref); 622 kref_init(&intfc->ref);
454 } 623 }
455 624
625 /* FIXME: parse the BOS descriptor */
626
456 /* Skip over any Class Specific or Vendor Specific descriptors; 627 /* Skip over any Class Specific or Vendor Specific descriptors;
457 * find the first interface descriptor */ 628 * find the first interface descriptor */
458 config->extra = buffer; 629 config->extra = buffer;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 112a2d6e922f..13bced521b83 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -36,6 +36,7 @@ struct wusb_dev;
36 * - configs have one (often) or more interfaces; 36 * - configs have one (often) or more interfaces;
37 * - interfaces have one (usually) or more settings; 37 * - interfaces have one (usually) or more settings;
38 * - each interface setting has zero or (usually) more endpoints. 38 * - each interface setting has zero or (usually) more endpoints.
39 * - a SuperSpeed endpoint has a companion descriptor
39 * 40 *
40 * And there might be other descriptors mixed in with those. 41 * And there might be other descriptors mixed in with those.
41 * 42 *
@@ -44,6 +45,19 @@ struct wusb_dev;
44 45
45struct ep_device; 46struct ep_device;
46 47
48/* For SS devices */
49/**
50 * struct usb_host_ep_comp - Valid for SuperSpeed devices only
51 * @desc: endpoint companion descriptor, wMaxPacketSize in native byteorder
52 * @extra: descriptors following this endpoint companion descriptor
53 * @extralen: how many bytes of "extra" are valid
54 */
55struct usb_host_ep_comp {
56 struct usb_ep_comp_descriptor desc;
57 unsigned char *extra; /* Extra descriptors */
58 int extralen;
59};
60
47/** 61/**
48 * struct usb_host_endpoint - host-side endpoint descriptor and queue 62 * struct usb_host_endpoint - host-side endpoint descriptor and queue
49 * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder 63 * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
@@ -51,6 +65,7 @@ struct ep_device;
51 * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) 65 * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
52 * with one or more transfer descriptors (TDs) per urb 66 * with one or more transfer descriptors (TDs) per urb
53 * @ep_dev: ep_device for sysfs info 67 * @ep_dev: ep_device for sysfs info
68 * @ep_comp: companion descriptor information for this endpoint
54 * @extra: descriptors following this endpoint in the configuration 69 * @extra: descriptors following this endpoint in the configuration
55 * @extralen: how many bytes of "extra" are valid 70 * @extralen: how many bytes of "extra" are valid
56 * @enabled: URBs may be submitted to this endpoint 71 * @enabled: URBs may be submitted to this endpoint
@@ -63,6 +78,7 @@ struct usb_host_endpoint {
63 struct list_head urb_list; 78 struct list_head urb_list;
64 void *hcpriv; 79 void *hcpriv;
65 struct ep_device *ep_dev; /* For sysfs info */ 80 struct ep_device *ep_dev; /* For sysfs info */
81 struct usb_host_ep_comp *ep_comp; /* For SS devices */
66 82
67 unsigned char *extra; /* Extra descriptors */ 83 unsigned char *extra; /* Extra descriptors */
68 int extralen; 84 int extralen;
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 93bfe6352342..9e9c5c0a3d72 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -191,6 +191,8 @@ struct usb_ctrlrequest {
191#define USB_DT_WIRE_ADAPTER 0x21 191#define USB_DT_WIRE_ADAPTER 0x21
192#define USB_DT_RPIPE 0x22 192#define USB_DT_RPIPE 0x22
193#define USB_DT_CS_RADIO_CONTROL 0x23 193#define USB_DT_CS_RADIO_CONTROL 0x23
194/* From the USB 3.0 spec */
195#define USB_DT_SS_ENDPOINT_COMP 0x30
194 196
195/* Conventional codes for class-specific descriptors. The convention is 197/* Conventional codes for class-specific descriptors. The convention is
196 * defined in the USB "Common Class" Spec (3.11). Individual class specs 198 * defined in the USB "Common Class" Spec (3.11). Individual class specs
@@ -535,6 +537,20 @@ static inline int usb_endpoint_is_isoc_out(
535 537
536/*-------------------------------------------------------------------------*/ 538/*-------------------------------------------------------------------------*/
537 539
540/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
541struct usb_ep_comp_descriptor {
542 __u8 bLength;
543 __u8 bDescriptorType;
544
545 __u8 bMaxBurst;
546 __u8 bmAttributes;
547 __u16 wBytesPerInterval;
548} __attribute__ ((packed));
549
550#define USB_DT_EP_COMP_SIZE 6
551
552/*-------------------------------------------------------------------------*/
553
538/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ 554/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
539struct usb_qualifier_descriptor { 555struct usb_qualifier_descriptor {
540 __u8 bLength; 556 __u8 bLength;