aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;