diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 2d4fd530e5e4..dd3482328ad2 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -49,7 +50,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; struct usb_host_endpoint *endpoint; - int n, i; + int n, i, j; d = (struct usb_endpoint_descriptor *) buffer; buffer += d->bLength; @@ -84,6 +85,45 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, memcpy(&endpoint->desc, d, n); INIT_LIST_HEAD(&endpoint->urb_list); + /* If the bInterval value is outside the legal range, + * set it to a default value: 32 ms */ + i = 0; /* i = min, j = max, n = default */ + j = 255; + if (usb_endpoint_xfer_int(d)) { + i = 1; + switch (to_usb_device(ddev)->speed) { + case USB_SPEED_HIGH: + n = 9; /* 32 ms = 2^(9-1) uframes */ + j = 16; + break; + default: /* USB_SPEED_FULL or _LOW */ + /* For low-speed, 10 ms is the official minimum. + * But some "overclocked" devices might want faster + * polling so we'll allow it. */ + n = 32; + break; + } + } else if (usb_endpoint_xfer_isoc(d)) { + i = 1; + j = 16; + switch (to_usb_device(ddev)->speed) { + case USB_SPEED_HIGH: + n = 9; /* 32 ms = 2^(9-1) uframes */ + break; + default: /* USB_SPEED_FULL */ + n = 6; /* 32 ms = 2^(6-1) frames */ + break; + } + } + if (d->bInterval < i || d->bInterval > j) { + dev_warn(ddev, "config %d interface %d altsetting %d " + "endpoint 0x%X has an invalid bInterval %d, " + "changing to %d\n", + cfgno, inum, asnum, + d->bEndpointAddress, d->bInterval, n); + endpoint->desc.bInterval = n; + } + /* Skip over any Class Specific or Vendor Specific descriptors; * find the next endpoint or interface descriptor */ endpoint->extra = buffer;