diff options
45 files changed, 611 insertions, 226 deletions
diff --git a/Documentation/userspace-api/media/v4l/user-func.rst b/Documentation/userspace-api/media/v4l/user-func.rst index 15ff0bf7bbe6..6f661138801c 100644 --- a/Documentation/userspace-api/media/v4l/user-func.rst +++ b/Documentation/userspace-api/media/v4l/user-func.rst @@ -62,6 +62,7 @@ Function Reference vidioc-query-dv-timings vidioc-querystd vidioc-reqbufs + vidioc-remove-bufs vidioc-s-hw-freq-seek vidioc-streamon vidioc-subdev-enum-frame-interval diff --git a/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst new file mode 100644 index 000000000000..1995b39af9ba --- /dev/null +++ b/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst @@ -0,0 +1,86 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: V4L + +.. _VIDIOC_REMOVE_BUFS: + +************************ +ioctl VIDIOC_REMOVE_BUFS +************************ + +Name +==== + +VIDIOC_REMOVE_BUFS - Removes buffers from a queue + +Synopsis +======== + +.. c:macro:: VIDIOC_REMOVE_BUFS + +``int ioctl(int fd, VIDIOC_REMOVE_BUFS, struct v4l2_remove_buffers *argp)`` + +Arguments +========= + +``fd`` + File descriptor returned by :c:func:`open()`. + +``argp`` + Pointer to struct :c:type:`v4l2_remove_buffers`. + +Description +=========== + +Applications can optionally call the :ref:`VIDIOC_REMOVE_BUFS` ioctl to +remove buffers from a queue. +:ref:`VIDIOC_CREATE_BUFS` ioctl support is mandatory to enable :ref:`VIDIOC_REMOVE_BUFS`. +This ioctl is available if the ``V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS`` capability +is set on the queue when :c:func:`VIDIOC_REQBUFS` or :c:func:`VIDIOC_CREATE_BUFS` +are invoked. + +.. c:type:: v4l2_remove_buffers + +.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}| + +.. flat-table:: struct v4l2_remove_buffers + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``index`` + - The starting buffer index to remove. This field is ignored if count == 0. + * - __u32 + - ``count`` + - The number of buffers to be removed with indices 'index' until 'index + count - 1'. + All buffers in this range must be valid and in DEQUEUED state. + :ref:`VIDIOC_REMOVE_BUFS` will always check the validity of ``type`, if it is + invalid it returns ``EINVAL`` error code. + If count is set to 0 :ref:`VIDIOC_REMOVE_BUFS` will do nothing and return 0. + * - __u32 + - ``type`` + - Type of the stream or buffers, this is the same as the struct + :c:type:`v4l2_format` ``type`` field. See + :c:type:`v4l2_buf_type` for valid values. + * - __u32 + - ``reserved``\ [13] + - A place holder for future extensions. Drivers and applications + must set the array to zero. + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. If an error occurs, no +buffers will be freed and one of the error codes below will be returned: + +EBUSY + File I/O is in progress. + One or more of the buffers in the range ``index`` to ``index + count - 1`` are not + in DEQUEUED state. + +EINVAL + One or more of the buffers in the range ``index`` to ``index + count - 1`` do not + exist in the queue. + The buffer type (``type`` field) is not valid. diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst index 0b3a41a45d05..bbc22dd76032 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst @@ -121,6 +121,7 @@ aborting or finishing any DMA in progress, an implicit .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: .. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS: .. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS: +.. _V4L2-BUF-CAP-SUPPORTS-REMOVE-BUFS: .. raw:: latex diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index b6bf8f232f48..0b2b48e1b2df 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -421,11 +421,12 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) */ static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index) { - WARN_ON(index >= q->max_num_buffers || q->bufs[index] || vb->vb2_queue); + WARN_ON(index >= q->max_num_buffers || test_bit(index, q->bufs_bitmap) || vb->vb2_queue); q->bufs[index] = vb; vb->index = index; vb->vb2_queue = q; + set_bit(index, q->bufs_bitmap); } /** @@ -434,6 +435,7 @@ static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, uns */ static void vb2_queue_remove_buffer(struct vb2_buffer *vb) { + clear_bit(vb->index, vb->vb2_queue->bufs_bitmap); vb->vb2_queue->bufs[vb->index] = NULL; vb->vb2_queue = NULL; } @@ -442,16 +444,19 @@ static void vb2_queue_remove_buffer(struct vb2_buffer *vb) * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type) * video buffer memory for all buffers/planes on the queue and initializes the * queue + * @first_index: index of the first created buffer, all newly allocated buffers + * have indices in the range [first_index..first_index+count-1] * * Returns the number of buffers successfully allocated. */ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, unsigned int num_buffers, unsigned int num_planes, - const unsigned plane_sizes[VB2_MAX_PLANES]) + const unsigned int plane_sizes[VB2_MAX_PLANES], + unsigned int *first_index) { - unsigned int q_num_buffers = vb2_get_num_buffers(q); unsigned int buffer, plane; struct vb2_buffer *vb; + unsigned long index = q->max_num_buffers; int ret; /* @@ -459,7 +464,25 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, * in the queue is below q->max_num_buffers */ num_buffers = min_t(unsigned int, num_buffers, - q->max_num_buffers - q_num_buffers); + q->max_num_buffers - vb2_get_num_buffers(q)); + + while (num_buffers) { + index = bitmap_find_next_zero_area(q->bufs_bitmap, q->max_num_buffers, + 0, num_buffers, 0); + + if (index < q->max_num_buffers) + break; + /* Try to find free space for less buffers */ + num_buffers--; + } + + /* If there is no space left to allocate buffers return 0 to indicate the error */ + if (!num_buffers) { + *first_index = 0; + return 0; + } + + *first_index = index; for (buffer = 0; buffer < num_buffers; ++buffer) { /* Allocate vb2 buffer structures */ @@ -479,7 +502,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->planes[plane].min_length = plane_sizes[plane]; } - vb2_queue_add_buffer(q, vb, q_num_buffers + buffer); + vb2_queue_add_buffer(q, vb, index++); call_void_bufop(q, init_buffer, vb); /* Allocate video buffer memory for the MMAP type */ @@ -517,17 +540,16 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, } /* - * __vb2_free_mem() - release all video buffer memory for a given queue + * __vb2_free_mem() - release video buffer memory for a given range of + * buffers in a given queue */ -static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) +static void __vb2_free_mem(struct vb2_queue *q, unsigned int start, unsigned int count) { - unsigned int buffer; + unsigned int i; struct vb2_buffer *vb; - unsigned int q_num_buffers = vb2_get_num_buffers(q); - for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; - ++buffer) { - vb = vb2_get_buffer(q, buffer); + for (i = start; i < start + count; i++) { + vb = vb2_get_buffer(q, i); if (!vb) continue; @@ -542,35 +564,33 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) } /* - * __vb2_queue_free() - free buffers at the end of the queue - video memory and + * __vb2_queue_free() - free @count buffers from @start index of the queue - video memory and * related information, if no buffers are left return the queue to an * uninitialized state. Might be called even if the queue has already been freed. */ -static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) +static void __vb2_queue_free(struct vb2_queue *q, unsigned int start, unsigned int count) { - unsigned int buffer; - unsigned int q_num_buffers = vb2_get_num_buffers(q); + unsigned int i; lockdep_assert_held(&q->mmap_lock); /* Call driver-provided cleanup function for each buffer, if provided */ - for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; - ++buffer) { - struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + for (i = start; i < start + count; i++) { + struct vb2_buffer *vb = vb2_get_buffer(q, i); if (vb && vb->planes[0].mem_priv) call_void_vb_qop(vb, buf_cleanup, vb); } /* Release video buffer memory */ - __vb2_free_mem(q, buffers); + __vb2_free_mem(q, start, count); #ifdef CONFIG_VIDEO_ADV_DEBUG /* * Check that all the calls were balanced during the life-time of this * queue. If not then dump the counters to the kernel log. */ - if (q_num_buffers) { + if (vb2_get_num_buffers(q)) { bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || q->cnt_prepare_streaming != q->cnt_unprepare_streaming || q->cnt_wait_prepare != q->cnt_wait_finish; @@ -596,8 +616,8 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->cnt_stop_streaming = 0; q->cnt_unprepare_streaming = 0; } - for (buffer = 0; buffer < vb2_get_num_buffers(q); buffer++) { - struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + for (i = start; i < start + count; i++) { + struct vb2_buffer *vb = vb2_get_buffer(q, i); bool unbalanced; if (!vb) @@ -614,7 +634,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) if (unbalanced) { pr_info("unbalanced counters for queue %p, buffer %d:\n", - q, buffer); + q, i); if (vb->cnt_buf_init != vb->cnt_buf_cleanup) pr_info(" buf_init: %u buf_cleanup: %u\n", vb->cnt_buf_init, vb->cnt_buf_cleanup); @@ -648,9 +668,8 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) #endif /* Free vb2 buffers */ - for (buffer = q_num_buffers - buffers; buffer < q_num_buffers; - ++buffer) { - struct vb2_buffer *vb = vb2_get_buffer(q, buffer); + for (i = start; i < start + count; i++) { + struct vb2_buffer *vb = vb2_get_buffer(q, i); if (!vb) continue; @@ -659,7 +678,6 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) kfree(vb); } - q->num_buffers -= buffers; if (!vb2_get_num_buffers(q)) { q->memory = VB2_MEMORY_UNKNOWN; INIT_LIST_HEAD(&q->queued_list); @@ -691,7 +709,7 @@ EXPORT_SYMBOL(vb2_buffer_in_use); static bool __buffers_in_use(struct vb2_queue *q) { unsigned int buffer; - for (buffer = 0; buffer < vb2_get_num_buffers(q); ++buffer) { + for (buffer = 0; buffer < q->max_num_buffers; ++buffer) { struct vb2_buffer *vb = vb2_get_buffer(q, buffer); if (!vb) @@ -813,6 +831,32 @@ static bool verify_coherency_flags(struct vb2_queue *q, bool non_coherent_mem) return true; } +static int vb2_core_allocated_buffers_storage(struct vb2_queue *q) +{ + if (!q->bufs) + q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL); + if (!q->bufs) + return -ENOMEM; + + if (!q->bufs_bitmap) + q->bufs_bitmap = bitmap_zalloc(q->max_num_buffers, GFP_KERNEL); + if (!q->bufs_bitmap) { + kfree(q->bufs); + q->bufs = NULL; + return -ENOMEM; + } + + return 0; +} + +static void vb2_core_free_buffers_storage(struct vb2_queue *q) +{ + kfree(q->bufs); + q->bufs = NULL; + bitmap_free(q->bufs_bitmap); + q->bufs_bitmap = NULL; +} + int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int flags, unsigned int *count) { @@ -820,7 +864,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int q_num_bufs = vb2_get_num_buffers(q); unsigned plane_sizes[VB2_MAX_PLANES] = { }; bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; - unsigned int i; + unsigned int i, first_index; int ret = 0; if (q->streaming) { @@ -851,9 +895,10 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * queued without ever calling STREAMON. */ __vb2_queue_cancel(q); - __vb2_queue_free(q, q_num_bufs); + __vb2_queue_free(q, 0, q->max_num_buffers); mutex_unlock(&q->mmap_lock); + q->is_busy = 0; /* * In case of REQBUFS(0) return immediately without calling * driver's queue_setup() callback and allocating resources. @@ -865,7 +910,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, /* * Make sure the requested values and current defaults are sane. */ - num_buffers = max_t(unsigned int, *count, q->min_queued_buffers); + num_buffers = max_t(unsigned int, *count, q->min_reqbufs_allocation); num_buffers = min_t(unsigned int, num_buffers, q->max_num_buffers); memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); /* @@ -873,10 +918,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * in the queue_setup op. */ mutex_lock(&q->mmap_lock); - if (!q->bufs) - q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL); - if (!q->bufs) - ret = -ENOMEM; + ret = vb2_core_allocated_buffers_storage(q); q->memory = memory; mutex_unlock(&q->mmap_lock); if (ret) @@ -906,8 +948,10 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, /* Finally, allocate buffers and video memory */ allocated_buffers = - __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); + __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes, &first_index); if (allocated_buffers == 0) { + /* There shouldn't be any buffers allocated, so first_index == 0 */ + WARN_ON(first_index); dprintk(q, 1, "memory allocation failed\n"); ret = -ENOMEM; goto error; @@ -917,7 +961,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * There is no point in continuing if we can't allocate the minimum * number of buffers needed by this vb2_queue. */ - if (allocated_buffers < q->min_queued_buffers) + if (allocated_buffers < q->min_reqbufs_allocation) ret = -ENOMEM; /* @@ -946,7 +990,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, } mutex_lock(&q->mmap_lock); - q->num_buffers = allocated_buffers; if (ret < 0) { /* @@ -954,7 +997,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * from already queued buffers and it will reset q->memory to * VB2_MEMORY_UNKNOWN. */ - __vb2_queue_free(q, allocated_buffers); + __vb2_queue_free(q, first_index, allocated_buffers); mutex_unlock(&q->mmap_lock); return ret; } @@ -966,6 +1009,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ *count = allocated_buffers; q->waiting_for_buffers = !q->is_output; + q->is_busy = 1; return 0; @@ -973,6 +1017,7 @@ error: mutex_lock(&q->mmap_lock); q->memory = VB2_MEMORY_UNKNOWN; mutex_unlock(&q->mmap_lock); + vb2_core_free_buffers_storage(q); return ret; } EXPORT_SYMBOL_GPL(vb2_core_reqbufs); @@ -980,7 +1025,8 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs); int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int flags, unsigned int *count, unsigned int requested_planes, - const unsigned int requested_sizes[]) + const unsigned int requested_sizes[], + unsigned int *first_index) { unsigned int num_planes = 0, num_buffers, allocated_buffers; unsigned plane_sizes[VB2_MAX_PLANES] = { }; @@ -1005,11 +1051,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * value in the queue_setup op. */ mutex_lock(&q->mmap_lock); + ret = vb2_core_allocated_buffers_storage(q); q->memory = memory; - if (!q->bufs) - q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL); - if (!q->bufs) - ret = -ENOMEM; mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -1042,7 +1085,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, /* Finally, allocate buffers and video memory */ allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, - num_planes, plane_sizes); + num_planes, plane_sizes, first_index); if (allocated_buffers == 0) { dprintk(q, 1, "memory allocation failed\n"); ret = -ENOMEM; @@ -1072,7 +1115,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } mutex_lock(&q->mmap_lock); - q->num_buffers += allocated_buffers; if (ret < 0) { /* @@ -1080,7 +1122,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * from already queued buffers and it will reset q->memory to * VB2_MEMORY_UNKNOWN. */ - __vb2_queue_free(q, allocated_buffers); + __vb2_queue_free(q, *first_index, allocated_buffers); mutex_unlock(&q->mmap_lock); return -ENOMEM; } @@ -1091,6 +1133,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * to the userspace. */ *count = allocated_buffers; + q->is_busy = 1; return 0; @@ -1648,6 +1691,44 @@ int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb) } EXPORT_SYMBOL_GPL(vb2_core_prepare_buf); +int vb2_core_remove_bufs(struct vb2_queue *q, unsigned int start, unsigned int count) +{ + unsigned int i, ret = 0; + unsigned int q_num_bufs = vb2_get_num_buffers(q); + + if (count == 0) + return 0; + + if (count > q_num_bufs) + return -EINVAL; + + if (start > q->max_num_buffers - count) + return -EINVAL; + + mutex_lock(&q->mmap_lock); + + /* Check that all buffers in the range exist */ + for (i = start; i < start + count; i++) { + struct vb2_buffer *vb = vb2_get_buffer(q, i); + + if (!vb) { + ret = -EINVAL; + goto unlock; + } + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + ret = -EBUSY; + goto unlock; + } + } + __vb2_queue_free(q, start, count); + dprintk(q, 2, "%u buffers removed\n", count); + +unlock: + mutex_unlock(&q->mmap_lock); + return ret; +} +EXPORT_SYMBOL_GPL(vb2_core_remove_bufs); + /* * vb2_start_streaming() - Attempt to start streaming. * @q: videobuf2 queue @@ -1694,7 +1775,7 @@ static int vb2_start_streaming(struct vb2_queue *q) * Forcefully reclaim buffers if the driver did not * correctly return them to vb2. */ - for (i = 0; i < vb2_get_num_buffers(q); ++i) { + for (i = 0; i < q->max_num_buffers; ++i) { vb = vb2_get_buffer(q, i); if (!vb) @@ -2100,7 +2181,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * to vb2 in stop_streaming(). */ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { - for (i = 0; i < vb2_get_num_buffers(q); i++) { + for (i = 0; i < q->max_num_buffers; i++) { struct vb2_buffer *vb = vb2_get_buffer(q, i); if (!vb) @@ -2144,7 +2225,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * call to __fill_user_buffer() after buf_finish(). That order can't * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ - for (i = 0; i < vb2_get_num_buffers(q); i++) { + for (i = 0; i < q->max_num_buffers; i++) { struct vb2_buffer *vb; struct media_request *req; @@ -2521,6 +2602,25 @@ int vb2_core_queue_init(struct vb2_queue *q) if (WARN_ON(q->supports_requests && q->min_queued_buffers)) return -EINVAL; + /* + * The minimum requirement is 2: one buffer is used + * by the hardware while the other is being processed by userspace. + */ + if (q->min_reqbufs_allocation < 2) + q->min_reqbufs_allocation = 2; + + /* + * If the driver needs 'min_queued_buffers' in the queue before + * calling start_streaming() then the minimum requirement is + * 'min_queued_buffers + 1' to keep at least one buffer available + * for userspace. + */ + if (q->min_reqbufs_allocation < q->min_queued_buffers + 1) + q->min_reqbufs_allocation = q->min_queued_buffers + 1; + + if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); @@ -2552,9 +2652,9 @@ void vb2_core_queue_release(struct vb2_queue *q) __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); mutex_lock(&q->mmap_lock); - __vb2_queue_free(q, vb2_get_num_buffers(q)); - kfree(q->bufs); - q->bufs = NULL; + __vb2_queue_free(q, 0, q->max_num_buffers); + vb2_core_free_buffers_storage(q); + q->is_busy = 0; mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_core_queue_release); @@ -2713,7 +2813,6 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) struct vb2_fileio_data *fileio; struct vb2_buffer *vb; int i, ret; - unsigned int count = 0; /* * Sanity check @@ -2734,18 +2833,8 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) if (q->streaming || vb2_get_num_buffers(q) > 0) return -EBUSY; - /* - * Start with q->min_queued_buffers + 1, driver can increase it in - * queue_setup() - * - * 'min_queued_buffers' buffers need to be queued up before you - * can start streaming, plus 1 for userspace (or in this case, - * kernelspace) processing. - */ - count = max(2, q->min_queued_buffers + 1); - dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", - (read) ? "read" : "write", count, q->fileio_read_once, + (read) ? "read" : "write", q->min_reqbufs_allocation, q->fileio_read_once, q->fileio_write_immediately); fileio = kzalloc(sizeof(*fileio), GFP_KERNEL); @@ -2759,7 +2848,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) * Request buffers and use MMAP type to force driver * to allocate buffers by itself. */ - fileio->count = count; + fileio->count = q->min_reqbufs_allocation; fileio->memory = VB2_MEMORY_MMAP; fileio->type = q->type; q->fileio = fileio; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index c575198e8354..293f3d5f1c4e 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -685,7 +685,7 @@ static void vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory, *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; } - *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; + *caps |= V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; if (q->io_modes & VB2_MMAP) *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP; if (q->io_modes & VB2_USERPTR) @@ -795,11 +795,15 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) for (i = 0; i < requested_planes; i++) if (requested_sizes[i] == 0) return -EINVAL; - return ret ? ret : vb2_core_create_bufs(q, create->memory, - create->flags, - &create->count, - requested_planes, - requested_sizes); + if (ret) + return ret; + + return vb2_core_create_bufs(q, create->memory, + create->flags, + &create->count, + requested_planes, + requested_sizes, + &create->index); } EXPORT_SYMBOL_GPL(vb2_create_bufs); @@ -997,6 +1001,24 @@ EXPORT_SYMBOL_GPL(vb2_poll); /* vb2 ioctl helpers */ +int vb2_ioctl_remove_bufs(struct file *file, void *priv, + struct v4l2_remove_buffers *d) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->queue->type != d->type) + return -EINVAL; + + if (d->count == 0) + return 0; + + if (vb2_queue_is_busy(vdev->queue, file)) + return -EBUSY; + + return vb2_core_remove_bufs(vdev->queue, d->index, d->count); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_remove_bufs); + int vb2_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index 8433ecab230c..7e0f34bfa5be 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -52,11 +52,12 @@ int wave5_vpu_release_device(struct file *filp, char *name) { struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); + struct vpu_device *dev = inst->dev; + int ret = 0; v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); if (inst->state != VPU_INST_STATE_NONE) { u32 fail_res; - int ret; ret = close_func(inst, &fail_res); if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) { @@ -71,8 +72,20 @@ int wave5_vpu_release_device(struct file *filp, } wave5_cleanup_instance(inst); + if (dev->irq < 0) { + ret = mutex_lock_interruptible(&dev->dev_lock); + if (ret) + return ret; - return 0; + if (list_empty(&dev->instances)) { + dev_dbg(dev->dev, "Disabling the hrtimer\n"); + hrtimer_cancel(&dev->hrtimer); + } + + mutex_unlock(&dev->dev_lock); + } + + return ret; } int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq, diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index ef227af72348..c8624c681fa6 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -1810,7 +1810,6 @@ static int wave5_vpu_open_dec(struct file *filp) v4l2_fh_add(&inst->v4l2_fh); INIT_LIST_HEAD(&inst->list); - list_add_tail(&inst->list, &dev->instances); inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_dec_dev; inst->v4l2_fh.m2m_ctx = @@ -1867,6 +1866,18 @@ static int wave5_vpu_open_dec(struct file *filp) wave5_vdi_allocate_sram(inst->dev); + ret = mutex_lock_interruptible(&dev->dev_lock); + if (ret) + goto cleanup_inst; + + if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) + hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), + HRTIMER_MODE_REL_PINNED); + + list_add_tail(&inst->list, &dev->instances); + + mutex_unlock(&dev->dev_lock); + return 0; cleanup_inst: diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 8bbf9d10b467..a45a2f699000 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1554,7 +1554,6 @@ static int wave5_vpu_open_enc(struct file *filp) v4l2_fh_add(&inst->v4l2_fh); INIT_LIST_HEAD(&inst->list); - list_add_tail(&inst->list, &dev->instances); inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev; inst->v4l2_fh.m2m_ctx = @@ -1729,6 +1728,18 @@ static int wave5_vpu_open_enc(struct file *filp) wave5_vdi_allocate_sram(inst->dev); + ret = mutex_lock_interruptible(&dev->dev_lock); + if (ret) + goto cleanup_inst; + + if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) + hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), + HRTIMER_MODE_REL_PINNED); + + list_add_tail(&inst->list, &dev->instances); + + mutex_unlock(&dev->dev_lock); + return 0; cleanup_inst: diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c index 1b3df5b04249..68a519ac412d 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -26,6 +26,9 @@ struct wave5_match_data { const char *fw_name; }; +static int vpu_poll_interval = 5; +module_param(vpu_poll_interval, int, 0644); + int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout) { int ret; @@ -40,7 +43,7 @@ int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout) return 0; } -static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id) +static void wave5_vpu_handle_irq(void *dev_id) { u32 seq_done; u32 cmd_done; @@ -48,42 +51,67 @@ static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id) struct vpu_instance *inst; struct vpu_device *dev = dev_id; - if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) { - irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON); - wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason); - wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1); - - list_for_each_entry(inst, &dev->instances, list) { - seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO); - cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST); - - if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || - irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { - if (seq_done & BIT(inst->id)) { - seq_done &= ~BIT(inst->id); - wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, - seq_done); - complete(&inst->irq_done); - } + irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON); + wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason); + wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1); + + list_for_each_entry(inst, &dev->instances, list) { + seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO); + cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST); + + if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || + irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { + if (seq_done & BIT(inst->id)) { + seq_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, + seq_done); + complete(&inst->irq_done); } + } - if (irq_reason & BIT(INT_WAVE5_DEC_PIC) || - irq_reason & BIT(INT_WAVE5_ENC_PIC)) { - if (cmd_done & BIT(inst->id)) { - cmd_done &= ~BIT(inst->id); - wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST, - cmd_done); - inst->ops->finish_process(inst); - } + if (irq_reason & BIT(INT_WAVE5_DEC_PIC) || + irq_reason & BIT(INT_WAVE5_ENC_PIC)) { + if (cmd_done & BIT(inst->id)) { + cmd_done &= ~BIT(inst->id); + wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST, + cmd_done); + inst->ops->finish_process(inst); } - - wave5_vpu_clear_interrupt(inst, irq_reason); } + + wave5_vpu_clear_interrupt(inst, irq_reason); } +} + +static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id) +{ + struct vpu_device *dev = dev_id; + + if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) + wave5_vpu_handle_irq(dev); return IRQ_HANDLED; } +static void wave5_vpu_irq_work_fn(struct kthread_work *work) +{ + struct vpu_device *dev = container_of(work, struct vpu_device, work); + + if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) + wave5_vpu_handle_irq(dev); +} + +static enum hrtimer_restart wave5_vpu_timer_callback(struct hrtimer *timer) +{ + struct vpu_device *dev = + container_of(timer, struct vpu_device, hrtimer); + + kthread_queue_work(dev->worker, &dev->work); + hrtimer_forward_now(timer, ns_to_ktime(vpu_poll_interval * NSEC_PER_MSEC)); + + return HRTIMER_RESTART; +} + static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name, u32 *revision) { @@ -185,6 +213,28 @@ static int wave5_vpu_probe(struct platform_device *pdev) } dev->product = wave5_vpu_get_product_id(dev); + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n"); + hrtimer_init(&dev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + dev->hrtimer.function = &wave5_vpu_timer_callback; + dev->worker = kthread_create_worker(0, "vpu_irq_thread"); + if (IS_ERR(dev->worker)) { + dev_err(&pdev->dev, "failed to create vpu irq worker\n"); + ret = PTR_ERR(dev->worker); + goto err_vdi_release; + } + dev->vpu_poll_interval = vpu_poll_interval; + kthread_init_work(&dev->work, wave5_vpu_irq_work_fn); + } else { + ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL, + wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev); + if (ret) { + dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret); + goto err_enc_unreg; + } + } + INIT_LIST_HEAD(&dev->instances); ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) { @@ -207,20 +257,6 @@ static int wave5_vpu_probe(struct platform_device *pdev) } } - dev->irq = platform_get_irq(pdev, 0); - if (dev->irq < 0) { - dev_err(&pdev->dev, "failed to get irq resource\n"); - ret = -ENXIO; - goto err_enc_unreg; - } - - ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL, - wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev); - if (ret) { - dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret); - goto err_enc_unreg; - } - ret = wave5_vpu_load_firmware(&pdev->dev, match_data->fw_name, &fw_revision); if (ret) { dev_err(&pdev->dev, "wave5_vpu_load_firmware, fail: %d\n", ret); @@ -254,6 +290,11 @@ static void wave5_vpu_remove(struct platform_device *pdev) { struct vpu_device *dev = dev_get_drvdata(&pdev->dev); + if (dev->irq < 0) { + kthread_destroy_worker(dev->worker); + hrtimer_cancel(&dev->hrtimer); + } + mutex_destroy(&dev->dev_lock); mutex_destroy(&dev->hw_lock); clk_bulk_disable_unprepare(dev->num_clks, dev->clks); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h index 352f6e904e50..edc50450ddb8 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h @@ -756,6 +756,10 @@ struct vpu_device { u32 product_code; struct ida inst_ida; struct clk_bulk_data *clks; + struct hrtimer hrtimer; + struct kthread_work work; + struct kthread_worker *worker; + int vpu_poll_interval; int num_clks; }; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c index ba742f0e391d..9107707de6c4 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c @@ -262,7 +262,7 @@ static int vidioc_try_fmt(struct mtk_vcodec_dec_ctx *ctx, struct v4l2_format *f, int tmp_w, tmp_h; /* - * Find next closer width align 64, heign align 64, size align + * Find next closer width align 64, height align 64, size align * 64 rectangle * Note: This only get default value, the real HW needed value * only available when ctx in MTK_STATE_HEADER state diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h index 849b89dd205c..f975db4293da 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h @@ -67,11 +67,11 @@ enum mtk_vdec_hw_arch { * @pic_w: picture width * @pic_h: picture height * @buf_w: picture buffer width (64 aligned up from pic_w) - * @buf_h: picture buffer heiht (64 aligned up from pic_h) + * @buf_h: picture buffer height (64 aligned up from pic_h) * @fb_sz: bitstream size of each plane * E.g. suppose picture size is 176x144, * buffer size will be aligned to 176x160. - * @cap_fourcc: fourcc number(may changed when resolution change) + * @cap_fourcc: fourcc number(may change on a resolution change) * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os. */ struct vdec_pic_info { diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c index 2b6a5adbc419..a081e12d67d6 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c @@ -326,7 +326,7 @@ struct vdec_av1_slice_quantization { * @use_lr: whether to use loop restoration * @use_chroma_lr: whether to use chroma loop restoration * @frame_restoration_type: specifies the type of restoration used for each plane - * @loop_restoration_size: pecifies the size of loop restoration units in units + * @loop_restoration_size: specifies the size of loop restoration units in units * of samples in the current plane */ struct vdec_av1_slice_lr { @@ -347,7 +347,7 @@ struct vdec_av1_slice_lr { * and loop_filter_sharpness together determine when * a block edge is filtered, and by how much the * filtering can change the sample values - * @loop_filter_delta_enabled: filetr level depends on the mode and reference + * @loop_filter_delta_enabled: filter level depends on the mode and reference * frame used to predict a block */ struct vdec_av1_slice_loop_filter { @@ -392,7 +392,7 @@ struct vdec_av1_slice_mfmv { /** * struct vdec_av1_slice_tile - AV1 Tile info * @tile_cols: specifies the number of tiles across the frame - * @tile_rows: pecifies the number of tiles down the frame + * @tile_rows: specifies the number of tiles down the frame * @mi_col_starts: an array specifying the start column * @mi_row_starts: an array specifying the start row * @context_update_tile_id: specifies which tile to use for the CDF update @@ -423,15 +423,15 @@ struct vdec_av1_slice_tile { * or the tile sizes are coded * @interpolation_filter: specifies the filter selection used for performing inter prediction * @allow_warped_motion: motion_mode may be present or not - * @is_motion_mode_switchable : euqlt to 0 specifies that only the SIMPLE motion mode will be used + * @is_motion_mode_switchable : equal to 0 specifies that only the SIMPLE motion mode will be used * @reference_mode : frame reference mode selected * @allow_high_precision_mv: specifies that motion vectors are specified to * quarter pel precision or to eighth pel precision - * @allow_intra_bc: ubducates that intra block copy may be used in this frame + * @allow_intra_bc: allows that intra block copy may be used in this frame * @force_integer_mv: specifies motion vectors will always be integers or * can contain fractional bits * @allow_screen_content_tools: intra blocks may use palette encoding - * @error_resilient_mode: error resislent mode is enable/disable + * @error_resilient_mode: error resilient mode is enable/disable * @frame_type: specifies the AV1 frame type * @primary_ref_frame: specifies which reference frame contains the CDF values * and other state that should be loaded at the start of the frame @@ -440,8 +440,8 @@ struct vdec_av1_slice_tile { * @disable_cdf_update: specified whether the CDF update in the symbol * decoding process should be disables * @skip_mode: av1 skip mode parameters - * @seg: av1 segmentaon parameters - * @delta_q_lf: av1 delta loop fileter + * @seg: av1 segmentation parameters + * @delta_q_lf: av1 delta loop filter * @quant: av1 Quantization params * @lr: av1 Loop Restauration parameters * @superres_denom: the denominator for the upscaling ratio @@ -450,8 +450,8 @@ struct vdec_av1_slice_tile { * @mfmv: av1 mfmv parameters * @tile: av1 Tile info * @frame_is_intra: intra frame - * @loss_less_array: loss less array - * @coded_loss_less: coded lsss less + * @loss_less_array: lossless array + * @coded_loss_less: coded lossless * @mi_rows: size of mi unit in rows * @mi_cols: size of mi unit in cols */ diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c index bf7dffe60d07..795cb19b075d 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c @@ -94,7 +94,7 @@ struct vdec_h264_dec_info { * AP-W/R : AP is writer/reader on this item * VPU-W/R: VPU is write/reader on this item * @hdr_buf : Header parsing buffer (AP-W, VPU-R) - * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R) + * @pred_buf_dma : HW working prediction buffer dma address (AP-W, VPU-R) * @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R) * @list_free : free frame buffer ring list (AP-W/R, VPU-W) * @list_disp : display frame buffer ring list (AP-R, VPU-W) @@ -117,7 +117,7 @@ struct vdec_h264_vsi { * struct vdec_h264_inst - h264 decoder instance * @num_nalu : how many nalus be decoded * @ctx : point to mtk_vcodec_dec_ctx - * @pred_buf : HW working predication buffer + * @pred_buf : HW working prediction buffer * @mv_buf : HW working motion vector buffer * @vpu : VPU instance * @vsi : VPU shared information @@ -136,7 +136,7 @@ static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) return HW_MB_STORE_SZ * (width/MB_UNIT_LEN) * (height/MB_UNIT_LEN); } -static int allocate_predication_buf(struct vdec_h264_inst *inst) +static int allocate_prediction_buf(struct vdec_h264_inst *inst) { int err = 0; @@ -151,7 +151,7 @@ static int allocate_predication_buf(struct vdec_h264_inst *inst) return 0; } -static void free_predication_buf(struct vdec_h264_inst *inst) +static void free_prediction_buf(struct vdec_h264_inst *inst) { struct mtk_vcodec_mem *mem = NULL; @@ -286,7 +286,7 @@ static int vdec_h264_init(struct mtk_vcodec_dec_ctx *ctx) } inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi; - err = allocate_predication_buf(inst); + err = allocate_prediction_buf(inst); if (err) goto error_deinit; @@ -308,7 +308,7 @@ static void vdec_h264_deinit(void *h_vdec) struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; vpu_dec_deinit(&inst->vpu); - free_predication_buf(inst); + free_prediction_buf(inst); free_mv_buf(inst); kfree(inst); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h index ac82be336055..31ffa13160a3 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h @@ -175,7 +175,7 @@ void mtk_vdec_h264_get_ref_list(u8 *ref_list, int num_valid); /** - * mtk_vdec_h264_get_ctrl_ptr - get each CID contrl address. + * mtk_vdec_h264_get_ctrl_ptr - get each CID control address. * * @ctx: v4l2 ctx * @id: CID control ID @@ -185,7 +185,7 @@ void mtk_vdec_h264_get_ref_list(u8 *ref_list, void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_dec_ctx *ctx, int id); /** - * mtk_vdec_h264_fill_dpb_info - get each CID contrl address. + * mtk_vdec_h264_fill_dpb_info - Fill the decoded picture buffer info * * @ctx: v4l2 ctx * @decode_params: slice decode params @@ -225,10 +225,13 @@ void mtk_vdec_h264_copy_slice_hd_params(struct mtk_h264_slice_hd_param *dst_para const struct v4l2_ctrl_h264_decode_params *dec_param); /** - * mtk_vdec_h264_copy_scaling_matrix - get each CID contrl address. + * mtk_vdec_h264_copy_scaling_matrix - Copy scaling matrix from a control to the driver * - * @dst_matrix: scaling list params for hw decoder - * @src_matrix: scaling list params from user driver + * @dst_matrix: scaling list params for the HW decoder + * @src_matrix: scaling list params from a V4L2 control + * + * This function is used to copy the scaling matrix from a + * v4l2 control into the slice parameters for a decode. */ void mtk_vdec_h264_copy_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, const struct v4l2_ctrl_h264_scaling_matrix *src_matrix); @@ -246,7 +249,7 @@ mtk_vdec_h264_copy_decode_params(struct slice_api_h264_decode_param *dst_params, const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); /** - * mtk_vdec_h264_update_dpb - updata dpb list. + * mtk_vdec_h264_update_dpb - update dpb list. * * @dec_param: v4l2 control decode params * @dpb: dpb entry informaton diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c index 5600f1df653d..73d5cef33b2a 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c @@ -27,7 +27,7 @@ struct mtk_h264_dec_slice_param { /** * struct vdec_h264_dec_info - decode information * @dpb_sz : decoding picture buffer size - * @resolution_changed : resoltion change happen + * @resolution_changed : flag to notify that a resolution change happened * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer * @cap_num_planes : number planes of capture buffer * @bs_dma : Input bit-stream buffer dma address @@ -54,7 +54,7 @@ struct vdec_h264_dec_info { * by VPU. * AP-W/R : AP is writer/reader on this item * VPU-W/R: VPU is write/reader on this item - * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R) + * @pred_buf_dma : HW working prediction buffer dma address (AP-W, VPU-R) * @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R) * @dec : decode information (AP-R, VPU-W) * @pic : picture information (AP-R, VPU-W) @@ -74,7 +74,7 @@ struct vdec_h264_vsi { * struct vdec_h264_slice_inst - h264 decoder instance * @num_nalu : how many nalus be decoded * @ctx : point to mtk_vcodec_dec_ctx - * @pred_buf : HW working predication buffer + * @pred_buf : HW working prediction buffer * @mv_buf : HW working motion vector buffer * @vpu : VPU instance * @vsi_ctx : Local VSI data for this decoding context @@ -154,7 +154,7 @@ static int get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) return 0; } -static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) +static int allocate_prediction_buf(struct vdec_h264_slice_inst *inst) { int err; @@ -169,7 +169,7 @@ static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) return 0; } -static void free_predication_buf(struct vdec_h264_slice_inst *inst) +static void free_prediction_buf(struct vdec_h264_slice_inst *inst) { struct mtk_vcodec_mem *mem = &inst->pred_buf; @@ -292,7 +292,7 @@ static int vdec_h264_slice_init(struct mtk_vcodec_dec_ctx *ctx) inst->vsi_ctx.dec.resolution_changed = true; inst->vsi_ctx.dec.realloc_mv_buf = true; - err = allocate_predication_buf(inst); + err = allocate_prediction_buf(inst); if (err) goto error_deinit; @@ -320,7 +320,7 @@ static void vdec_h264_slice_deinit(void *h_vdec) struct vdec_h264_slice_inst *inst = h_vdec; vpu_dec_deinit(&inst->vpu); - free_predication_buf(inst); + free_prediction_buf(inst); free_mv_buf(inst); kfree(inst); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c index 0e741e0dc8ba..2d4611e7fa0b 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c @@ -51,7 +51,7 @@ struct vdec_h264_slice_lat_dec_param { * struct vdec_h264_slice_info - decode information * * @nal_info: nal info of current picture - * @timeout: Decode timeout: 1 timeout, 0 no timeount + * @timeout: Decode timeout: 1 timeout, 0 no timeout * @bs_buf_size: bitstream size * @bs_buf_addr: bitstream buffer dma address * @y_fb_dma: Y frame buffer dma address @@ -131,9 +131,9 @@ struct vdec_h264_slice_share_info { /** * struct vdec_h264_slice_inst - h264 decoder instance * - * @slice_dec_num: how many picture be decoded + * @slice_dec_num: Number of frames to be decoded * @ctx: point to mtk_vcodec_dec_ctx - * @pred_buf: HW working predication buffer + * @pred_buf: HW working prediction buffer * @mv_buf: HW working motion vector buffer * @vpu: VPU instance * @vsi: vsi used for lat diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c index 06ed47df693b..fe0a8508d632 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c @@ -254,7 +254,7 @@ struct vdec_hevc_slice_lat_dec_param { * struct vdec_hevc_slice_info - decode information * * @wdma_end_addr_offset: wdma end address offset - * @timeout: Decode timeout: 1 timeout, 0 no timeount + * @timeout: Decode timeout: 1 timeout, 0 no timeout * @vdec_fb_va: VDEC frame buffer struct virtual address * @crc: Used to check whether hardware's status is right */ @@ -342,7 +342,7 @@ struct vdec_hevc_slice_share_info { /** * struct vdec_hevc_slice_inst - hevc decoder instance * - * @slice_dec_num: how many picture be decoded + * @slice_dec_num: Number of frames to be decoded * @ctx: point to mtk_vcodec_dec_ctx * @mv_buf: HW working motion vector buffer * @vpu: VPU instance diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c index 19407f9bc773..9649f4ec1f2a 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c @@ -56,7 +56,7 @@ * @cur_c_fb_dma : current plane C frame buffer dma address * @bs_dma : bitstream dma address * @bs_sz : bitstream size - * @resolution_changed: resolution change flag 1 - changed, 0 - not change + * @resolution_changed: resolution change flag 1 - changed, 0 - not changed * @show_frame : display this frame or not * @wait_key_frame : wait key frame coming */ @@ -109,7 +109,7 @@ struct vdec_vp8_hw_reg_base { /** * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode * @wq_hd : Wait queue to wait VPU message ack - * @signaled : 1 - Host has received ack message from VPU, 0 - not receive + * @signaled : 1 - Host has received ack message from VPU, 0 - not received * @failure : VPU execution result status 0 - success, others - fail * @inst_addr : VPU decoder instance address */ diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c index f677e499fefa..e27e728f392e 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c @@ -35,7 +35,7 @@ * @cur_c_fb_dma: current plane C frame buffer dma address * @bs_dma: bitstream dma address * @bs_sz: bitstream size - * @resolution_changed:resolution change flag 1 - changed, 0 - not change + * @resolution_changed:resolution change flag 1 - changed, 0 - not changed * @frame_header_type: current frame header type * @crc: used to check whether hardware's status is right * @reserved: reserved, currently unused diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c index 55355fa70090..3cd542242b1d 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c @@ -41,7 +41,7 @@ struct vp9_dram_buf { /** * struct vp9_fb_info - contains frame buffer info - * @fb : frmae buffer + * @fb : frame buffer * @reserved : reserved field used by vpu */ struct vp9_fb_info { @@ -89,7 +89,7 @@ struct vp9_sf_ref_fb { * AP-W/R : AP is writer/reader on this item * VPU-W/R: VPU is write/reader on this item * @sf_bs_buf : super frame backup buffer (AP-W, VPU-R) - * @sf_ref_fb : record supoer frame reference buffer information + * @sf_ref_fb : record super frame reference buffer information * (AP-R/W, VPU-R/W) * @sf_next_ref_fb_idx : next available super frame (AP-W, VPU-R) * @sf_frm_cnt : super frame count, filled by vpu (AP-R, VPU-W) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h b/drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h index 1d9beb9e4a14..b0f576867f4b 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h @@ -158,14 +158,14 @@ int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *ctx, struct vdec_lat_buf *buf struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *ctx); /** - * vdec_msg_queue_update_ube_rptr - used to updata the ube read point. + * vdec_msg_queue_update_ube_rptr - used to update the ube read point. * @msg_queue: used to store the lat buffer information * @ube_rptr: current ube read point */ void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue, uint64_t ube_rptr); /** - * vdec_msg_queue_update_ube_wptr - used to updata the ube write point. + * vdec_msg_queue_update_ube_wptr - used to update the ube write point. * @msg_queue: used to store the lat buffer information * @ube_wptr: current ube write point */ diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h index aa7d08afc2f4..57ed9b1f5eaa 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h @@ -81,7 +81,7 @@ int vpu_dec_deinit(struct vdec_vpu_inst *vpu); /** * vpu_dec_reset - reset decoder, use for flush decoder when end of stream or - * seek. Remainig non displayed frame will be pushed to display. + * seek. Remaining non displayed frame will be pushed to display. * * @vpu: instance for vdec_vpu_inst */ @@ -98,7 +98,7 @@ int vpu_dec_core(struct vdec_vpu_inst *vpu); /** * vpu_dec_core_end - core end decoding, basically the function will be invoked once * when core HW decoding done and receive interrupt successfully. The - * decoder in VPU will updata hardware information and deinit hardware + * decoder in VPU will update hardware information and deinit hardware * and check if there is a new decoded frame available to display. * * @vpu : instance for vdec_vpu_inst diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index 181884e798fd..7eaf0e24c9fc 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -311,7 +311,7 @@ static int vidioc_try_fmt_out(struct mtk_vcodec_enc_ctx *ctx, struct v4l2_format pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VENC_MIN_H, max_height); pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VENC_MIN_W, max_width); - /* find next closer width align 16, heign align 32, size align + /* find next closer width align 16, height align 32, size align * 64 rectangle */ tmp_w = pix_fmt_mp->width; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h index d00fb68b8235..889440a436b6 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h @@ -156,7 +156,7 @@ int venc_if_set_param(struct mtk_vcodec_enc_ctx *ctx, * @ctx: device context * @opt: encode frame option * @frm_buf: input frame buffer information - * @bs_buf: output bitstream buffer infomraiton + * @bs_buf: output bitstream buffer information * @result: encode result * Return: 0 if encoding frame successfully, otherwise it is failed. */ diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index e4cf27b5a072..0df2a1b4974b 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -24,7 +24,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinctrl.h> diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 941fa23c211a..df6f2536263b 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -756,6 +756,7 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 41eeec648803..b29a1a9f381d 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -9,7 +9,6 @@ #include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pm_qos.h> diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 5719dda6e0f0..0b55314a8082 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -845,13 +845,13 @@ static ssize_t imon_clock_show(struct device *d, mutex_lock(&ictx->lock); if (!ictx->display_supported) { - len = snprintf(buf, PAGE_SIZE, "Not supported."); + len = sysfs_emit(buf, "Not supported."); } else { - len = snprintf(buf, PAGE_SIZE, - "To set the clock on your iMON display:\n" - "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" - "%s", ictx->display_isopen ? - "\nNOTE: imon device must be closed\n" : ""); + len = sysfs_emit(buf, + "To set the clock on your iMON display:\n" + "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" + "%s", ictx->display_isopen ? + "\nNOTE: imon device must be closed\n" : ""); } mutex_unlock(&ictx->lock); diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index bbc81bed4f90..8fc8e496e6aa 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -4,13 +4,18 @@ // Copyright (c) 2016 Samsung Electronics Co., Ltd. // Copyright (c) Andi Shyti <[email protected]> -#include <linux/delay.h> -#include <linux/fs.h> +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/math.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of_gpio.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <linux/string.h> +#include <linux/types.h> + #include <media/rc-core.h> #define IR_SPI_DRIVER_NAME "ir-spi" @@ -31,8 +36,7 @@ struct ir_spi_data { struct regulator *regulator; }; -static int ir_spi_tx(struct rc_dev *dev, - unsigned int *buffer, unsigned int count) +static int ir_spi_tx(struct rc_dev *dev, unsigned int *buffer, unsigned int count) { int i; int ret; @@ -52,7 +56,7 @@ static int ir_spi_tx(struct rc_dev *dev, return -EINVAL; /* - * the first value in buffer is a pulse, so that 0, 2, 4, ... + * The first value in buffer is a pulse, so that 0, 2, 4, ... * contain a pulse duration. On the contrary, 1, 3, 5, ... * contain a space duration. */ @@ -111,15 +115,16 @@ static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) static int ir_spi_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; int ret; u8 dc; struct ir_spi_data *idata; - idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL); + idata = devm_kzalloc(dev, sizeof(*idata), GFP_KERNEL); if (!idata) return -ENOMEM; - idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator"); + idata->regulator = devm_regulator_get(dev, "irda_regulator"); if (IS_ERR(idata->regulator)) return PTR_ERR(idata->regulator); @@ -135,32 +140,31 @@ static int ir_spi_probe(struct spi_device *spi) idata->rc->priv = idata; idata->spi = spi; - idata->negated = of_property_read_bool(spi->dev.of_node, - "led-active-low"); - ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc); + idata->negated = device_property_read_bool(dev, "led-active-low"); + ret = device_property_read_u8(dev, "duty-cycle", &dc); if (ret) dc = 50; - /* ir_spi_set_duty_cycle cannot fail, - * it returns int to be compatible with the - * rc->s_tx_duty_cycle function + /* + * ir_spi_set_duty_cycle() cannot fail, it returns int + * to be compatible with the rc->s_tx_duty_cycle function. */ ir_spi_set_duty_cycle(idata->rc, dc); idata->freq = IR_SPI_DEFAULT_FREQUENCY; - return devm_rc_register_device(&spi->dev, idata->rc); + return devm_rc_register_device(dev, idata->rc); } static const struct of_device_id ir_spi_of_match[] = { { .compatible = "ir-spi-led" }, - {}, + {} }; MODULE_DEVICE_TABLE(of, ir_spi_of_match); static const struct spi_device_id ir_spi_ids[] = { { "ir-spi-led" }, - {}, + {} }; MODULE_DEVICE_TABLE(spi, ir_spi_ids); @@ -172,7 +176,6 @@ static struct spi_driver ir_spi_driver = { .of_match_table = ir_spi_of_match, }, }; - module_spi_driver(ir_spi_driver); MODULE_AUTHOR("Andi Shyti <[email protected]>"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index caad59f76793..52aea4167718 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -27,7 +27,9 @@ static dev_t lirc_base_dev; static DEFINE_IDA(lirc_ida); /* Only used for sysfs but defined to void otherwise */ -static struct class *lirc_class; +static const struct class lirc_class = { + .name = "lirc", +}; /** * lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace @@ -724,7 +726,7 @@ int lirc_register(struct rc_dev *dev) return minor; device_initialize(&dev->lirc_dev); - dev->lirc_dev.class = lirc_class; + dev->lirc_dev.class = &lirc_class; dev->lirc_dev.parent = &dev->dev; dev->lirc_dev.release = lirc_release_device; dev->lirc_dev.devt = MKDEV(MAJOR(lirc_base_dev), minor); @@ -789,15 +791,13 @@ int __init lirc_dev_init(void) { int retval; - lirc_class = class_create("lirc"); - if (IS_ERR(lirc_class)) { - pr_err("class_create failed\n"); - return PTR_ERR(lirc_class); - } + retval = class_register(&lirc_class); + if (retval) + return retval; retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX, "lirc"); if (retval) { - class_destroy(lirc_class); + class_unregister(&lirc_class); pr_err("alloc_chrdev_region failed\n"); return retval; } @@ -810,7 +810,7 @@ int __init lirc_dev_init(void) void __exit lirc_dev_exit(void) { - class_destroy(lirc_class); + class_unregister(&lirc_class); unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); } diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index e13f5452b927..3e011fe62ae1 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1345,6 +1345,7 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs, .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 2a2d19d23bab..ba7550b8ba7e 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -221,6 +221,7 @@ static const struct v4l2_ioctl_ops vimc_capture_ioctl_ops = { .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_remove_bufs = vb2_ioctl_remove_bufs, }; static void vimc_capture_return_all_buffers(struct vimc_capture_device *vcapture, @@ -432,7 +433,7 @@ static struct vimc_ent_device *vimc_capture_add(struct vimc_device *vimc, q->mem_ops = vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG ? &vb2_dma_contig_memops : &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_queued_buffers = 2; + q->min_reqbufs_allocation = 2; q->lock = &vcapture->lock; q->dev = v4l2_dev->dev; diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index b9a4b44bd0ed..f8d970319764 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -539,6 +539,7 @@ const struct v4l2_ioctl_ops visl_ioctl_ops = { .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs, .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 159c72cbb5bf..0273bc9863b0 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -769,6 +769,7 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_remove_bufs = vb2_ioctl_remove_bufs, .vidioc_enum_input = vivid_enum_input, .vidioc_g_input = vivid_g_input, @@ -861,7 +862,7 @@ static const struct media_device_ops vivid_media_ops = { static int vivid_create_queue(struct vivid_dev *dev, struct vb2_queue *q, u32 buf_type, - unsigned int min_queued_buffers, + unsigned int min_reqbufs_allocation, const struct vb2_ops *ops) { if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar) @@ -898,7 +899,7 @@ static int vivid_create_queue(struct vivid_dev *dev, q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_queued_buffers = supports_requests[dev->inst] ? 0 : min_queued_buffers; + q->min_reqbufs_allocation = min_reqbufs_allocation; q->lock = &dev->mutex; q->dev = dev->v4l2_dev.dev; q->supports_requests = supports_requests[dev->inst]; @@ -1364,7 +1365,7 @@ static int vivid_create_queues(struct vivid_dev *dev) if (dev->has_meta_out) { /* initialize meta_out queue */ ret = vivid_create_queue(dev, &dev->vb_meta_out_q, - V4L2_BUF_TYPE_META_OUTPUT, 1, + V4L2_BUF_TYPE_META_OUTPUT, 2, &vivid_meta_out_qops); if (ret) return ret; @@ -1373,7 +1374,7 @@ static int vivid_create_queues(struct vivid_dev *dev) if (dev->has_touch_cap) { /* initialize touch_cap queue */ ret = vivid_create_queue(dev, &dev->vb_touch_cap_q, - V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, + V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, &vivid_touch_cap_qops); if (ret) return ret; diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 4a569a6e58be..82ab3b26914e 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -18,7 +18,6 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned int q_num_bufs = vb2_get_num_buffers(vq); unsigned int size = sizeof(struct vivid_meta_out_buf); if (!vivid_is_webcam(dev)) @@ -31,9 +30,6 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, sizes[0] = size; } - if (q_num_bufs + *nbuffers < 2) - *nbuffers = 2 - q_num_bufs; - *nplanes = 1; return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c index 4b3c6ea0afde..3888c21b4d0c 100644 --- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c @@ -13,7 +13,6 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned int q_num_bufs = vb2_get_num_buffers(vq); struct v4l2_pix_format *f = &dev->tch_format; unsigned int size = f->sizeimage; @@ -24,9 +23,6 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, sizes[0] = size; } - if (q_num_bufs + *nbuffers < 2) - *nbuffers = 2 - q_num_bufs; - *nplanes = 1; return 0; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index d13954bd31fd..e39e9742fdb5 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -722,6 +722,9 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon); SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); + /* VIDIOC_CREATE_BUFS support is mandatory to enable VIDIOC_REMOVE_BUFS */ + if (ops->vidioc_create_bufs) + SET_VALID_IOCTL(ops, VIDIOC_REMOVE_BUFS, vidioc_remove_bufs); } if (is_vid || is_vbi || is_meta) { diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 6e7b8b682d13..5aeff5519407 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -489,6 +489,14 @@ static void v4l_print_create_buffers(const void *arg, bool write_only) v4l_print_format(&p->format, write_only); } +static void v4l_print_remove_buffers(const void *arg, bool write_only) +{ + const struct v4l2_remove_buffers *p = arg; + + pr_cont("type=%s, index=%u, count=%u\n", + prt_names(p->type, v4l2_type_names), p->index, p->count); +} + static void v4l_print_streamparm(const void *arg, bool write_only) { const struct v4l2_streamparm *p = arg; @@ -2092,6 +2100,7 @@ static int v4l_overlay(const struct v4l2_ioctl_ops *ops, static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_requestbuffers *p = arg; int ret = check_fmt(file, p->type); @@ -2100,6 +2109,10 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, memset_after(p, 0, flags); + p->capabilities = 0; + if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) + p->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; + return ops->vidioc_reqbufs(file, fh, p); } @@ -2133,6 +2146,7 @@ static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_create_buffers *create = arg; int ret = check_fmt(file, create->format.type); @@ -2143,6 +2157,10 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, v4l_sanitize_format(&create->format); + create->capabilities = 0; + if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) + create->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; + ret = ops->vidioc_create_bufs(file, fh, create); if (create->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || @@ -2161,6 +2179,17 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); } +static int v4l_remove_bufs(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_remove_buffers *remove = arg; + + if (ops->vidioc_remove_bufs) + return ops->vidioc_remove_bufs(file, fh, remove); + + return -ENOTTY; +} + static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2910,6 +2939,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), IOCTL_INFO(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)), IOCTL_INFO(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)), + IOCTL_INFO(VIDIOC_REMOVE_BUFS, v4l_remove_bufs, v4l_print_remove_buffers, INFO_FL_PRIO | INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_remove_buffers, type)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 75517134a5e9..eb22d6172462 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -1386,6 +1386,21 @@ int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs); +int v4l2_m2m_ioctl_remove_bufs(struct file *file, void *priv, + struct v4l2_remove_buffers *remove) +{ + struct v4l2_fh *fh = file->private_data; + struct vb2_queue *q = v4l2_m2m_get_vq(fh->m2m_ctx, remove->type); + + if (!q) + return -EINVAL; + if (q->type != remove->type) + return -EINVAL; + + return vb2_core_remove_bufs(q, remove->index, remove->count); +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_remove_bufs); + int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index edb733f21604..bdbb7e542321 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -163,6 +163,8 @@ struct v4l2_fh; * :ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl * @vidioc_prepare_buf: pointer to the function that implements * :ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl + * @vidioc_remove_bufs: pointer to the function that implements + * :ref:`VIDIOC_REMOVE_BUFS <vidioc_remove_bufs>` ioctl * @vidioc_overlay: pointer to the function that implements * :ref:`VIDIOC_OVERLAY <vidioc_overlay>` ioctl * @vidioc_g_fbuf: pointer to the function that implements @@ -422,6 +424,8 @@ struct v4l2_ioctl_ops { struct v4l2_create_buffers *b); int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_remove_bufs)(struct file *file, void *fh, + struct v4l2_remove_buffers *d); int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i); int (*vidioc_g_fbuf)(struct file *file, void *fh, diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 7f1af1f7f912..0af330cf91c3 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -867,6 +867,8 @@ int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb); int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh, struct v4l2_create_buffers *create); +int v4l2_m2m_ioctl_remove_bufs(struct file *file, void *priv, + struct v4l2_remove_buffers *d); int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf); int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh, diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 8b86996b2719..955237ac503d 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -346,8 +346,8 @@ struct vb2_buffer { * describes the requested number of planes and sizes\[\] * contains the requested plane sizes. In this case * \*num_buffers are being allocated additionally to - * q->num_buffers. If either \*num_planes or the requested - * sizes are invalid callback must return %-EINVAL. + * the buffers already allocated. If either \*num_planes + * or the requested sizes are invalid callback must return %-EINVAL. * @wait_prepare: release any locks taken while calling vb2 functions; * it is called before an ioctl needs to wait for a new * buffer to arrive; required to avoid a deadlock in @@ -549,9 +549,21 @@ struct vb2_buf_ops { * @start_streaming can be called. Used when a DMA engine * cannot be started unless at least this number of buffers * have been queued into the driver. - * VIDIOC_REQBUFS will ensure at least @min_queued_buffers + * VIDIOC_REQBUFS will ensure at least @min_queued_buffers + 1 * buffers will be allocated. Note that VIDIOC_CREATE_BUFS will not * modify the requested buffer count. + * @min_reqbufs_allocation: the minimum number of buffers to be allocated when + * calling VIDIOC_REQBUFS. Note that VIDIOC_CREATE_BUFS will *not* + * modify the requested buffer count and does not use this field. + * Drivers can set this if there has to be a certain number of + * buffers available for the hardware to work effectively. + * This allows calling VIDIOC_REQBUFS with a buffer count of 1 and + * it will be automatically adjusted to a workable buffer count. + * If set, then @min_reqbufs_allocation must be larger than + * @min_queued_buffers + 1. + * If this field is > 3, then it is highly recommended that the + * driver implements the V4L2_CID_MIN_BUFFERS_FOR_CAPTURE/OUTPUT + * control. * @alloc_devs: &struct device memory type/allocator-specific per-plane device */ /* @@ -559,8 +571,9 @@ struct vb2_buf_ops { * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped * @memory: current memory type used * @dma_dir: DMA mapping direction. - * @bufs: videobuf2 buffer structures - * @num_buffers: number of allocated/used buffers + * @bufs: videobuf2 buffer structures. If it is non-NULL then + * bufs_bitmap is also non-NULL. + * @bufs_bitmap: bitmap tracking whether each bufs[] entry is used * @max_num_buffers: upper limit of number of allocated/used buffers. * If set to 0 v4l2 core will change it VB2_MAX_FRAME * for backward compatibility. @@ -582,6 +595,7 @@ struct vb2_buf_ops { * released. Used to prevent destroying the queue by other threads. * @is_multiplanar: set if buffer type is multiplanar * @is_output: set if buffer type is output + * @is_busy: set if at least one buffer has been allocated at some time. * @copy_timestamp: set if vb2-core should set timestamps * @last_buffer_dequeued: used in poll() and DQBUF to immediately return if the * last decoded buffer was already dequeued. Set for capture queues @@ -621,6 +635,7 @@ struct vb2_queue { u32 timestamp_flags; gfp_t gfp_flags; u32 min_queued_buffers; + u32 min_reqbufs_allocation; struct device *alloc_devs[VB2_MAX_PLANES]; @@ -629,7 +644,7 @@ struct vb2_queue { unsigned int memory; enum dma_data_direction dma_dir; struct vb2_buffer **bufs; - unsigned int num_buffers; + unsigned long *bufs_bitmap; unsigned int max_num_buffers; struct list_head queued_list; @@ -647,6 +662,7 @@ struct vb2_queue { unsigned int waiting_in_dqbuf:1; unsigned int is_multiplanar:1; unsigned int is_output:1; + unsigned int is_busy:1; unsigned int copy_timestamp:1; unsigned int last_buffer_dequeued:1; @@ -811,6 +827,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * @count: requested buffer count. * @requested_planes: number of planes requested. * @requested_sizes: array with the size of the planes. + * @first_index: index of the first created buffer, all allocated buffers have + * indices in the range [first_index..first_index+count-1] * * Videobuf2 core helper to implement VIDIOC_CREATE_BUFS() operation. It is * called internally by VB2 by an API-specific handler, like @@ -827,7 +845,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int flags, unsigned int *count, unsigned int requested_planes, - const unsigned int requested_sizes[]); + const unsigned int requested_sizes[], + unsigned int *first_index); /** * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace @@ -852,6 +871,16 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb); /** + * vb2_core_remove_bufs() - + * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @start: first index of the range of buffers to remove. + * @count: number of buffers to remove. + * + * Return: returns zero on success; an error code otherwise. + */ +int vb2_core_remove_bufs(struct vb2_queue *q, unsigned int start, unsigned int count); + +/** * vb2_core_qbuf() - Queue a buffer from userspace * * @q: pointer to &struct vb2_queue with videobuf2 queue. @@ -1155,7 +1184,10 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q) */ static inline unsigned int vb2_get_num_buffers(struct vb2_queue *q) { - return q->num_buffers; + if (q->bufs_bitmap) + return bitmap_weight(q->bufs_bitmap, q->max_num_buffers); + + return 0; } /** @@ -1166,7 +1198,7 @@ static inline unsigned int vb2_get_num_buffers(struct vb2_queue *q) */ static inline bool vb2_is_busy(struct vb2_queue *q) { - return vb2_get_num_buffers(q) > 0; + return !!q->is_busy; } /** @@ -1264,7 +1296,7 @@ static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q, if (index >= q->max_num_buffers) return NULL; - if (index < q->num_buffers) + if (test_bit(index, q->bufs_bitmap)) return q->bufs[index]; return NULL; } diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 5a845887850b..77ce8238ab30 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -334,6 +334,8 @@ int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i); int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i); int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p); +int vb2_ioctl_remove_bufs(struct file *file, void *priv, + struct v4l2_remove_buffers *p); /* struct v4l2_file_operations helpers */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index a8015e5e7fa4..2663213b76a4 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1036,6 +1036,7 @@ struct v4l2_requestbuffers { #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6) #define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7) +#define V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS (1 << 8) /** * struct v4l2_plane - plane info for multi-planar buffers @@ -2624,6 +2625,20 @@ struct v4l2_create_buffers { __u32 reserved[5]; }; +/** + * struct v4l2_remove_buffers - VIDIOC_REMOVE_BUFS argument + * @index: the first buffer to be removed + * @count: number of buffers to removed + * @type: enum v4l2_buf_type + * @reserved: future extensions + */ +struct v4l2_remove_buffers { + __u32 index; + __u32 count; + __u32 type; + __u32 reserved[13]; +}; + /* * I O C T L C O D E S F O R V I D E O D E V I C E S * @@ -2723,6 +2738,8 @@ struct v4l2_create_buffers { #define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) +#define VIDIOC_REMOVE_BUFS _IOWR('V', 104, struct v4l2_remove_buffers) + /* Reminder: when adding new ioctls please add support for them to drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */ |