162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *      uvc_queue.c  --  USB Video Class driver - Buffers management
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *      Copyright (C) 2005-2010
662306a36Sopenharmony_ci *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/atomic.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/mm.h>
1262306a36Sopenharmony_ci#include <linux/list.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/usb.h>
1562306a36Sopenharmony_ci#include <linux/videodev2.h>
1662306a36Sopenharmony_ci#include <linux/vmalloc.h>
1762306a36Sopenharmony_ci#include <linux/wait.h>
1862306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
1962306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "uvcvideo.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* ------------------------------------------------------------------------
2462306a36Sopenharmony_ci * Video buffers queue management.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Video queues is initialized by uvc_queue_init(). The function performs
2762306a36Sopenharmony_ci * basic initialization of the uvc_video_queue struct and never fails.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Video buffers are managed by videobuf2. The driver uses a mutex to protect
3062306a36Sopenharmony_ci * the videobuf2 queue operations by serializing calls to videobuf2 and a
3162306a36Sopenharmony_ci * spinlock to protect the IRQ queue that holds the buffers to be processed by
3262306a36Sopenharmony_ci * the driver.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	return container_of(buf, struct uvc_buffer, buf);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * Return all queued buffers to videobuf2 in the requested state.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * This function must be called with the queue spinlock held.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistatic void uvc_queue_return_buffers(struct uvc_video_queue *queue,
4662306a36Sopenharmony_ci			       enum uvc_buffer_state state)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR
4962306a36Sopenharmony_ci					? VB2_BUF_STATE_ERROR
5062306a36Sopenharmony_ci					: VB2_BUF_STATE_QUEUED;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	while (!list_empty(&queue->irqqueue)) {
5362306a36Sopenharmony_ci		struct uvc_buffer *buf = list_first_entry(&queue->irqqueue,
5462306a36Sopenharmony_ci							  struct uvc_buffer,
5562306a36Sopenharmony_ci							  queue);
5662306a36Sopenharmony_ci		list_del(&buf->queue);
5762306a36Sopenharmony_ci		buf->state = state;
5862306a36Sopenharmony_ci		vb2_buffer_done(&buf->buf.vb2_buf, vb2_state);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
6362306a36Sopenharmony_ci * videobuf2 queue operations
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int uvc_queue_setup(struct vb2_queue *vq,
6762306a36Sopenharmony_ci			   unsigned int *nbuffers, unsigned int *nplanes,
6862306a36Sopenharmony_ci			   unsigned int sizes[], struct device *alloc_devs[])
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
7162306a36Sopenharmony_ci	struct uvc_streaming *stream;
7262306a36Sopenharmony_ci	unsigned int size;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	switch (vq->type) {
7562306a36Sopenharmony_ci	case V4L2_BUF_TYPE_META_CAPTURE:
7662306a36Sopenharmony_ci		size = UVC_METADATA_BUF_SIZE;
7762306a36Sopenharmony_ci		break;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci		stream = uvc_queue_to_stream(queue);
8162306a36Sopenharmony_ci		size = stream->ctrl.dwMaxVideoFrameSize;
8262306a36Sopenharmony_ci		break;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * When called with plane sizes, validate them. The driver supports
8762306a36Sopenharmony_ci	 * single planar formats only, and requires buffers to be large enough
8862306a36Sopenharmony_ci	 * to store a complete frame.
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	if (*nplanes)
9162306a36Sopenharmony_ci		return *nplanes != 1 || sizes[0] < size ? -EINVAL : 0;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	*nplanes = 1;
9462306a36Sopenharmony_ci	sizes[0] = size;
9562306a36Sopenharmony_ci	return 0;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int uvc_buffer_prepare(struct vb2_buffer *vb)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
10162306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
10262306a36Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
10562306a36Sopenharmony_ci	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
10662306a36Sopenharmony_ci		uvc_dbg(uvc_queue_to_stream(queue)->dev, CAPTURE,
10762306a36Sopenharmony_ci			"[E] Bytes used out of bounds\n");
10862306a36Sopenharmony_ci		return -EINVAL;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
11262306a36Sopenharmony_ci		return -ENODEV;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	buf->state = UVC_BUF_STATE_QUEUED;
11562306a36Sopenharmony_ci	buf->error = 0;
11662306a36Sopenharmony_ci	buf->mem = vb2_plane_vaddr(vb, 0);
11762306a36Sopenharmony_ci	buf->length = vb2_plane_size(vb, 0);
11862306a36Sopenharmony_ci	if (vb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
11962306a36Sopenharmony_ci		buf->bytesused = 0;
12062306a36Sopenharmony_ci	else
12162306a36Sopenharmony_ci		buf->bytesused = vb2_get_plane_payload(vb, 0);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void uvc_buffer_queue(struct vb2_buffer *vb)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
12962306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
13062306a36Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
13162306a36Sopenharmony_ci	unsigned long flags;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
13462306a36Sopenharmony_ci	if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
13562306a36Sopenharmony_ci		kref_init(&buf->ref);
13662306a36Sopenharmony_ci		list_add_tail(&buf->queue, &queue->irqqueue);
13762306a36Sopenharmony_ci	} else {
13862306a36Sopenharmony_ci		/*
13962306a36Sopenharmony_ci		 * If the device is disconnected return the buffer to userspace
14062306a36Sopenharmony_ci		 * directly. The next QBUF call will fail with -ENODEV.
14162306a36Sopenharmony_ci		 */
14262306a36Sopenharmony_ci		buf->state = UVC_BUF_STATE_ERROR;
14362306a36Sopenharmony_ci		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void uvc_buffer_finish(struct vb2_buffer *vb)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
15262306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
15362306a36Sopenharmony_ci	struct uvc_streaming *stream = uvc_queue_to_stream(queue);
15462306a36Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (vb->state == VB2_BUF_STATE_DONE)
15762306a36Sopenharmony_ci		uvc_video_clock_update(stream, vbuf, buf);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
16362306a36Sopenharmony_ci	struct uvc_streaming *stream = uvc_queue_to_stream(queue);
16462306a36Sopenharmony_ci	int ret;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	lockdep_assert_irqs_enabled();
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	queue->buf_used = 0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	ret = uvc_video_start_streaming(stream);
17162306a36Sopenharmony_ci	if (ret == 0)
17262306a36Sopenharmony_ci		return 0;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	spin_lock_irq(&queue->irqlock);
17562306a36Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
17662306a36Sopenharmony_ci	spin_unlock_irq(&queue->irqlock);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return ret;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void uvc_stop_streaming(struct vb2_queue *vq)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	lockdep_assert_irqs_enabled();
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (vq->type != V4L2_BUF_TYPE_META_CAPTURE)
18862306a36Sopenharmony_ci		uvc_video_stop_streaming(uvc_queue_to_stream(queue));
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	spin_lock_irq(&queue->irqlock);
19162306a36Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
19262306a36Sopenharmony_ci	spin_unlock_irq(&queue->irqlock);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const struct vb2_ops uvc_queue_qops = {
19662306a36Sopenharmony_ci	.queue_setup = uvc_queue_setup,
19762306a36Sopenharmony_ci	.buf_prepare = uvc_buffer_prepare,
19862306a36Sopenharmony_ci	.buf_queue = uvc_buffer_queue,
19962306a36Sopenharmony_ci	.buf_finish = uvc_buffer_finish,
20062306a36Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
20162306a36Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
20262306a36Sopenharmony_ci	.start_streaming = uvc_start_streaming,
20362306a36Sopenharmony_ci	.stop_streaming = uvc_stop_streaming,
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic const struct vb2_ops uvc_meta_queue_qops = {
20762306a36Sopenharmony_ci	.queue_setup = uvc_queue_setup,
20862306a36Sopenharmony_ci	.buf_prepare = uvc_buffer_prepare,
20962306a36Sopenharmony_ci	.buf_queue = uvc_buffer_queue,
21062306a36Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
21162306a36Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
21262306a36Sopenharmony_ci	.stop_streaming = uvc_stop_streaming,
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciint uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
21662306a36Sopenharmony_ci		    int drop_corrupted)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	int ret;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	queue->queue.type = type;
22162306a36Sopenharmony_ci	queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
22262306a36Sopenharmony_ci	queue->queue.drv_priv = queue;
22362306a36Sopenharmony_ci	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
22462306a36Sopenharmony_ci	queue->queue.mem_ops = &vb2_vmalloc_memops;
22562306a36Sopenharmony_ci	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
22662306a36Sopenharmony_ci		| V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
22762306a36Sopenharmony_ci	queue->queue.lock = &queue->mutex;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	switch (type) {
23062306a36Sopenharmony_ci	case V4L2_BUF_TYPE_META_CAPTURE:
23162306a36Sopenharmony_ci		queue->queue.ops = &uvc_meta_queue_qops;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	default:
23462306a36Sopenharmony_ci		queue->queue.io_modes |= VB2_DMABUF;
23562306a36Sopenharmony_ci		queue->queue.ops = &uvc_queue_qops;
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ret = vb2_queue_init(&queue->queue);
24062306a36Sopenharmony_ci	if (ret)
24162306a36Sopenharmony_ci		return ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	mutex_init(&queue->mutex);
24462306a36Sopenharmony_ci	spin_lock_init(&queue->irqlock);
24562306a36Sopenharmony_ci	INIT_LIST_HEAD(&queue->irqqueue);
24662306a36Sopenharmony_ci	queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_civoid uvc_queue_release(struct uvc_video_queue *queue)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
25462306a36Sopenharmony_ci	vb2_queue_release(&queue->queue);
25562306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
25962306a36Sopenharmony_ci * V4L2 queue operations
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciint uvc_request_buffers(struct uvc_video_queue *queue,
26362306a36Sopenharmony_ci			struct v4l2_requestbuffers *rb)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	int ret;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
26862306a36Sopenharmony_ci	ret = vb2_reqbufs(&queue->queue, rb);
26962306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return ret ? ret : rb->count;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ciint uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	int ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
27962306a36Sopenharmony_ci	ret = vb2_querybuf(&queue->queue, buf);
28062306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return ret;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ciint uvc_create_buffers(struct uvc_video_queue *queue,
28662306a36Sopenharmony_ci		       struct v4l2_create_buffers *cb)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	int ret;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
29162306a36Sopenharmony_ci	ret = vb2_create_bufs(&queue->queue, cb);
29262306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ciint uvc_queue_buffer(struct uvc_video_queue *queue,
29862306a36Sopenharmony_ci		     struct media_device *mdev, struct v4l2_buffer *buf)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	int ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
30362306a36Sopenharmony_ci	ret = vb2_qbuf(&queue->queue, mdev, buf);
30462306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return ret;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint uvc_export_buffer(struct uvc_video_queue *queue,
31062306a36Sopenharmony_ci		      struct v4l2_exportbuffer *exp)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
31562306a36Sopenharmony_ci	ret = vb2_expbuf(&queue->queue, exp);
31662306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return ret;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
32262306a36Sopenharmony_ci		       int nonblocking)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	int ret;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
32762306a36Sopenharmony_ci	ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
32862306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return ret;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciint uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	int ret;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
33862306a36Sopenharmony_ci	ret = vb2_streamon(&queue->queue, type);
33962306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return ret;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ciint uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
34962306a36Sopenharmony_ci	ret = vb2_streamoff(&queue->queue, type);
35062306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return ret;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ciint uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	return vb2_mmap(&queue->queue, vma);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#ifndef CONFIG_MMU
36162306a36Sopenharmony_ciunsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
36262306a36Sopenharmony_ci		unsigned long pgoff)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci#endif
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
36962306a36Sopenharmony_ci			    poll_table *wait)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	__poll_t ret;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
37462306a36Sopenharmony_ci	ret = vb2_poll(&queue->queue, file, wait);
37562306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
38162306a36Sopenharmony_ci *
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/*
38562306a36Sopenharmony_ci * Check if buffers have been allocated.
38662306a36Sopenharmony_ci */
38762306a36Sopenharmony_ciint uvc_queue_allocated(struct uvc_video_queue *queue)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	int allocated;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	mutex_lock(&queue->mutex);
39262306a36Sopenharmony_ci	allocated = vb2_is_busy(&queue->queue);
39362306a36Sopenharmony_ci	mutex_unlock(&queue->mutex);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return allocated;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/*
39962306a36Sopenharmony_ci * Cancel the video buffers queue.
40062306a36Sopenharmony_ci *
40162306a36Sopenharmony_ci * Cancelling the queue marks all buffers on the irq queue as erroneous,
40262306a36Sopenharmony_ci * wakes them up and removes them from the queue.
40362306a36Sopenharmony_ci *
40462306a36Sopenharmony_ci * If the disconnect parameter is set, further calls to uvc_queue_buffer will
40562306a36Sopenharmony_ci * fail with -ENODEV.
40662306a36Sopenharmony_ci *
40762306a36Sopenharmony_ci * This function acquires the irq spinlock and can be called from interrupt
40862306a36Sopenharmony_ci * context.
40962306a36Sopenharmony_ci */
41062306a36Sopenharmony_civoid uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	unsigned long flags;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
41562306a36Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
41662306a36Sopenharmony_ci	/*
41762306a36Sopenharmony_ci	 * This must be protected by the irqlock spinlock to avoid race
41862306a36Sopenharmony_ci	 * conditions between uvc_buffer_queue and the disconnection event that
41962306a36Sopenharmony_ci	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
42062306a36Sopenharmony_ci	 * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
42162306a36Sopenharmony_ci	 * state outside the queue code.
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	if (disconnect)
42462306a36Sopenharmony_ci		queue->flags |= UVC_QUEUE_DISCONNECTED;
42562306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/*
42962306a36Sopenharmony_ci * uvc_queue_get_current_buffer: Obtain the current working output buffer
43062306a36Sopenharmony_ci *
43162306a36Sopenharmony_ci * Buffers may span multiple packets, and even URBs, therefore the active buffer
43262306a36Sopenharmony_ci * remains on the queue until the EOF marker.
43362306a36Sopenharmony_ci */
43462306a36Sopenharmony_cistatic struct uvc_buffer *
43562306a36Sopenharmony_ci__uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	if (list_empty(&queue->irqqueue))
43862306a36Sopenharmony_ci		return NULL;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return list_first_entry(&queue->irqqueue, struct uvc_buffer, queue);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistruct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct uvc_buffer *nextbuf;
44662306a36Sopenharmony_ci	unsigned long flags;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
44962306a36Sopenharmony_ci	nextbuf = __uvc_queue_get_current_buffer(queue);
45062306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return nextbuf;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/*
45662306a36Sopenharmony_ci * uvc_queue_buffer_requeue: Requeue a buffer on our internal irqqueue
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * Reuse a buffer through our internal queue without the need to 'prepare'.
45962306a36Sopenharmony_ci * The buffer will be returned to userspace through the uvc_buffer_queue call if
46062306a36Sopenharmony_ci * the device has been disconnected.
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_cistatic void uvc_queue_buffer_requeue(struct uvc_video_queue *queue,
46362306a36Sopenharmony_ci		struct uvc_buffer *buf)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	buf->error = 0;
46662306a36Sopenharmony_ci	buf->state = UVC_BUF_STATE_QUEUED;
46762306a36Sopenharmony_ci	buf->bytesused = 0;
46862306a36Sopenharmony_ci	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	uvc_buffer_queue(&buf->buf.vb2_buf);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void uvc_queue_buffer_complete(struct kref *ref)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct uvc_buffer *buf = container_of(ref, struct uvc_buffer, ref);
47662306a36Sopenharmony_ci	struct vb2_buffer *vb = &buf->buf.vb2_buf;
47762306a36Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
48062306a36Sopenharmony_ci		uvc_queue_buffer_requeue(queue, buf);
48162306a36Sopenharmony_ci		return;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
48562306a36Sopenharmony_ci	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
48662306a36Sopenharmony_ci	vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * Release a reference on the buffer. Complete the buffer when the last
49162306a36Sopenharmony_ci * reference is released.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_civoid uvc_queue_buffer_release(struct uvc_buffer *buf)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	kref_put(&buf->ref, uvc_queue_buffer_complete);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/*
49962306a36Sopenharmony_ci * Remove this buffer from the queue. Lifetime will persist while async actions
50062306a36Sopenharmony_ci * are still running (if any), and uvc_queue_buffer_release will give the buffer
50162306a36Sopenharmony_ci * back to VB2 when all users have completed.
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_cistruct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
50462306a36Sopenharmony_ci		struct uvc_buffer *buf)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct uvc_buffer *nextbuf;
50762306a36Sopenharmony_ci	unsigned long flags;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
51062306a36Sopenharmony_ci	list_del(&buf->queue);
51162306a36Sopenharmony_ci	nextbuf = __uvc_queue_get_current_buffer(queue);
51262306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	uvc_queue_buffer_release(buf);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return nextbuf;
51762306a36Sopenharmony_ci}
518