This is an automatic generated email to let you know that the following patch 
were queued at the 
http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:

Subject: v4l2-compliance: Add a test for REMOVE_BUFS ioctl
Author:  Benjamin Gaignard <benjamin.gaign...@collabora.com>
Date:    Thu Mar 14 16:34:15 2024 +0100

Add new test for REMOVE_BUFS ioctl.
It create buffers and check if they could be removed from queue.
It also check that removing non existing buffer or a queued
buffer failed.
Since using REMOVE_BUFS can create "holes" v4l_queue_querybufs()
function needs to be modify to do a range check between [from..from+count-1].

Signed-off-by: Benjamin Gaignard <benjamin.gaign...@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>

 utils/common/cv4l-helpers.h                 |   4 +
 utils/common/v4l-helpers.h                  |  27 +++++--
 utils/v4l2-compliance/v4l2-compliance.cpp   |   1 +
 utils/v4l2-compliance/v4l2-compliance.h     |   1 +
 utils/v4l2-compliance/v4l2-test-buffers.cpp | 118 ++++++++++++++++++++++++++++
 5 files changed, 146 insertions(+), 5 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=a04dfa5b72df01c6dbdf68fd9365e2d913fe5a0f
diff --git a/utils/common/cv4l-helpers.h b/utils/common/cv4l-helpers.h
index 7299d2fae12b..ec33da78b741 100644
--- a/utils/common/cv4l-helpers.h
+++ b/utils/common/cv4l-helpers.h
@@ -765,6 +765,10 @@ public:
        {
                return v4l_queue_reqbufs(fd->g_v4l_fd(), this, count, flags);
        }
+       int remove_bufs(cv4l_fd *fd, unsigned index = 0, unsigned count = 0)
+       {
+               return v4l_queue_remove_bufs(fd->g_v4l_fd(), this, index, 
count);
+       }
        bool has_create_bufs(cv4l_fd *fd) const
        {
                return v4l_queue_has_create_bufs(fd->g_v4l_fd(), this);
diff --git a/utils/common/v4l-helpers.h b/utils/common/v4l-helpers.h
index 5ce3dabc067b..437a68444067 100644
--- a/utils/common/v4l-helpers.h
+++ b/utils/common/v4l-helpers.h
@@ -1547,12 +1547,29 @@ 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_querybufs(struct v4l_fd *f, struct v4l_queue *q, 
unsigned from)
+static inline int v4l_queue_remove_bufs(struct v4l_fd *f, struct v4l_queue *q, 
unsigned index, unsigned count)
 {
-       unsigned b, p;
+       struct v4l2_remove_buffers removebufs;
        int ret;
 
-       for (b = from; b < v4l_queue_g_buffers(q); b++) {
+       memset(&removebufs, 0, sizeof(removebufs));
+       removebufs.type = q->type;
+       removebufs.index = index;
+       removebufs.count = count;
+
+       ret = v4l_ioctl(f, VIDIOC_REMOVE_BUFS, &removebufs);
+       if (!ret)
+               q->buffers -= removebufs.count;
+
+       return ret;
+}
+
+static inline int v4l_queue_querybufs(struct v4l_fd *f, struct v4l_queue *q, 
unsigned from, unsigned count)
+{
+       unsigned b, p, max = from + count;
+       int ret;
+
+       for (b = from; b < max; b++) {
                struct v4l_buffer buf;
 
                v4l_buffer_init(&buf, v4l_queue_g_type(q), 
v4l_queue_g_memory(q), b);
@@ -1605,7 +1622,7 @@ static inline int v4l_queue_reqbufs(struct v4l_fd *f,
                        }
                }
        }
-       return v4l_queue_querybufs(f, q, 0);
+       return v4l_queue_querybufs(f, q, 0, reqbufs.count);
 }
 
 static inline bool v4l_queue_has_create_bufs(struct v4l_fd *f, const struct 
v4l_queue *q)
@@ -1649,7 +1666,7 @@ static inline int v4l_queue_create_bufs(struct v4l_fd *f,
                }
        }
        q->buffers += createbufs.count;
-       return v4l_queue_querybufs(f, q, q->buffers - createbufs.count);
+       return v4l_queue_querybufs(f, q, createbufs.index, createbufs.count);
 }
 
 static inline int v4l_queue_mmap_bufs(struct v4l_fd *f,
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp 
b/utils/v4l2-compliance/v4l2-compliance.cpp
index 9e2c6983637a..2cf979096bd0 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -1466,6 +1466,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 CREATE_BUFS maximum buffers: %s\n", 
ok(testCreateBufsMax(&node)));
+               printf("\ttest VIDIOC_REMOVE_BUFS: %s\n", 
ok(testRemoveBufs(&node)));
                // Reopen after each streaming test to reset the streaming state
                // in case of any errors in the preceeding test.
                node.reopen();
diff --git a/utils/v4l2-compliance/v4l2-compliance.h 
b/utils/v4l2-compliance/v4l2-compliance.h
index 0cfc9a378e99..b6e342f31ce3 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -385,6 +385,7 @@ int testReadWrite(struct node *node);
 int testExpBuf(struct node *node);
 int testBlockingWait(struct node *node);
 int testCreateBufsMax(struct node *node);
+int testRemoveBufs(struct node *node);
 
 // 32-bit architecture, 32/64-bit time_t tests
 int testTime32_64(struct node *node);
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp 
b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index 922b99b556cd..1db6f4e9e66c 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -529,6 +529,124 @@ static int testCanSetSameTimings(struct node *node)
        return 0;
 }
 
+int testRemoveBufs(struct node *node)
+{
+       int ret;
+       unsigned i;
+
+       node->reopen();
+
+       for (i = 1; i <= V4L2_BUF_TYPE_LAST; i++) {
+               struct v4l2_remove_buffers removebufs = { };
+               unsigned buffers;
+
+               if (!(node->valid_buftypes & (1 << i)))
+                       continue;
+
+               cv4l_queue q(i, V4L2_MEMORY_MMAP);
+
+               if (testSetupVbi(node, i))
+                       continue;
+               ret = q.remove_bufs(node, 0, 0);
+               if (ret == ENOTTY)
+                       continue;
+
+               q.init(i, V4L2_MEMORY_MMAP);
+               ret = q.create_bufs(node, 0);
+
+               memset(&removebufs, 0xff, sizeof(removebufs));
+               removebufs.index = 0;
+               removebufs.count = 0;
+               removebufs.type = q.g_type();
+               fail_on_test(doioctl(node, VIDIOC_REMOVE_BUFS, &removebufs));
+               fail_on_test(check_0(removebufs.reserved, 
sizeof(removebufs.reserved)));
+
+               buffer buf(i);
+
+               /* Create only 1 buffer */
+               fail_on_test(q.create_bufs(node, 1));
+               buffers = q.g_buffers();
+               fail_on_test(buffers != 1);
+               /* Removing buffer index 1 must fail */
+               fail_on_test(q.remove_bufs(node, 1, buffers) != EINVAL);
+               /* Removing buffer index 0 is valid */
+               fail_on_test(q.remove_bufs(node, 0, buffers));
+               /* Removing buffer index 0 again must fail */
+               fail_on_test(q.remove_bufs(node, 0, 1) != EINVAL);
+               /* Create 3 buffers indexes 0 to 2 */
+               fail_on_test(q.create_bufs(node, 3));
+               /* Remove them one by one */
+               fail_on_test(q.remove_bufs(node, 2, 1));
+               fail_on_test(q.remove_bufs(node, 0, 1));
+               fail_on_test(q.remove_bufs(node, 1, 1));
+               /* Removing buffer index 0 again must fail */
+               fail_on_test(q.remove_bufs(node, 0, 1) != EINVAL);
+
+               /* Create 4 buffers indexes 0 to 3 */
+               fail_on_test(q.create_bufs(node, 4));
+               /* Remove buffers index 1 and 2 */
+               fail_on_test(q.remove_bufs(node, 1, 2));
+               /* Add 3 more buffers should be indexes 4 to 6 */
+               fail_on_test(q.create_bufs(node, 3));
+               /* Query buffers:
+                * 1 and 2 have been removed they must fail
+                * 0 and 3 to 6 must exist*/
+               fail_on_test(buf.querybuf(node, 0));
+               fail_on_test(buf.querybuf(node, 1) != EINVAL);
+               fail_on_test(buf.querybuf(node, 2) != EINVAL);
+               fail_on_test(buf.querybuf(node, 3));
+               fail_on_test(buf.querybuf(node, 4));
+               fail_on_test(buf.querybuf(node, 5));
+               fail_on_test(buf.querybuf(node, 6));
+
+               /* Remove existing buffer index 6 with bad type must fail */
+               memset(&removebufs, 0xff, sizeof(removebufs));
+               removebufs.index = 6;
+               removebufs.count = 1;
+               removebufs.type = 0;
+               fail_on_test(doioctl(node, VIDIOC_REMOVE_BUFS, &removebufs) != 
EINVAL);
+
+               /* Remove existing buffer index 6 with bad type and count == 0
+                * must fail */
+               memset(&removebufs, 0xff, sizeof(removebufs));
+               removebufs.index = 6;
+               removebufs.count = 0;
+               removebufs.type = 0;
+               fail_on_test(doioctl(node, VIDIOC_REMOVE_BUFS, &removebufs) != 
EINVAL);
+
+               /* Remove with count == 0 must always return 0 */
+               fail_on_test(q.remove_bufs(node, 0, 0));
+               fail_on_test(q.remove_bufs(node, 1, 0));
+               fail_on_test(q.remove_bufs(node, 6, 0));
+               fail_on_test(q.remove_bufs(node, 7, 0));
+               fail_on_test(q.remove_bufs(node, 0xffffffff, 0));
+
+               /* Remove crossing max allowed buffers boundary must fail */
+               fail_on_test(q.remove_bufs(node, q.g_max_num_buffers() - 2, 7) 
!= EINVAL);
+
+               /* Remove overflow must fail */
+               fail_on_test(q.remove_bufs(node, 3, 0xfffffff) != EINVAL);
+
+               /* Remove 2 buffers on index 2 when index 2 is free must fail */
+               fail_on_test(q.remove_bufs(node, 2, 2) != EINVAL);
+
+               /* Remove 2 buffers on index 0 when index 1 is free must fail */
+               fail_on_test(q.remove_bufs(node, 0, 2) != EINVAL);
+
+               /* Remove 2 buffers on index 1 when index 1 and 2 are free must 
fail */
+               fail_on_test(q.remove_bufs(node, 1, 2) != EINVAL);
+
+               /* Create 2 buffers, that must fill the hole */
+               fail_on_test(q.create_bufs(node, 2));
+               /* Remove all buffers */
+               fail_on_test(q.remove_bufs(node, 0, 7));
+
+               fail_on_test(q.reqbufs(node, 0));
+       }
+
+       return 0;
+}
+
 int testReqBufs(struct node *node)
 {
        struct v4l2_create_buffers crbufs = { };

Reply via email to