drivers/usb/core/urb.c

Source file repositories/reference/linux-study-clean/drivers/usb/core/urb.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/core/urb.c
Extension
.c
Size
34130 bytes
Lines
1022
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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);
	kmsan_handle_urb(urb, is_out);

	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
			dev->state < USB_STATE_CONFIGURED)
		return -ENODEV;

	max = usb_endpoint_maxp(&ep->desc);
	is_eusb2_isoch_double = usb_endpoint_is_hs_isoc_double(dev, ep);
	if (!max && !is_eusb2_isoch_double) {
		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 speed, 1-3 packets/uframe, max 6 for eUSB2 double bw */
		if (dev->speed == USB_SPEED_HIGH) {
			if (is_eusb2_isoch_double)
				max = le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval);
			else
				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) {
		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.

Annotation

Implementation Notes