18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *      uvc_queue.c  --  USB Video Class driver - Buffers management
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *      Copyright (C) 2005-2010
68c2ecf20Sopenharmony_ci *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/atomic.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/mm.h>
128c2ecf20Sopenharmony_ci#include <linux/list.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/usb.h>
158c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
168c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
178c2ecf20Sopenharmony_ci#include <linux/wait.h>
188c2ecf20Sopenharmony_ci#include <media/videobuf2-v4l2.h>
198c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "uvcvideo.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------
248c2ecf20Sopenharmony_ci * Video buffers queue management.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Video queues is initialized by uvc_queue_init(). The function performs
278c2ecf20Sopenharmony_ci * basic initialization of the uvc_video_queue struct and never fails.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Video buffers are managed by videobuf2. The driver uses a mutex to protect
308c2ecf20Sopenharmony_ci * the videobuf2 queue operations by serializing calls to videobuf2 and a
318c2ecf20Sopenharmony_ci * spinlock to protect the IRQ queue that holds the buffers to be processed by
328c2ecf20Sopenharmony_ci * the driver.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline struct uvc_streaming *
368c2ecf20Sopenharmony_ciuvc_queue_to_stream(struct uvc_video_queue *queue)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return container_of(queue, struct uvc_streaming, queue);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return container_of(buf, struct uvc_buffer, buf);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/*
478c2ecf20Sopenharmony_ci * Return all queued buffers to videobuf2 in the requested state.
488c2ecf20Sopenharmony_ci *
498c2ecf20Sopenharmony_ci * This function must be called with the queue spinlock held.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic void uvc_queue_return_buffers(struct uvc_video_queue *queue,
528c2ecf20Sopenharmony_ci			       enum uvc_buffer_state state)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR
558c2ecf20Sopenharmony_ci					? VB2_BUF_STATE_ERROR
568c2ecf20Sopenharmony_ci					: VB2_BUF_STATE_QUEUED;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	while (!list_empty(&queue->irqqueue)) {
598c2ecf20Sopenharmony_ci		struct uvc_buffer *buf = list_first_entry(&queue->irqqueue,
608c2ecf20Sopenharmony_ci							  struct uvc_buffer,
618c2ecf20Sopenharmony_ci							  queue);
628c2ecf20Sopenharmony_ci		list_del(&buf->queue);
638c2ecf20Sopenharmony_ci		buf->state = state;
648c2ecf20Sopenharmony_ci		vb2_buffer_done(&buf->buf.vb2_buf, vb2_state);
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
698c2ecf20Sopenharmony_ci * videobuf2 queue operations
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int uvc_queue_setup(struct vb2_queue *vq,
738c2ecf20Sopenharmony_ci			   unsigned int *nbuffers, unsigned int *nplanes,
748c2ecf20Sopenharmony_ci			   unsigned int sizes[], struct device *alloc_devs[])
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
778c2ecf20Sopenharmony_ci	struct uvc_streaming *stream;
788c2ecf20Sopenharmony_ci	unsigned int size;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	switch (vq->type) {
818c2ecf20Sopenharmony_ci	case V4L2_BUF_TYPE_META_CAPTURE:
828c2ecf20Sopenharmony_ci		size = UVC_METADATA_BUF_SIZE;
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	default:
868c2ecf20Sopenharmony_ci		stream = uvc_queue_to_stream(queue);
878c2ecf20Sopenharmony_ci		size = stream->ctrl.dwMaxVideoFrameSize;
888c2ecf20Sopenharmony_ci		break;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/*
928c2ecf20Sopenharmony_ci	 * When called with plane sizes, validate them. The driver supports
938c2ecf20Sopenharmony_ci	 * single planar formats only, and requires buffers to be large enough
948c2ecf20Sopenharmony_ci	 * to store a complete frame.
958c2ecf20Sopenharmony_ci	 */
968c2ecf20Sopenharmony_ci	if (*nplanes)
978c2ecf20Sopenharmony_ci		return *nplanes != 1 || sizes[0] < size ? -EINVAL : 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	*nplanes = 1;
1008c2ecf20Sopenharmony_ci	sizes[0] = size;
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int uvc_buffer_prepare(struct vb2_buffer *vb)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1078c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
1088c2ecf20Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
1118c2ecf20Sopenharmony_ci	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
1128c2ecf20Sopenharmony_ci		uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
1138c2ecf20Sopenharmony_ci		return -EINVAL;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
1178c2ecf20Sopenharmony_ci		return -ENODEV;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	buf->state = UVC_BUF_STATE_QUEUED;
1208c2ecf20Sopenharmony_ci	buf->error = 0;
1218c2ecf20Sopenharmony_ci	buf->mem = vb2_plane_vaddr(vb, 0);
1228c2ecf20Sopenharmony_ci	buf->length = vb2_plane_size(vb, 0);
1238c2ecf20Sopenharmony_ci	if (vb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1248c2ecf20Sopenharmony_ci		buf->bytesused = 0;
1258c2ecf20Sopenharmony_ci	else
1268c2ecf20Sopenharmony_ci		buf->bytesused = vb2_get_plane_payload(vb, 0);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void uvc_buffer_queue(struct vb2_buffer *vb)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1348c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
1358c2ecf20Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
1368c2ecf20Sopenharmony_ci	unsigned long flags;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
1398c2ecf20Sopenharmony_ci	if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
1408c2ecf20Sopenharmony_ci		kref_init(&buf->ref);
1418c2ecf20Sopenharmony_ci		list_add_tail(&buf->queue, &queue->irqqueue);
1428c2ecf20Sopenharmony_ci	} else {
1438c2ecf20Sopenharmony_ci		/* If the device is disconnected return the buffer to userspace
1448c2ecf20Sopenharmony_ci		 * directly. The next QBUF call will fail with -ENODEV.
1458c2ecf20Sopenharmony_ci		 */
1468c2ecf20Sopenharmony_ci		buf->state = UVC_BUF_STATE_ERROR;
1478c2ecf20Sopenharmony_ci		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic void uvc_buffer_finish(struct vb2_buffer *vb)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1568c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
1578c2ecf20Sopenharmony_ci	struct uvc_streaming *stream = uvc_queue_to_stream(queue);
1588c2ecf20Sopenharmony_ci	struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (vb->state == VB2_BUF_STATE_DONE)
1618c2ecf20Sopenharmony_ci		uvc_video_clock_update(stream, vbuf, buf);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
1678c2ecf20Sopenharmony_ci	struct uvc_streaming *stream = uvc_queue_to_stream(queue);
1688c2ecf20Sopenharmony_ci	int ret;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	lockdep_assert_irqs_enabled();
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	queue->buf_used = 0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	ret = uvc_video_start_streaming(stream);
1758c2ecf20Sopenharmony_ci	if (ret == 0)
1768c2ecf20Sopenharmony_ci		return 0;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	spin_lock_irq(&queue->irqlock);
1798c2ecf20Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
1808c2ecf20Sopenharmony_ci	spin_unlock_irq(&queue->irqlock);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return ret;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void uvc_stop_streaming(struct vb2_queue *vq)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	lockdep_assert_irqs_enabled();
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (vq->type != V4L2_BUF_TYPE_META_CAPTURE)
1928c2ecf20Sopenharmony_ci		uvc_video_stop_streaming(uvc_queue_to_stream(queue));
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	spin_lock_irq(&queue->irqlock);
1958c2ecf20Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
1968c2ecf20Sopenharmony_ci	spin_unlock_irq(&queue->irqlock);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic const struct vb2_ops uvc_queue_qops = {
2008c2ecf20Sopenharmony_ci	.queue_setup = uvc_queue_setup,
2018c2ecf20Sopenharmony_ci	.buf_prepare = uvc_buffer_prepare,
2028c2ecf20Sopenharmony_ci	.buf_queue = uvc_buffer_queue,
2038c2ecf20Sopenharmony_ci	.buf_finish = uvc_buffer_finish,
2048c2ecf20Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
2058c2ecf20Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
2068c2ecf20Sopenharmony_ci	.start_streaming = uvc_start_streaming,
2078c2ecf20Sopenharmony_ci	.stop_streaming = uvc_stop_streaming,
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic const struct vb2_ops uvc_meta_queue_qops = {
2118c2ecf20Sopenharmony_ci	.queue_setup = uvc_queue_setup,
2128c2ecf20Sopenharmony_ci	.buf_prepare = uvc_buffer_prepare,
2138c2ecf20Sopenharmony_ci	.buf_queue = uvc_buffer_queue,
2148c2ecf20Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
2158c2ecf20Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
2168c2ecf20Sopenharmony_ci	.stop_streaming = uvc_stop_streaming,
2178c2ecf20Sopenharmony_ci};
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ciint uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
2208c2ecf20Sopenharmony_ci		    int drop_corrupted)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int ret;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	queue->queue.type = type;
2258c2ecf20Sopenharmony_ci	queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
2268c2ecf20Sopenharmony_ci	queue->queue.drv_priv = queue;
2278c2ecf20Sopenharmony_ci	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
2288c2ecf20Sopenharmony_ci	queue->queue.mem_ops = &vb2_vmalloc_memops;
2298c2ecf20Sopenharmony_ci	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
2308c2ecf20Sopenharmony_ci		| V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
2318c2ecf20Sopenharmony_ci	queue->queue.lock = &queue->mutex;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	switch (type) {
2348c2ecf20Sopenharmony_ci	case V4L2_BUF_TYPE_META_CAPTURE:
2358c2ecf20Sopenharmony_ci		queue->queue.ops = &uvc_meta_queue_qops;
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci	default:
2388c2ecf20Sopenharmony_ci		queue->queue.io_modes |= VB2_DMABUF;
2398c2ecf20Sopenharmony_ci		queue->queue.ops = &uvc_queue_qops;
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	ret = vb2_queue_init(&queue->queue);
2448c2ecf20Sopenharmony_ci	if (ret)
2458c2ecf20Sopenharmony_ci		return ret;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	mutex_init(&queue->mutex);
2488c2ecf20Sopenharmony_ci	spin_lock_init(&queue->irqlock);
2498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&queue->irqqueue);
2508c2ecf20Sopenharmony_ci	queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_civoid uvc_queue_release(struct uvc_video_queue *queue)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
2588c2ecf20Sopenharmony_ci	vb2_queue_release(&queue->queue);
2598c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
2638c2ecf20Sopenharmony_ci * V4L2 queue operations
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciint uvc_request_buffers(struct uvc_video_queue *queue,
2678c2ecf20Sopenharmony_ci			struct v4l2_requestbuffers *rb)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	int ret;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
2728c2ecf20Sopenharmony_ci	ret = vb2_reqbufs(&queue->queue, rb);
2738c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	return ret ? ret : rb->count;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ciint uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	int ret;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
2838c2ecf20Sopenharmony_ci	ret = vb2_querybuf(&queue->queue, buf);
2848c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return ret;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ciint uvc_create_buffers(struct uvc_video_queue *queue,
2908c2ecf20Sopenharmony_ci		       struct v4l2_create_buffers *cb)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	int ret;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
2958c2ecf20Sopenharmony_ci	ret = vb2_create_bufs(&queue->queue, cb);
2968c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return ret;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciint uvc_queue_buffer(struct uvc_video_queue *queue,
3028c2ecf20Sopenharmony_ci		     struct media_device *mdev, struct v4l2_buffer *buf)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int ret;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3078c2ecf20Sopenharmony_ci	ret = vb2_qbuf(&queue->queue, mdev, buf);
3088c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	return ret;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ciint uvc_export_buffer(struct uvc_video_queue *queue,
3148c2ecf20Sopenharmony_ci		      struct v4l2_exportbuffer *exp)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	int ret;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3198c2ecf20Sopenharmony_ci	ret = vb2_expbuf(&queue->queue, exp);
3208c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return ret;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ciint uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
3268c2ecf20Sopenharmony_ci		       int nonblocking)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	int ret;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3318c2ecf20Sopenharmony_ci	ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
3328c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return ret;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ciint uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	int ret;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3428c2ecf20Sopenharmony_ci	ret = vb2_streamon(&queue->queue, type);
3438c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return ret;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ciint uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	int ret;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3538c2ecf20Sopenharmony_ci	ret = vb2_streamoff(&queue->queue, type);
3548c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return ret;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ciint uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	return vb2_mmap(&queue->queue, vma);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci#ifndef CONFIG_MMU
3658c2ecf20Sopenharmony_ciunsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
3668c2ecf20Sopenharmony_ci		unsigned long pgoff)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci#endif
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
3738c2ecf20Sopenharmony_ci			    poll_table *wait)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	__poll_t ret;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3788c2ecf20Sopenharmony_ci	ret = vb2_poll(&queue->queue, file, wait);
3798c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return ret;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
3858c2ecf20Sopenharmony_ci *
3868c2ecf20Sopenharmony_ci */
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/*
3898c2ecf20Sopenharmony_ci * Check if buffers have been allocated.
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_ciint uvc_queue_allocated(struct uvc_video_queue *queue)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int allocated;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	mutex_lock(&queue->mutex);
3968c2ecf20Sopenharmony_ci	allocated = vb2_is_busy(&queue->queue);
3978c2ecf20Sopenharmony_ci	mutex_unlock(&queue->mutex);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return allocated;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/*
4038c2ecf20Sopenharmony_ci * Cancel the video buffers queue.
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * Cancelling the queue marks all buffers on the irq queue as erroneous,
4068c2ecf20Sopenharmony_ci * wakes them up and removes them from the queue.
4078c2ecf20Sopenharmony_ci *
4088c2ecf20Sopenharmony_ci * If the disconnect parameter is set, further calls to uvc_queue_buffer will
4098c2ecf20Sopenharmony_ci * fail with -ENODEV.
4108c2ecf20Sopenharmony_ci *
4118c2ecf20Sopenharmony_ci * This function acquires the irq spinlock and can be called from interrupt
4128c2ecf20Sopenharmony_ci * context.
4138c2ecf20Sopenharmony_ci */
4148c2ecf20Sopenharmony_civoid uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	unsigned long flags;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
4198c2ecf20Sopenharmony_ci	uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
4208c2ecf20Sopenharmony_ci	/* This must be protected by the irqlock spinlock to avoid race
4218c2ecf20Sopenharmony_ci	 * conditions between uvc_buffer_queue and the disconnection event that
4228c2ecf20Sopenharmony_ci	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
4238c2ecf20Sopenharmony_ci	 * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
4248c2ecf20Sopenharmony_ci	 * state outside the queue code.
4258c2ecf20Sopenharmony_ci	 */
4268c2ecf20Sopenharmony_ci	if (disconnect)
4278c2ecf20Sopenharmony_ci		queue->flags |= UVC_QUEUE_DISCONNECTED;
4288c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci/*
4328c2ecf20Sopenharmony_ci * uvc_queue_get_current_buffer: Obtain the current working output buffer
4338c2ecf20Sopenharmony_ci *
4348c2ecf20Sopenharmony_ci * Buffers may span multiple packets, and even URBs, therefore the active buffer
4358c2ecf20Sopenharmony_ci * remains on the queue until the EOF marker.
4368c2ecf20Sopenharmony_ci */
4378c2ecf20Sopenharmony_cistatic struct uvc_buffer *
4388c2ecf20Sopenharmony_ci__uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	if (list_empty(&queue->irqqueue))
4418c2ecf20Sopenharmony_ci		return NULL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return list_first_entry(&queue->irqqueue, struct uvc_buffer, queue);
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistruct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct uvc_buffer *nextbuf;
4498c2ecf20Sopenharmony_ci	unsigned long flags;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
4528c2ecf20Sopenharmony_ci	nextbuf = __uvc_queue_get_current_buffer(queue);
4538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return nextbuf;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/*
4598c2ecf20Sopenharmony_ci * uvc_queue_buffer_requeue: Requeue a buffer on our internal irqqueue
4608c2ecf20Sopenharmony_ci *
4618c2ecf20Sopenharmony_ci * Reuse a buffer through our internal queue without the need to 'prepare'.
4628c2ecf20Sopenharmony_ci * The buffer will be returned to userspace through the uvc_buffer_queue call if
4638c2ecf20Sopenharmony_ci * the device has been disconnected.
4648c2ecf20Sopenharmony_ci */
4658c2ecf20Sopenharmony_cistatic void uvc_queue_buffer_requeue(struct uvc_video_queue *queue,
4668c2ecf20Sopenharmony_ci		struct uvc_buffer *buf)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	buf->error = 0;
4698c2ecf20Sopenharmony_ci	buf->state = UVC_BUF_STATE_QUEUED;
4708c2ecf20Sopenharmony_ci	buf->bytesused = 0;
4718c2ecf20Sopenharmony_ci	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	uvc_buffer_queue(&buf->buf.vb2_buf);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic void uvc_queue_buffer_complete(struct kref *ref)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct uvc_buffer *buf = container_of(ref, struct uvc_buffer, ref);
4798c2ecf20Sopenharmony_ci	struct vb2_buffer *vb = &buf->buf.vb2_buf;
4808c2ecf20Sopenharmony_ci	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
4838c2ecf20Sopenharmony_ci		uvc_queue_buffer_requeue(queue, buf);
4848c2ecf20Sopenharmony_ci		return;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
4888c2ecf20Sopenharmony_ci	vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
4898c2ecf20Sopenharmony_ci	vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci/*
4938c2ecf20Sopenharmony_ci * Release a reference on the buffer. Complete the buffer when the last
4948c2ecf20Sopenharmony_ci * reference is released.
4958c2ecf20Sopenharmony_ci */
4968c2ecf20Sopenharmony_civoid uvc_queue_buffer_release(struct uvc_buffer *buf)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	kref_put(&buf->ref, uvc_queue_buffer_complete);
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci/*
5028c2ecf20Sopenharmony_ci * Remove this buffer from the queue. Lifetime will persist while async actions
5038c2ecf20Sopenharmony_ci * are still running (if any), and uvc_queue_buffer_release will give the buffer
5048c2ecf20Sopenharmony_ci * back to VB2 when all users have completed.
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_cistruct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
5078c2ecf20Sopenharmony_ci		struct uvc_buffer *buf)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct uvc_buffer *nextbuf;
5108c2ecf20Sopenharmony_ci	unsigned long flags;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->irqlock, flags);
5138c2ecf20Sopenharmony_ci	list_del(&buf->queue);
5148c2ecf20Sopenharmony_ci	nextbuf = __uvc_queue_get_current_buffer(queue);
5158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->irqlock, flags);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	uvc_queue_buffer_release(buf);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return nextbuf;
5208c2ecf20Sopenharmony_ci}
521