diff options
Diffstat (limited to 'drivers/usb/core/urb.c')
-rw-r--r-- | drivers/usb/core/urb.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 0885d4abdc62..45a32dadb406 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { unsigned int orig_flags = urb->transfer_flags; unsigned int allowed; + static int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT + }; + + /* Check that the pipe's type matches the endpoint's type */ + if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + return -EPIPE; /* The most suitable error code :-) */ /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | @@ -429,8 +436,16 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: /* too small? */ - if (urb->interval <= 0) - return -EINVAL; + switch (dev->speed) { + case USB_SPEED_WIRELESS: + if (urb->interval < 6) + return -EINVAL; + break; + default: + if (urb->interval <= 0) + return -EINVAL; + break; + } /* too big? */ switch (dev->speed) { case USB_SPEED_SUPER: /* units are 125us */ @@ -438,6 +453,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (urb->interval > (1 << 15)) return -EINVAL; max = 1 << 15; + break; + case USB_SPEED_WIRELESS: + if (urb->interval > 16) + return -EINVAL; + break; case USB_SPEED_HIGH: /* units are microframes */ /* NOTE usb handles 2^15 */ if (urb->interval > (1024 * 8)) @@ -461,8 +481,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) default: return -EINVAL; } - /* Round down to a power of 2, no more than max */ - urb->interval = min(max, 1 << ilog2(urb->interval)); + if (dev->speed != USB_SPEED_WIRELESS) { + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); + } } return usb_hcd_submit_urb(urb, mem_flags); |