@@ -2631,6 +2631,7 @@ 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_DELETE_BUF _IOWR('V', 104, struct v4l2_buffer)
/* Reminder: when adding new ioctls please add support for them to
drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
@@ -758,6 +758,10 @@ public:
{
return v4l_queue_reqbufs(fd->g_v4l_fd(), this, count, flags);
}
+ int delete_buf(cv4l_fd *fd, unsigned index = 0)
+ {
+ return v4l_queue_delete_buf(fd->g_v4l_fd(), this, index);
+ }
bool has_create_bufs(cv4l_fd *fd) const
{
return v4l_queue_has_create_bufs(fd->g_v4l_fd(), this);
@@ -1388,6 +1388,11 @@ static inline int v4l_buffer_prepare_buf(struct v4l_fd *f, struct v4l_buffer *bu
return v4l_ioctl(f, VIDIOC_PREPARE_BUF, &buf->buf);
}
+static inline int v4l_buffer_delete_buf(struct v4l_fd *f, struct v4l_buffer *buf)
+{
+ return v4l_ioctl(f, VIDIOC_DELETE_BUF, &buf->buf);
+}
+
static inline int v4l_buffer_qbuf(struct v4l_fd *f, struct v4l_buffer *buf)
{
return v4l_ioctl(f, VIDIOC_QBUF, &buf->buf);
@@ -1490,6 +1495,14 @@ static inline void *v4l_queue_g_dataptr(const struct v4l_queue *q, unsigned inde
return v4l_queue_g_mmapping(q, index, plane);
}
+static inline int v4l_queue_delete_buf(struct v4l_fd *f, struct v4l_queue *q, unsigned index)
+{
+ struct v4l_buffer buf;
+
+ v4l_buffer_init(&buf, v4l_queue_g_type(q), v4l_queue_g_memory(q), index);
+ return v4l_ioctl(f, VIDIOC_DELETE_BUF, &buf.buf);
+}
+
static inline int v4l_queue_querybufs(struct v4l_fd *f, struct v4l_queue *q, unsigned from)
{
unsigned b, p;
@@ -1357,6 +1357,7 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
printf("Buffer ioctls%s:\n", suffix);
printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
+ printf("\ttest VIDIOC_DELETE_BUF: %s\n", ok(testDeleteBuf(&node)));
// Reopen after each streaming test to reset the streaming state
// in case of any errors in the preceeding test.
node.reopen();
@@ -377,6 +377,7 @@ int testReqBufs(struct node *node);
int testReadWrite(struct node *node);
int testExpBuf(struct node *node);
int testBlockingWait(struct node *node);
+int testDeleteBuf(struct node *node);
// 32-bit architecture, 32/64-bit time_t tests
int testTime32_64(struct node *node);
@@ -529,6 +529,135 @@ static int testCanSetSameTimings(struct node *node)
return 0;
}
+int testDeleteBuf(struct node *node)
+{
+ bool can_stream = node->g_caps() & V4L2_CAP_STREAMING;
+ bool mmap_valid;
+ bool userptr_valid;
+ bool dmabuf_valid;
+ int ret;
+ unsigned i;
+
+ node->reopen();
+
+ cv4l_queue q(0, 0);
+
+ ret = q.reqbufs(node, 0);
+ if (ret == ENOTTY) {
+ warn("request buf not supported ret %d\n", ret);
+ fail_on_test(can_stream);
+ return ret;
+ }
+
+ ret = q.delete_buf(node, 0);
+ if (ret == ENOTTY) {
+ warn("VIDIOC_DELETE_BUF not supported ret %d\n", ret);
+ return ret;
+ }
+
+ for (i = 1; i <= V4L2_BUF_TYPE_LAST; i++) {
+ if (!(node->valid_buftypes & (1 << i)))
+ continue;
+
+ if (testSetupVbi(node, i))
+ continue;
+
+ info("test buftype %s\n", buftype2s(i).c_str());
+ if (node->valid_buftype == 0)
+ node->valid_buftype = i;
+
+ q.init(0, 0);
+ fail_on_test(q.reqbufs(node, i) != EINVAL);
+ q.init(i, V4L2_MEMORY_MMAP);
+ ret = q.reqbufs(node, 0);
+ fail_on_test_val(ret && ret != EINVAL, ret);
+ mmap_valid = !ret;
+
+ q.init(i, V4L2_MEMORY_USERPTR);
+ ret = q.reqbufs(node, 0);
+ fail_on_test_val(ret && ret != EINVAL, ret);
+ userptr_valid = !ret;
+ fail_on_test(!mmap_valid && userptr_valid);
+
+ q.init(i, V4L2_MEMORY_DMABUF);
+ ret = q.reqbufs(node, 0);
+ fail_on_test_val(ret && ret != EINVAL, ret);
+ dmabuf_valid = !ret;
+ fail_on_test(!mmap_valid && dmabuf_valid);
+
+ if (mmap_valid) {
+ q.init(i, V4L2_MEMORY_MMAP);
+ fail_on_test(q.reqbufs(node, 1));
+ fail_on_test(q.g_buffers() == 0);
+ fail_on_test(q.delete_buf(node, 1) != EINVAL);
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 3));
+ fail_on_test(q.delete_buf(node, 2));
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 1));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 2));
+ for (unsigned j = 0; j < q.g_buffers(); j++) {
+ buffer buf(q);
+
+ fail_on_test(buf.querybuf(node, j));
+ ret = buf.qbuf(node);
+ if (!ret)
+ fail_on_test(q.delete_buf(node, j) != EINVAL);
+ }
+ }
+
+ if (userptr_valid) {
+ q.init(i, V4L2_MEMORY_USERPTR);
+ fail_on_test(q.reqbufs(node, 1));
+ fail_on_test(q.g_buffers() == 0);
+ fail_on_test(q.delete_buf(node, 1) != EINVAL);
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 3));
+ fail_on_test(q.delete_buf(node, 2));
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 1));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 2));
+ for (unsigned j = 0; j < q.g_buffers(); j++) {
+ buffer buf(q);
+
+ fail_on_test(buf.querybuf(node, j));
+ ret = buf.qbuf(node);
+ if (!ret)
+ fail_on_test(q.delete_buf(node, j) != EINVAL);
+ }
+ }
+
+ if (dmabuf_valid) {
+ q.init(i, V4L2_MEMORY_DMABUF);
+ fail_on_test(q.reqbufs(node, 1));
+ fail_on_test(q.g_buffers() == 0);
+ fail_on_test(q.delete_buf(node, 1) != EINVAL);
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 3));
+ fail_on_test(q.delete_buf(node, 2));
+ fail_on_test(q.delete_buf(node, 0));
+ fail_on_test(q.delete_buf(node, 1));
+ fail_on_test(q.delete_buf(node, 0) != EINVAL);
+ fail_on_test(q.reqbufs(node, 2));
+ for (unsigned j = 0; j < q.g_buffers(); j++) {
+ buffer buf(q);
+
+ fail_on_test(buf.querybuf(node, j));
+ ret = buf.qbuf(node);
+ if (!ret)
+ fail_on_test(q.delete_buf(node, j) != EINVAL);
+ }
+ }
+ }
+
+ return 0;
+}
+
int testReqBufs(struct node *node)
{
struct v4l2_create_buffers crbufs = { };
Add new test for DELETE_BUF ioctl. It create a buffer and check if it could be remove from queue. It also check that removing non existing buffer or a queued buffer failed. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com> --- include/linux/videodev2.h | 1 + utils/common/cv4l-helpers.h | 4 + utils/common/v4l-helpers.h | 13 ++ utils/v4l2-compliance/v4l2-compliance.cpp | 1 + utils/v4l2-compliance/v4l2-compliance.h | 1 + utils/v4l2-compliance/v4l2-test-buffers.cpp | 129 ++++++++++++++++++++ 6 files changed, 149 insertions(+)