drivers/usb/usbip/stub_tx.c

Source file repositories/reference/linux-study-clean/drivers/usb/usbip/stub_tx.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/usbip/stub_tx.c
Extension
.c
Size
11634 bytes
Lines
451
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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 (!iov) {
			usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
			return -1;
		}

		iovnum = 0;

		/* 1. setup usbip_header */
		setup_ret_submit_pdu(&pdu_header, urb);
		usbip_dbg_stub_tx("setup txdata seqnum: %u\n",
				  pdu_header.base.seqnum);

		if (priv->sgl) {
			for (i = 0; i < priv->num_urbs; i++)
				actual_length += priv->urbs[i]->actual_length;

			pdu_header.u.ret_submit.status = priv->urb_status;
			pdu_header.u.ret_submit.actual_length = actual_length;
		}

		usbip_header_correct_endian(&pdu_header, 1);

		iov[iovnum].iov_base = &pdu_header;
		iov[iovnum].iov_len  = sizeof(pdu_header);
		iovnum++;
		txsize += sizeof(pdu_header);

		/* 2. setup transfer buffer */
		if (usb_pipein(urb->pipe) && priv->sgl) {
			/* If the server split a single SG request into several
			 * URBs because the server's HCD doesn't support SG,
			 * reassemble the split URB buffers into a single
			 * return command.
			 */
			for (i = 0; i < priv->num_urbs; i++) {
				iov[iovnum].iov_base =
					priv->urbs[i]->transfer_buffer;
				iov[iovnum].iov_len =
					priv->urbs[i]->actual_length;
				iovnum++;
			}
			txsize += actual_length;
		} else if (usb_pipein(urb->pipe) &&
		    usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
		    urb->actual_length > 0) {
			if (urb->num_sgs) {
				unsigned int copy = urb->actual_length;
				unsigned int size;

				for_each_sg(urb->sg, sg, urb->num_sgs, i) {
					if (copy == 0)
						break;

					size = min(copy, sg->length);
					iov[iovnum].iov_base = sg_virt(sg);
					iov[iovnum].iov_len = size;

					iovnum++;
					copy -= size;
				}
			} else {
				iov[iovnum].iov_base = urb->transfer_buffer;
				iov[iovnum].iov_len  = urb->actual_length;
				iovnum++;
			}
			txsize += urb->actual_length;
		} else if (usb_pipein(urb->pipe) &&
			   usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
			/*
			 * For isochronous packets: actual length is the sum of
			 * the actual length of the individual, packets, but as
			 * the packet offsets are not changed there will be
			 * padding between the packets. To optimally use the
			 * bandwidth the padding is not transmitted.
			 */

			int i;

			for (i = 0; i < urb->number_of_packets; i++) {
				iov[iovnum].iov_base = urb->transfer_buffer +
					urb->iso_frame_desc[i].offset;
				iov[iovnum].iov_len =
					urb->iso_frame_desc[i].actual_length;
				iovnum++;
				txsize += urb->iso_frame_desc[i].actual_length;
			}

			if (txsize != sizeof(pdu_header) + urb->actual_length) {
				dev_err(&sdev->udev->dev,
					"actual length of urb %d does not match iso packet sizes %zu\n",

Annotation

Implementation Notes