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