diff options
Diffstat (limited to 'drivers/usb/core/config.c')
-rw-r--r-- | drivers/usb/core/config.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 31ccdccd7a04..051163189810 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c | |||
@@ -171,6 +171,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, | |||
171 | ep, buffer, size); | 171 | ep, buffer, size); |
172 | } | 172 | } |
173 | 173 | ||
174 | static const unsigned short low_speed_maxpacket_maxes[4] = { | ||
175 | [USB_ENDPOINT_XFER_CONTROL] = 8, | ||
176 | [USB_ENDPOINT_XFER_ISOC] = 0, | ||
177 | [USB_ENDPOINT_XFER_BULK] = 0, | ||
178 | [USB_ENDPOINT_XFER_INT] = 8, | ||
179 | }; | ||
180 | static const unsigned short full_speed_maxpacket_maxes[4] = { | ||
181 | [USB_ENDPOINT_XFER_CONTROL] = 64, | ||
182 | [USB_ENDPOINT_XFER_ISOC] = 1023, | ||
183 | [USB_ENDPOINT_XFER_BULK] = 64, | ||
184 | [USB_ENDPOINT_XFER_INT] = 64, | ||
185 | }; | ||
186 | static const unsigned short high_speed_maxpacket_maxes[4] = { | ||
187 | [USB_ENDPOINT_XFER_CONTROL] = 64, | ||
188 | [USB_ENDPOINT_XFER_ISOC] = 1024, | ||
189 | [USB_ENDPOINT_XFER_BULK] = 512, | ||
190 | [USB_ENDPOINT_XFER_INT] = 1023, | ||
191 | }; | ||
192 | static const unsigned short super_speed_maxpacket_maxes[4] = { | ||
193 | [USB_ENDPOINT_XFER_CONTROL] = 512, | ||
194 | [USB_ENDPOINT_XFER_ISOC] = 1024, | ||
195 | [USB_ENDPOINT_XFER_BULK] = 1024, | ||
196 | [USB_ENDPOINT_XFER_INT] = 1024, | ||
197 | }; | ||
198 | |||
174 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | 199 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, |
175 | int asnum, struct usb_host_interface *ifp, int num_ep, | 200 | int asnum, struct usb_host_interface *ifp, int num_ep, |
176 | unsigned char *buffer, int size) | 201 | unsigned char *buffer, int size) |
@@ -179,6 +204,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
179 | struct usb_endpoint_descriptor *d; | 204 | struct usb_endpoint_descriptor *d; |
180 | struct usb_host_endpoint *endpoint; | 205 | struct usb_host_endpoint *endpoint; |
181 | int n, i, j, retval; | 206 | int n, i, j, retval; |
207 | unsigned int maxp; | ||
208 | const unsigned short *maxpacket_maxes; | ||
182 | 209 | ||
183 | d = (struct usb_endpoint_descriptor *) buffer; | 210 | d = (struct usb_endpoint_descriptor *) buffer; |
184 | buffer += d->bLength; | 211 | buffer += d->bLength; |
@@ -286,6 +313,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
286 | endpoint->desc.wMaxPacketSize = cpu_to_le16(8); | 313 | endpoint->desc.wMaxPacketSize = cpu_to_le16(8); |
287 | } | 314 | } |
288 | 315 | ||
316 | /* Validate the wMaxPacketSize field */ | ||
317 | maxp = usb_endpoint_maxp(&endpoint->desc); | ||
318 | |||
319 | /* Find the highest legal maxpacket size for this endpoint */ | ||
320 | i = 0; /* additional transactions per microframe */ | ||
321 | switch (to_usb_device(ddev)->speed) { | ||
322 | case USB_SPEED_LOW: | ||
323 | maxpacket_maxes = low_speed_maxpacket_maxes; | ||
324 | break; | ||
325 | case USB_SPEED_FULL: | ||
326 | maxpacket_maxes = full_speed_maxpacket_maxes; | ||
327 | break; | ||
328 | case USB_SPEED_HIGH: | ||
329 | /* Bits 12..11 are allowed only for HS periodic endpoints */ | ||
330 | if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) { | ||
331 | i = maxp & (BIT(12) | BIT(11)); | ||
332 | maxp &= ~i; | ||
333 | } | ||
334 | /* fallthrough */ | ||
335 | default: | ||
336 | maxpacket_maxes = high_speed_maxpacket_maxes; | ||
337 | break; | ||
338 | case USB_SPEED_SUPER: | ||
339 | case USB_SPEED_SUPER_PLUS: | ||
340 | maxpacket_maxes = super_speed_maxpacket_maxes; | ||
341 | break; | ||
342 | } | ||
343 | j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)]; | ||
344 | |||
345 | if (maxp > j) { | ||
346 | dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n", | ||
347 | cfgno, inum, asnum, d->bEndpointAddress, maxp, j); | ||
348 | maxp = j; | ||
349 | endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp); | ||
350 | } | ||
351 | |||
289 | /* | 352 | /* |
290 | * Some buggy high speed devices have bulk endpoints using | 353 | * Some buggy high speed devices have bulk endpoints using |
291 | * maxpacket sizes other than 512. High speed HCDs may not | 354 | * maxpacket sizes other than 512. High speed HCDs may not |
@@ -293,9 +356,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
293 | */ | 356 | */ |
294 | if (to_usb_device(ddev)->speed == USB_SPEED_HIGH | 357 | if (to_usb_device(ddev)->speed == USB_SPEED_HIGH |
295 | && usb_endpoint_xfer_bulk(d)) { | 358 | && usb_endpoint_xfer_bulk(d)) { |
296 | unsigned maxp; | ||
297 | |||
298 | maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff; | ||
299 | if (maxp != 512) | 359 | if (maxp != 512) |
300 | dev_warn(ddev, "config %d interface %d altsetting %d " | 360 | dev_warn(ddev, "config %d interface %d altsetting %d " |
301 | "bulk endpoint 0x%X has invalid maxpacket %d\n", | 361 | "bulk endpoint 0x%X has invalid maxpacket %d\n", |