drivers/usb/gadget/function/uvc_queue.c

Source file repositories/reference/linux-study-clean/drivers/usb/gadget/function/uvc_queue.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/gadget/function/uvc_queue.c
Extension
.c
Size
10206 bytes
Lines
369
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

vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
		uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
		return -EINVAL;
	}

	if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
		return -ENODEV;

	buf->state = UVC_BUF_STATE_QUEUED;
	if (queue->use_sg) {
		buf->sgt = vb2_dma_sg_plane_desc(vb, 0);
		buf->sg = buf->sgt->sgl;
	} else {
		buf->mem = vb2_plane_vaddr(vb, 0);
	}
	buf->length = vb2_plane_size(vb, 0);
	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
		buf->bytesused = 0;
	} else {
		buf->bytesused = vb2_get_plane_payload(vb, 0);

		if (video->reqs_per_frame != 0)	{
			buf->req_payload_size =
				DIV_ROUND_UP(buf->bytesused +
					(video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
					video->reqs_per_frame);
			if (buf->req_payload_size > video->req_size)
				buf->req_payload_size = video->req_size;
		} else {
			buf->req_payload_size = video->max_req_size;
		}
	}

	return 0;
}

static void uvc_buffer_queue(struct vb2_buffer *vb)
{
	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf);
	unsigned long flags;

	spin_lock_irqsave(&queue->irqlock, flags);

	if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
		list_add_tail(&buf->queue, &queue->irqqueue);
	} else {
		/*
		 * If the device is disconnected return the buffer to userspace
		 * directly. The next QBUF call will fail with -ENODEV.
		 */
		buf->state = UVC_BUF_STATE_ERROR;
		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
	}

	spin_unlock_irqrestore(&queue->irqlock, flags);
}

static const struct vb2_ops uvc_queue_qops = {
	.queue_setup = uvc_queue_setup,
	.buf_prepare = uvc_buffer_prepare,
	.buf_queue = uvc_buffer_queue,
};

int uvcg_queue_init(struct uvc_video_queue *queue, struct device *dev, enum v4l2_buf_type type,
		    struct mutex *lock)
{
	struct uvc_video *video = container_of(queue, struct uvc_video, queue);
	struct usb_composite_dev *cdev = video->uvc->func.config->cdev;
	int ret;

	queue->queue.type = type;
	queue->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
	queue->queue.drv_priv = queue;
	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
	queue->queue.ops = &uvc_queue_qops;
	queue->queue.lock = lock;
	if (cdev->gadget->sg_supported) {
		queue->queue.mem_ops = &vb2_dma_sg_memops;
		queue->use_sg = 1;
	} else {
		queue->queue.mem_ops = &vb2_vmalloc_memops;
	}

	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY
				     | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
	queue->queue.dev = dev;

	ret = vb2_queue_init(&queue->queue);

Annotation

Implementation Notes