aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/config.c')
-rw-r--r--drivers/usb/core/config.c192
1 files changed, 183 insertions, 9 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 568244c99bdc..24dfb33f90cb 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,129 @@ 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_ss_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_ss_ep_comp_descriptor *desc;
78 int retval;
79 int num_skipped;
80 int max_tx;
81 int i;
82
83 /* Allocate space for the SS endpoint companion descriptor */
84 ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
85 GFP_KERNEL);
86 if (!ep->ss_ep_comp)
87 return -ENOMEM;
88 desc = (struct usb_ss_ep_comp_descriptor *) buffer;
89 if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
90 dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
91 " interface %d altsetting %d ep %d: "
92 "using minimum values\n",
93 cfgno, inum, asnum, ep->desc.bEndpointAddress);
94 ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
95 ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
96 ep->ss_ep_comp->desc.bMaxBurst = 0;
97 /*
98 * Leave bmAttributes as zero, which will mean no streams for
99 * bulk, and isoc won't support multiple bursts of packets.
100 * With bursts of only one packet, and a Mult of 1, the max
101 * amount of data moved per endpoint service interval is one
102 * packet.
103 */
104 if (usb_endpoint_xfer_isoc(&ep->desc) ||
105 usb_endpoint_xfer_int(&ep->desc))
106 ep->ss_ep_comp->desc.wBytesPerInterval =
107 ep->desc.wMaxPacketSize;
108 /*
109 * The next descriptor is for an Endpoint or Interface,
110 * no extra descriptors to copy into the companion structure,
111 * and we didn't eat up any of the buffer.
112 */
113 retval = 0;
114 goto valid;
115 }
116 memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
117 desc = &ep->ss_ep_comp->desc;
118 buffer += desc->bLength;
119 size -= desc->bLength;
120
121 /* Eat up the other descriptors we don't care about */
122 ep->ss_ep_comp->extra = buffer;
123 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
124 USB_DT_INTERFACE, &num_skipped);
125 ep->ss_ep_comp->extralen = i;
126 buffer += i;
127 size -= i;
128 retval = buffer - buffer_start + i;
129 if (num_skipped > 0)
130 dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
131 num_skipped, plural(num_skipped),
132 "SuperSpeed endpoint companion");
133
134 /* Check the various values */
135 if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
136 dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
137 "config %d interface %d altsetting %d ep %d: "
138 "setting to zero\n", desc->bMaxBurst,
139 cfgno, inum, asnum, ep->desc.bEndpointAddress);
140 desc->bMaxBurst = 0;
141 }
142 if (desc->bMaxBurst > 15) {
143 dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
144 "config %d interface %d altsetting %d ep %d: "
145 "setting to 15\n", desc->bMaxBurst,
146 cfgno, inum, asnum, ep->desc.bEndpointAddress);
147 desc->bMaxBurst = 15;
148 }
149 if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
150 && desc->bmAttributes != 0) {
151 dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
152 "config %d interface %d altsetting %d ep %d: "
153 "setting to zero\n",
154 usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
155 desc->bmAttributes,
156 cfgno, inum, asnum, ep->desc.bEndpointAddress);
157 desc->bmAttributes = 0;
158 }
159 if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
160 dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
161 "config %d interface %d altsetting %d ep %d: "
162 "setting to max\n",
163 cfgno, inum, asnum, ep->desc.bEndpointAddress);
164 desc->bmAttributes = 16;
165 }
166 if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
167 dev_warn(ddev, "Isoc endpoint has Mult of %d in "
168 "config %d interface %d altsetting %d ep %d: "
169 "setting to 3\n", desc->bmAttributes + 1,
170 cfgno, inum, asnum, ep->desc.bEndpointAddress);
171 desc->bmAttributes = 2;
172 }
173 if (usb_endpoint_xfer_isoc(&ep->desc)) {
174 max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
175 (desc->bmAttributes + 1);
176 } else if (usb_endpoint_xfer_int(&ep->desc)) {
177 max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
178 } else {
179 goto valid;
180 }
181 if (desc->wBytesPerInterval > max_tx) {
182 dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
183 "config %d interface %d altsetting %d ep %d: "
184 "setting to %d\n",
185 usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
186 desc->wBytesPerInterval,
187 cfgno, inum, asnum, ep->desc.bEndpointAddress,
188 max_tx);
189 desc->wBytesPerInterval = max_tx;
190 }
191valid:
192 return retval;
193}
194
46static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, 195static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
47 int asnum, struct usb_host_interface *ifp, int num_ep, 196 int asnum, struct usb_host_interface *ifp, int num_ep,
48 unsigned char *buffer, int size) 197 unsigned char *buffer, int size)
@@ -50,7 +199,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
50 unsigned char *buffer0 = buffer; 199 unsigned char *buffer0 = buffer;
51 struct usb_endpoint_descriptor *d; 200 struct usb_endpoint_descriptor *d;
52 struct usb_host_endpoint *endpoint; 201 struct usb_host_endpoint *endpoint;
53 int n, i, j; 202 int n, i, j, retval;
54 203
55 d = (struct usb_endpoint_descriptor *) buffer; 204 d = (struct usb_endpoint_descriptor *) buffer;
56 buffer += d->bLength; 205 buffer += d->bLength;
@@ -92,6 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
92 if (usb_endpoint_xfer_int(d)) { 241 if (usb_endpoint_xfer_int(d)) {
93 i = 1; 242 i = 1;
94 switch (to_usb_device(ddev)->speed) { 243 switch (to_usb_device(ddev)->speed) {
244 case USB_SPEED_SUPER:
95 case USB_SPEED_HIGH: 245 case USB_SPEED_HIGH:
96 /* Many device manufacturers are using full-speed 246 /* Many device manufacturers are using full-speed
97 * bInterval values in high-speed interrupt endpoint 247 * bInterval values in high-speed interrupt endpoint
@@ -161,17 +311,39 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
161 cfgno, inum, asnum, d->bEndpointAddress, 311 cfgno, inum, asnum, d->bEndpointAddress,
162 maxp); 312 maxp);
163 } 313 }
164 314 /* Allocate room for and parse any SS endpoint companion descriptors */
165 /* Skip over any Class Specific or Vendor Specific descriptors; 315 if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
166 * find the next endpoint or interface descriptor */ 316 endpoint->extra = buffer;
167 endpoint->extra = buffer; 317 i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
168 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 318 USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
169 USB_DT_INTERFACE, &n); 319 endpoint->extralen = i;
170 endpoint->extralen = i; 320 buffer += i;
321 size -= i;
322
323 if (size > 0) {
324 retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
325 inum, asnum, endpoint, num_ep, buffer,
326 size);
327 if (retval >= 0) {
328 buffer += retval;
329 retval = buffer - buffer0;
330 }
331 } else {
332 retval = buffer - buffer0;
333 }
334 } else {
335 /* Skip over any Class Specific or Vendor Specific descriptors;
336 * find the next endpoint or interface descriptor */
337 endpoint->extra = buffer;
338 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
339 USB_DT_INTERFACE, &n);
340 endpoint->extralen = i;
341 retval = buffer - buffer0 + i;
342 }
171 if (n > 0) 343 if (n > 0)
172 dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 344 dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
173 n, plural(n), "endpoint"); 345 n, plural(n), "endpoint");
174 return buffer - buffer0 + i; 346 return retval;
175 347
176skip_to_next_endpoint_or_interface_descriptor: 348skip_to_next_endpoint_or_interface_descriptor:
177 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 349 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
@@ -452,6 +624,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
452 kref_init(&intfc->ref); 624 kref_init(&intfc->ref);
453 } 625 }
454 626
627 /* FIXME: parse the BOS descriptor */
628
455 /* Skip over any Class Specific or Vendor Specific descriptors; 629 /* Skip over any Class Specific or Vendor Specific descriptors;
456 * find the first interface descriptor */ 630 * find the first interface descriptor */
457 config->extra = buffer; 631 config->extra = buffer;