in core/urb.c [367:595]
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
unsigned int allowed;
if (!urb || !urb->complete)
return -EINVAL;
if (urb->hcpriv) {
WARN_ONCE(1, "URB %pK submitted while active\n", urb);
return -EBUSY;
}
dev = urb->dev;
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
return -ENODEV;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
ep = usb_pipe_endpoint(dev, urb->pipe);
if (!ep)
return -ENOENT;
urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
xfertype = usb_endpoint_type(&ep->desc);
if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
struct usb_ctrlrequest *setup =
(struct usb_ctrlrequest *) urb->setup_packet;
if (!setup)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out),
"BOGUS control dir, pipe %x doesn't match bRequestType %x\n",
urb->pipe, setup->bRequestType);
if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) {
dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n",
le16_to_cpu(setup->wLength),
urb->transfer_buffer_length);
return -EBADR;
}
} else {
is_out = usb_endpoint_dir_out(&ep->desc);
}
/* Clear the internal flags and cache the direction for later use */
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
max = usb_endpoint_maxp(&ep->desc);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__func__, max);
return -EMSGSIZE;
}
/* periodic transfers limit size per frame/uframe,
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
if (dev->speed >= USB_SPEED_SUPER) {
int burst = 1 + ep->ss_ep_comp.bMaxBurst;
int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
max *= burst;
max *= mult;
}
if (dev->speed == USB_SPEED_SUPER_PLUS &&
USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) {
struct usb_ssp_isoc_ep_comp_descriptor *isoc_ep_comp;
isoc_ep_comp = &ep->ssp_isoc_ep_comp;
max = le32_to_cpu(isoc_ep_comp->dwBytesPerInterval);
}
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH)
max *= usb_endpoint_maxp_mult(&ep->desc);
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
} else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
dev->speed != USB_SPEED_WIRELESS) {
struct scatterlist *sg;
int i;
for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
if (sg->length % max)
return -EINVAL;
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
if (urb->transfer_buffer_length > INT_MAX)
return -EMSGSIZE;
/*
* stuff that drivers shouldn't do, but which shouldn't
* cause problems in HCDs if they get it wrong.
*/
/* Check that the pipe's type matches the endpoint's type */
if (usb_pipe_type_check(urb->dev, urb->pipe))
dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]);
/* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER);
switch (xfertype) {
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
if (is_out)
allowed |= URB_ZERO_PACKET;
fallthrough;
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
allowed &= urb->transfer_flags;
/* warn if submitter gave bogus flags */
if (allowed != urb->transfer_flags)
dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
urb->transfer_flags, allowed);
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (xfertype) {
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
/* too small? */
switch (dev->speed) {
case USB_SPEED_WIRELESS:
if ((urb->interval < 6)
&& (xfertype == USB_ENDPOINT_XFER_INT))
return -EINVAL;
fallthrough;
default:
if (urb->interval <= 0)
return -EINVAL;
break;
}
/* too big? */
switch (dev->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
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))
urb->interval = 1024 * 8;
max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
/* NOTE ohci only handles up to 32 */
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
/* NOTE usb and ohci handle up to 2^15 */
max = 1024;
}
break;
default:
return -EINVAL;
}
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);
}