Message ID | 20240221155435.100093-8-benjamin.gaignard@collabora.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add REMOVE_BUF ioctl | expand |
Hi Benjamin, While reviewing the v4l2-compliance code I realized that the type handling needs to be improved. See my comments below: On 21/02/2024 4:54 pm, Benjamin Gaignard wrote: > 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> > --- > version 20: > - Rename DELETE_BUFS into REMOVE_BUFS > - Change documention, structure and variables name to use 'remove' > > .../userspace-api/media/v4l/user-func.rst | 1 + > .../media/v4l/vidioc-remove-bufs.rst | 82 +++++++++++++++++++ > .../media/v4l/vidioc-reqbufs.rst | 1 + > .../media/common/videobuf2/videobuf2-core.c | 38 +++++++++ > .../media/common/videobuf2/videobuf2-v4l2.c | 14 +++- > drivers/media/v4l2-core/v4l2-dev.c | 3 + > drivers/media/v4l2-core/v4l2-ioctl.c | 32 ++++++++ > include/media/v4l2-ioctl.h | 4 + > include/media/videobuf2-core.h | 10 +++ > include/media/videobuf2-v4l2.h | 2 + > include/uapi/linux/videodev2.h | 17 ++++ > 11 files changed, 203 insertions(+), 1 deletion(-) > create mode 100644 Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst > > 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..0fbc0dfbbaa1 > --- /dev/null > +++ b/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst > @@ -0,0 +1,82 @@ > +.. 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. Just add: "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. > + If count is set to 0 :ref:`VIDIOC_REMOVE_BUFS` will do nothing and return 0. I compared this to CREATE_BUFS and there the documentation clearly states that it will return an error if count == 0 and the type is incorrect. So we should do the same: the type field is checked regardless of the count value. > + * - __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. > + > +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. This does not mention that it is also returned if type is invalid. > 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 009cea95d662..0b2b48e1b2df 100644 > --- a/drivers/media/common/videobuf2/videobuf2-core.c > +++ b/drivers/media/common/videobuf2/videobuf2-core.c > @@ -1691,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 > diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c > index 03e8080a68a8..9a5dcbb8fef3 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) > @@ -1001,6 +1001,18 @@ 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); > + First check if the type matches vdev->queue->type and return -EINVAL if it isn't. Next, if count == 0, then just return 0. Otherwise it might return -EBUSY in the check below. > + 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/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 33076af4dfdb..a5a4134218e6 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,9 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, > > memset_after(p, 0, flags); > > + 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 +2145,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 +2156,9 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, > > v4l_sanitize_format(&create->format); > > + 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 +2177,21 @@ 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; > + int ret = check_fmt(file, remove->type); This check should be dropped, it is unnecessary since vb2_ioctl_remove_bufs will verify this. It's not sufficient either since check_fmt allows type V4L2_BUF_TYPE_VIDEO_CAPTURE to be specified if vidioc_g_fmt_vid_cap_mplane is present, so it is not as precise as checking for 'type == q->type'. For create_bufs that is done later on, so the call to check_fmt there is fairly pointless anyway. A good test here is to do: modprobe vivid multiplanar=2 This enables multiplanar mode for the video capture and output. If you pass in V4L2_BUF_TYPE_VIDEO_CAPTURE to remove_bufs, then it passes with the check_fmt call, but q->type will actually be V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, so that should have returned -EINVAL. > + > + if (ret) > + return ret; > + > + 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 +2941,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/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/videobuf2-core.h b/include/media/videobuf2-core.h > index 7aebeaf671d8..a4e59280747e 100644 > --- a/include/media/videobuf2-core.h > +++ b/include/media/videobuf2-core.h > @@ -867,6 +867,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 > * > 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! */ Regards, Hans
On 21/02/2024 4:54 pm, Benjamin Gaignard wrote: > 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> > --- > version 20: > - Rename DELETE_BUFS into REMOVE_BUFS > - Change documention, structure and variables name to use 'remove' > > .../userspace-api/media/v4l/user-func.rst | 1 + > .../media/v4l/vidioc-remove-bufs.rst | 82 +++++++++++++++++++ > .../media/v4l/vidioc-reqbufs.rst | 1 + > .../media/common/videobuf2/videobuf2-core.c | 38 +++++++++ > .../media/common/videobuf2/videobuf2-v4l2.c | 14 +++- > drivers/media/v4l2-core/v4l2-dev.c | 3 + > drivers/media/v4l2-core/v4l2-ioctl.c | 32 ++++++++ > include/media/v4l2-ioctl.h | 4 + > include/media/videobuf2-core.h | 10 +++ > include/media/videobuf2-v4l2.h | 2 + > include/uapi/linux/videodev2.h | 17 ++++ > 11 files changed, 203 insertions(+), 1 deletion(-) > create mode 100644 Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst > > 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..0fbc0dfbbaa1 > --- /dev/null > +++ b/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst > @@ -0,0 +1,82 @@ > +.. 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. > + * - __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. > + 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. > + > +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. > 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 009cea95d662..0b2b48e1b2df 100644 > --- a/drivers/media/common/videobuf2/videobuf2-core.c > +++ b/drivers/media/common/videobuf2/videobuf2-core.c > @@ -1691,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 > diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c > index 03e8080a68a8..9a5dcbb8fef3 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) > @@ -1001,6 +1001,18 @@ 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 (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/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 33076af4dfdb..a5a4134218e6 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,9 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, > > memset_after(p, 0, flags); You need to add 'p->capabilities = 0;' here. > > + 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 +2145,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 +2156,9 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, > > v4l_sanitize_format(&create->format); > Ditto. In both cases p->capabilities is uninitialized if VIDIOC_REMOVE_BUFS is not supported. And since vb2_set_flags_and_caps just ORs the capabilities you end up with garbage. Regards, Hans > + 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 +2177,21 @@ 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; > + int ret = check_fmt(file, remove->type); > + > + if (ret) > + return ret; > + > + 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 +2941,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/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/videobuf2-core.h b/include/media/videobuf2-core.h > index 7aebeaf671d8..a4e59280747e 100644 > --- a/include/media/videobuf2-core.h > +++ b/include/media/videobuf2-core.h > @@ -867,6 +867,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 > * > 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! */
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..0fbc0dfbbaa1 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst @@ -0,0 +1,82 @@ +.. 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. + * - __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. + 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. + +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. 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 009cea95d662..0b2b48e1b2df 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1691,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 diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 03e8080a68a8..9a5dcbb8fef3 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) @@ -1001,6 +1001,18 @@ 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 (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/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 33076af4dfdb..a5a4134218e6 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,9 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, memset_after(p, 0, flags); + 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 +2145,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 +2156,9 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, v4l_sanitize_format(&create->format); + 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 +2177,21 @@ 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; + int ret = check_fmt(file, remove->type); + + if (ret) + return ret; + + 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 +2941,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/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/videobuf2-core.h b/include/media/videobuf2-core.h index 7aebeaf671d8..a4e59280747e 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -867,6 +867,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 * 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! */
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> --- version 20: - Rename DELETE_BUFS into REMOVE_BUFS - Change documention, structure and variables name to use 'remove' .../userspace-api/media/v4l/user-func.rst | 1 + .../media/v4l/vidioc-remove-bufs.rst | 82 +++++++++++++++++++ .../media/v4l/vidioc-reqbufs.rst | 1 + .../media/common/videobuf2/videobuf2-core.c | 38 +++++++++ .../media/common/videobuf2/videobuf2-v4l2.c | 14 +++- drivers/media/v4l2-core/v4l2-dev.c | 3 + drivers/media/v4l2-core/v4l2-ioctl.c | 32 ++++++++ include/media/v4l2-ioctl.h | 4 + include/media/videobuf2-core.h | 10 +++ include/media/videobuf2-v4l2.h | 2 + include/uapi/linux/videodev2.h | 17 ++++ 11 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst