Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: v4l2: Add REMOVE_BUFS ioctl

VIDIOC_REMOVE_BUFS ioctl allows to remove buffers from a queue.
The number of buffers to remove in given by count field of
struct v4l2_remove_buffers and the range start at the index
specified in the same structure.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil: vidioc-remove-bufs.rst: mention no bufs are freed on error]

authored by

Benjamin Gaignard and committed by
Hans Verkuil
a3293a85 5fb19f20

+211 -1
+1
Documentation/userspace-api/media/v4l/user-func.rst
··· 62 62 vidioc-query-dv-timings 63 63 vidioc-querystd 64 64 vidioc-reqbufs 65 + vidioc-remove-bufs 65 66 vidioc-s-hw-freq-seek 66 67 vidioc-streamon 67 68 vidioc-subdev-enum-frame-interval
+86
Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst
··· 1 + .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later 2 + .. c:namespace:: V4L 3 + 4 + .. _VIDIOC_REMOVE_BUFS: 5 + 6 + ************************ 7 + ioctl VIDIOC_REMOVE_BUFS 8 + ************************ 9 + 10 + Name 11 + ==== 12 + 13 + VIDIOC_REMOVE_BUFS - Removes buffers from a queue 14 + 15 + Synopsis 16 + ======== 17 + 18 + .. c:macro:: VIDIOC_REMOVE_BUFS 19 + 20 + ``int ioctl(int fd, VIDIOC_REMOVE_BUFS, struct v4l2_remove_buffers *argp)`` 21 + 22 + Arguments 23 + ========= 24 + 25 + ``fd`` 26 + File descriptor returned by :c:func:`open()`. 27 + 28 + ``argp`` 29 + Pointer to struct :c:type:`v4l2_remove_buffers`. 30 + 31 + Description 32 + =========== 33 + 34 + Applications can optionally call the :ref:`VIDIOC_REMOVE_BUFS` ioctl to 35 + remove buffers from a queue. 36 + :ref:`VIDIOC_CREATE_BUFS` ioctl support is mandatory to enable :ref:`VIDIOC_REMOVE_BUFS`. 37 + This ioctl is available if the ``V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS`` capability 38 + is set on the queue when :c:func:`VIDIOC_REQBUFS` or :c:func:`VIDIOC_CREATE_BUFS` 39 + are invoked. 40 + 41 + .. c:type:: v4l2_remove_buffers 42 + 43 + .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}| 44 + 45 + .. flat-table:: struct v4l2_remove_buffers 46 + :header-rows: 0 47 + :stub-columns: 0 48 + :widths: 1 1 2 49 + 50 + * - __u32 51 + - ``index`` 52 + - The starting buffer index to remove. This field is ignored if count == 0. 53 + * - __u32 54 + - ``count`` 55 + - The number of buffers to be removed with indices 'index' until 'index + count - 1'. 56 + All buffers in this range must be valid and in DEQUEUED state. 57 + :ref:`VIDIOC_REMOVE_BUFS` will always check the validity of ``type`, if it is 58 + invalid it returns ``EINVAL`` error code. 59 + If count is set to 0 :ref:`VIDIOC_REMOVE_BUFS` will do nothing and return 0. 60 + * - __u32 61 + - ``type`` 62 + - Type of the stream or buffers, this is the same as the struct 63 + :c:type:`v4l2_format` ``type`` field. See 64 + :c:type:`v4l2_buf_type` for valid values. 65 + * - __u32 66 + - ``reserved``\ [13] 67 + - A place holder for future extensions. Drivers and applications 68 + must set the array to zero. 69 + 70 + Return Value 71 + ============ 72 + 73 + On success 0 is returned, on error -1 and the ``errno`` variable is set 74 + appropriately. The generic error codes are described at the 75 + :ref:`Generic Error Codes <gen-errors>` chapter. If an error occurs, no 76 + buffers will be freed and one of the error codes below will be returned: 77 + 78 + EBUSY 79 + File I/O is in progress. 80 + One or more of the buffers in the range ``index`` to ``index + count - 1`` are not 81 + in DEQUEUED state. 82 + 83 + EINVAL 84 + One or more of the buffers in the range ``index`` to ``index + count - 1`` do not 85 + exist in the queue. 86 + The buffer type (``type`` field) is not valid.
+1
Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst
··· 121 121 .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: 122 122 .. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS: 123 123 .. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS: 124 + .. _V4L2-BUF-CAP-SUPPORTS-REMOVE-BUFS: 124 125 125 126 .. raw:: latex 126 127
+38
drivers/media/common/videobuf2/videobuf2-core.c
··· 1691 1691 } 1692 1692 EXPORT_SYMBOL_GPL(vb2_core_prepare_buf); 1693 1693 1694 + int vb2_core_remove_bufs(struct vb2_queue *q, unsigned int start, unsigned int count) 1695 + { 1696 + unsigned int i, ret = 0; 1697 + unsigned int q_num_bufs = vb2_get_num_buffers(q); 1698 + 1699 + if (count == 0) 1700 + return 0; 1701 + 1702 + if (count > q_num_bufs) 1703 + return -EINVAL; 1704 + 1705 + if (start > q->max_num_buffers - count) 1706 + return -EINVAL; 1707 + 1708 + mutex_lock(&q->mmap_lock); 1709 + 1710 + /* Check that all buffers in the range exist */ 1711 + for (i = start; i < start + count; i++) { 1712 + struct vb2_buffer *vb = vb2_get_buffer(q, i); 1713 + 1714 + if (!vb) { 1715 + ret = -EINVAL; 1716 + goto unlock; 1717 + } 1718 + if (vb->state != VB2_BUF_STATE_DEQUEUED) { 1719 + ret = -EBUSY; 1720 + goto unlock; 1721 + } 1722 + } 1723 + __vb2_queue_free(q, start, count); 1724 + dprintk(q, 2, "%u buffers removed\n", count); 1725 + 1726 + unlock: 1727 + mutex_unlock(&q->mmap_lock); 1728 + return ret; 1729 + } 1730 + EXPORT_SYMBOL_GPL(vb2_core_remove_bufs); 1731 + 1694 1732 /* 1695 1733 * vb2_start_streaming() - Attempt to start streaming. 1696 1734 * @q: videobuf2 queue
+19 -1
drivers/media/common/videobuf2/videobuf2-v4l2.c
··· 685 685 *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; 686 686 } 687 687 688 - *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; 688 + *caps |= V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; 689 689 if (q->io_modes & VB2_MMAP) 690 690 *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP; 691 691 if (q->io_modes & VB2_USERPTR) ··· 1000 1000 */ 1001 1001 1002 1002 /* vb2 ioctl helpers */ 1003 + 1004 + int vb2_ioctl_remove_bufs(struct file *file, void *priv, 1005 + struct v4l2_remove_buffers *d) 1006 + { 1007 + struct video_device *vdev = video_devdata(file); 1008 + 1009 + if (vdev->queue->type != d->type) 1010 + return -EINVAL; 1011 + 1012 + if (d->count == 0) 1013 + return 0; 1014 + 1015 + if (vb2_queue_is_busy(vdev->queue, file)) 1016 + return -EBUSY; 1017 + 1018 + return vb2_core_remove_bufs(vdev->queue, d->index, d->count); 1019 + } 1020 + EXPORT_SYMBOL_GPL(vb2_ioctl_remove_bufs); 1003 1021 1004 1022 int vb2_ioctl_reqbufs(struct file *file, void *priv, 1005 1023 struct v4l2_requestbuffers *p)
+3
drivers/media/v4l2-core/v4l2-dev.c
··· 722 722 SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); 723 723 SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon); 724 724 SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); 725 + /* VIDIOC_CREATE_BUFS support is mandatory to enable VIDIOC_REMOVE_BUFS */ 726 + if (ops->vidioc_create_bufs) 727 + SET_VALID_IOCTL(ops, VIDIOC_REMOVE_BUFS, vidioc_remove_bufs); 725 728 } 726 729 727 730 if (is_vid || is_vbi || is_meta) {
+30
drivers/media/v4l2-core/v4l2-ioctl.c
··· 489 489 v4l_print_format(&p->format, write_only); 490 490 } 491 491 492 + static void v4l_print_remove_buffers(const void *arg, bool write_only) 493 + { 494 + const struct v4l2_remove_buffers *p = arg; 495 + 496 + pr_cont("type=%s, index=%u, count=%u\n", 497 + prt_names(p->type, v4l2_type_names), p->index, p->count); 498 + } 499 + 492 500 static void v4l_print_streamparm(const void *arg, bool write_only) 493 501 { 494 502 const struct v4l2_streamparm *p = arg; ··· 2100 2092 static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, 2101 2093 struct file *file, void *fh, void *arg) 2102 2094 { 2095 + struct video_device *vfd = video_devdata(file); 2103 2096 struct v4l2_requestbuffers *p = arg; 2104 2097 int ret = check_fmt(file, p->type); 2105 2098 ··· 2108 2099 return ret; 2109 2100 2110 2101 memset_after(p, 0, flags); 2102 + 2103 + p->capabilities = 0; 2104 + if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) 2105 + p->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; 2111 2106 2112 2107 return ops->vidioc_reqbufs(file, fh, p); 2113 2108 } ··· 2146 2133 static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, 2147 2134 struct file *file, void *fh, void *arg) 2148 2135 { 2136 + struct video_device *vfd = video_devdata(file); 2149 2137 struct v4l2_create_buffers *create = arg; 2150 2138 int ret = check_fmt(file, create->format.type); 2151 2139 ··· 2156 2142 memset_after(create, 0, flags); 2157 2143 2158 2144 v4l_sanitize_format(&create->format); 2145 + 2146 + create->capabilities = 0; 2147 + if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) 2148 + create->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; 2159 2149 2160 2150 ret = ops->vidioc_create_bufs(file, fh, create); 2161 2151 ··· 2177 2159 int ret = check_fmt(file, b->type); 2178 2160 2179 2161 return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); 2162 + } 2163 + 2164 + static int v4l_remove_bufs(const struct v4l2_ioctl_ops *ops, 2165 + struct file *file, void *fh, void *arg) 2166 + { 2167 + struct v4l2_remove_buffers *remove = arg; 2168 + 2169 + if (ops->vidioc_remove_bufs) 2170 + return ops->vidioc_remove_bufs(file, fh, remove); 2171 + 2172 + return -ENOTTY; 2180 2173 } 2181 2174 2182 2175 static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, ··· 2939 2910 IOCTL_INFO(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), 2940 2911 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)), 2941 2912 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)), 2913 + 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)), 2942 2914 }; 2943 2915 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) 2944 2916
+4
include/media/v4l2-ioctl.h
··· 163 163 * :ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl 164 164 * @vidioc_prepare_buf: pointer to the function that implements 165 165 * :ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl 166 + * @vidioc_remove_bufs: pointer to the function that implements 167 + * :ref:`VIDIOC_REMOVE_BUFS <vidioc_remove_bufs>` ioctl 166 168 * @vidioc_overlay: pointer to the function that implements 167 169 * :ref:`VIDIOC_OVERLAY <vidioc_overlay>` ioctl 168 170 * @vidioc_g_fbuf: pointer to the function that implements ··· 424 422 struct v4l2_create_buffers *b); 425 423 int (*vidioc_prepare_buf)(struct file *file, void *fh, 426 424 struct v4l2_buffer *b); 425 + int (*vidioc_remove_bufs)(struct file *file, void *fh, 426 + struct v4l2_remove_buffers *d); 427 427 428 428 int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i); 429 429 int (*vidioc_g_fbuf)(struct file *file, void *fh,
+10
include/media/videobuf2-core.h
··· 871 871 int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb); 872 872 873 873 /** 874 + * vb2_core_remove_bufs() - 875 + * @q: pointer to &struct vb2_queue with videobuf2 queue. 876 + * @start: first index of the range of buffers to remove. 877 + * @count: number of buffers to remove. 878 + * 879 + * Return: returns zero on success; an error code otherwise. 880 + */ 881 + int vb2_core_remove_bufs(struct vb2_queue *q, unsigned int start, unsigned int count); 882 + 883 + /** 874 884 * vb2_core_qbuf() - Queue a buffer from userspace 875 885 * 876 886 * @q: pointer to &struct vb2_queue with videobuf2 queue.
+2
include/media/videobuf2-v4l2.h
··· 334 334 int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i); 335 335 int vb2_ioctl_expbuf(struct file *file, void *priv, 336 336 struct v4l2_exportbuffer *p); 337 + int vb2_ioctl_remove_bufs(struct file *file, void *priv, 338 + struct v4l2_remove_buffers *p); 337 339 338 340 /* struct v4l2_file_operations helpers */ 339 341
+17
include/uapi/linux/videodev2.h
··· 1036 1036 #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) 1037 1037 #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6) 1038 1038 #define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7) 1039 + #define V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS (1 << 8) 1039 1040 1040 1041 /** 1041 1042 * struct v4l2_plane - plane info for multi-planar buffers ··· 2625 2624 __u32 reserved[5]; 2626 2625 }; 2627 2626 2627 + /** 2628 + * struct v4l2_remove_buffers - VIDIOC_REMOVE_BUFS argument 2629 + * @index: the first buffer to be removed 2630 + * @count: number of buffers to removed 2631 + * @type: enum v4l2_buf_type 2632 + * @reserved: future extensions 2633 + */ 2634 + struct v4l2_remove_buffers { 2635 + __u32 index; 2636 + __u32 count; 2637 + __u32 type; 2638 + __u32 reserved[13]; 2639 + }; 2640 + 2628 2641 /* 2629 2642 * 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 2630 2643 * ··· 2738 2723 #define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) 2739 2724 2740 2725 #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) 2726 + #define VIDIOC_REMOVE_BUFS _IOWR('V', 104, struct v4l2_remove_buffers) 2727 + 2741 2728 2742 2729 /* Reminder: when adding new ioctls please add support for them to 2743 2730 drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */