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: improve request tests
Author:  Hans Verkuil <hverkuil-ci...@xs4all.nl>
Date:    Wed Jun 9 15:17:21 2021 +0200

Add a lot of comments to explain the various tests. Also check
that all controls are filled in correctly upon completion of a
request, even if no controls were set in the queued request.

Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>

 utils/v4l2-compliance/v4l2-compliance.h      |  25 ++--
 utils/v4l2-compliance/v4l2-test-buffers.cpp  | 169 +++++++++++++++++++++++++--
 utils/v4l2-compliance/v4l2-test-controls.cpp |   3 +-
 3 files changed, 177 insertions(+), 20 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=b4a711027f31d73ee17322d835c5c114be09aec5
diff --git a/utils/v4l2-compliance/v4l2-compliance.h 
b/utils/v4l2-compliance/v4l2-compliance.h
index c2835d951eca..0b05fff7e668 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -80,6 +80,9 @@ enum poll_mode {
 #define VIVID_CID_QUEUE_ERROR          (VIVID_CID_VIVID_BASE + 70)
 #define VIVID_CID_REQ_VALIDATE_ERROR   (VIVID_CID_VIVID_BASE + 72)
 
+#define VIVID_CID_CUSTOM_BASE          (V4L2_CID_USER_BASE | 0xf000)
+#define VIVID_CID_RO_INTEGER           (VIVID_CID_CUSTOM_BASE + 12)
+
 struct test_query_ext_ctrl: v4l2_query_ext_ctrl {
        __u64 menu_mask;
 };
@@ -220,14 +223,14 @@ private:
                        std::exit(EXIT_FAILURE);                \
        } while (0)
 
-#define warn_once(fmt, args...)                                                
\
-       do {                                                            \
-               static bool show;                                       \
-                                                                       \
-               if (!show) {                                            \
-                       show = true;                                    \
-                       warn(fmt, ##args);                              \
-               }                                                       \
+#define warn_once(fmt, args...)                                \
+       do {                                            \
+               static bool show;                       \
+                                                       \
+               if (!show) {                            \
+                       show = true;                    \
+                       warn(fmt, ##args);              \
+               }                                       \
        } while (0)
 
 #define warn_on_test(test)                             \
@@ -236,6 +239,12 @@ private:
                        warn("%s\n", #test);            \
        } while (0)
 
+#define warn_once_on_test(test)                        \
+       do {                                            \
+               if (test)                               \
+                       warn_once("%s\n", #test);       \
+       } while (0)
+
 #define warn_or_info(is_info, fmt, args...)            \
        do {                                            \
                if (is_info)                            \
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp 
b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index f52fa00ddef5..1fe1ec1ca638 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -1950,12 +1950,22 @@ int testRequests(struct node *node, bool test_streaming)
        struct test_query_ext_ctrl valid_qctrl;
        v4l2_ext_controls ctrls;
        v4l2_ext_control ctrl;
+       v4l2_ext_control vivid_ro_ctrl = {
+               .id = VIVID_CID_RO_INTEGER,
+       };
+       v4l2_ext_controls vivid_ro_ctrls = {
+               .which = V4L2_CTRL_WHICH_REQUEST_VAL,
+               .count = 1,
+               .controls = &vivid_ro_ctrl,
+       };
        bool have_controls;
        int ret;
 
+       // If requests are supported, then there must be a media device
        if (node->buf_caps & V4L2_BUF_CAP_SUPPORTS_REQUESTS)
                fail_on_test(media_fd < 0);
 
+       // Check if the driver has controls that can be used to test requests
        memset(&valid_qctrl, 0, sizeof(valid_qctrl));
        memset(&ctrls, 0, sizeof(ctrls));
        memset(&ctrl, 0, sizeof(ctrl));
@@ -1982,42 +1992,57 @@ int testRequests(struct node *node, bool test_streaming)
                        0 : ENOTTY;
        }
 
+       // Test if V4L2_CTRL_WHICH_REQUEST_VAL is supported
        ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
        ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
        fail_on_test(ret != EINVAL && ret != EBADR && ret != ENOTTY);
        have_controls = ret != ENOTTY;
 
        if (media_fd < 0 || ret == EBADR) {
+               // Should not happen if requests are supported
                fail_on_test(node->buf_caps & V4L2_BUF_CAP_SUPPORTS_REQUESTS);
                return ENOTTY;
        }
        if (have_controls) {
                ctrls.request_fd = 10;
+               // Test that querying controls with an invalid request_fd
+               // returns EINVAL
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != 
EINVAL);
        }
        ret = doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd);
        if (ret == ENOTTY) {
+               // Should not happen if requests are supported
                fail_on_test(node->buf_caps & V4L2_BUF_CAP_SUPPORTS_REQUESTS);
                return ENOTTY;
        }
+       // Check that a request was allocated with a valid fd
        fail_on_test(ret);
-       fhs.add(req_fd);
        fail_on_test(req_fd < 0);
+       fhs.add(req_fd);
        if (have_controls) {
                ctrls.request_fd = req_fd;
+               // The request is in unqueued state, so this should return 
EACCES
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != 
EACCES);
        }
+       // You cannot queue a request that has no buffer
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, nullptr) != 
ENOENT);
+       // REINIT must work for an unqueued request
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, nullptr));
+       // Close media_fd
        fhs.del(media_fd);
+       // This should have no effect on req_fd
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, nullptr) != 
ENOENT);
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, nullptr));
+       // Close req_fd
        fhs.del(req_fd);
+       // G_EXT_CTRLS must now return EINVAL for req_fd since it no longer 
exists
        if (have_controls)
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != 
EINVAL);
+       // And the media request ioctls now must return EBADF
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, nullptr) != 
EBADF);
        fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, nullptr) != 
EBADF);
 
+       // Open media_fd and alloc a request again
        media_fd = fhs.add(mi_get_media_fd(node->g_fd(), node->bus_info));
        fail_on_test(doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd));
        fhs.add(req_fd);
@@ -2026,29 +2051,40 @@ int testRequests(struct node *node, bool test_streaming)
        if (have_controls) {
                ctrl.value = valid_qctrl.minimum;
                ctrls.which = 0;
+               // Set control without requests
                fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
                ctrl.value = valid_qctrl.maximum;
                ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
                ctrls.request_fd = req_fd;
+               // Set control for a request
                fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
                ctrl.value = valid_qctrl.minimum;
                ctrls.request_fd = req_fd;
+               // But you cannot get the value of an unqueued request
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != 
EACCES);
                ctrls.which = 0;
+               // But you can without a request
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
                fail_on_test(ctrl.value != valid_qctrl.minimum);
                ctrls.request_fd = req_fd;
                ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
                ctrl.id = 1;
+               // Setting an invalid control in a request must fail
                fail_on_test(!doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+               // And also when trying to read an invalid control of a request
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != 
EACCES);
        }
        ctrl.id = valid_qctrl.id;
+       // Close req_fd and media_fd and reopen device node
        fhs.del(req_fd);
        fhs.del(media_fd);
        node->reopen();
 
        int type = node->g_type();
+       // For m2m devices g_type() will return the capture type, so
+       // we need to invert it to get the output type.
+       // At the moment only the output type of an m2m device can use
+       // requests.
        if (node->is_m2m)
                type = v4l_type_invert(type);
        if (v4l_type_is_vbi(type)) {
@@ -2059,6 +2095,8 @@ int testRequests(struct node *node, bool test_streaming)
        }
 
        if (!(node->valid_buftypes & (1 << type))) {
+               // If the type is not supported, then check that requests
+               // are also not supported.
                fail_on_test(node->buf_caps & V4L2_BUF_CAP_SUPPORTS_REQUESTS);
                return ENOTTY;
        }
@@ -2067,46 +2105,60 @@ int testRequests(struct node *node, bool test_streaming)
        buffer_info.clear();
 
        cv4l_queue q(type, V4L2_MEMORY_MMAP);
+       // For m2m devices q is the output queue and m2m_q is the capture queue
        cv4l_queue m2m_q(v4l_type_invert(type));
 
        q.init(type, V4L2_MEMORY_MMAP);
-       fail_on_test(q.reqbufs(node, 2));
+       fail_on_test(q.reqbufs(node, 15));
 
        unsigned min_bufs = q.g_buffers();
-       fail_on_test(q.reqbufs(node, min_bufs + 4));
+       fail_on_test(q.reqbufs(node, min_bufs + 6));
        unsigned num_bufs = q.g_buffers();
+       // Create twice as many requests as there are buffers
        unsigned num_requests = 2 * num_bufs;
        last_seq.init();
 
        media_fd = fhs.add(mi_get_media_fd(node->g_fd(), node->bus_info));
 
+       // Allocate the requests
        for (unsigned i = 0; i < num_requests; i++) {
                fail_on_test(doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, 
&buf_req_fds[i]));
                fhs.add(buf_req_fds[i]);
                fail_on_test(buf_req_fds[i] < 0);
+               // Check that empty requests can't be queued
                fail_on_test(!doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_QUEUE, nullptr));
        }
+       // close the media fd, should not be needed anymore
        fhs.del(media_fd);
 
        buffer buf(q);
 
        fail_on_test(buf.querybuf(node, 0));
+       // Queue a buffer without using requests
        ret = buf.qbuf(node);
+       // If this fails, then that can only happen if the queue
+       // requires requests. In that case EBADR is returned.
        fail_on_test(ret && ret != EBADR);
        fail_on_test(buf.querybuf(node, 1));
+       // Now try to queue the buffer to the request
        buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
        buf.s_request_fd(buf_req_fds[1]);
+       // If requests are required, then this must now work
+       // If requests are optional, then this must now fail since the
+       // queue in is non-request mode.
        if (ret == EBADR)
                fail_on_test(buf.qbuf(node));
        else
                fail_on_test(!buf.qbuf(node));
 
+       // Reopen device node, clearing any pending requests
        node->reopen();
 
        q.init(type, V4L2_MEMORY_MMAP);
        fail_on_test(q.reqbufs(node, num_bufs));
 
        if (node->is_m2m) {
+               // Setup the capture queue
                fail_on_test(m2m_q.reqbufs(node, 2));
                fail_on_test(node->streamon(m2m_q.g_type()));
 
@@ -2115,6 +2167,9 @@ int testRequests(struct node *node, bool test_streaming)
                fail_on_test(buf.querybuf(node, 0));
                buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
                buf.s_request_fd(buf_req_fds[0]);
+               // Only the output queue can support requests,
+               // so if the capture queue also supports requests,
+               // then something is wrong.
                fail_on_test(!buf.qbuf(node));
                fail_on_test(node->streamoff(m2m_q.g_type()));
                fail_on_test(m2m_q.reqbufs(node, 0));
@@ -2128,10 +2183,12 @@ int testRequests(struct node *node, bool test_streaming)
                buffer buf(q);
 
                fail_on_test(buf.querybuf(node, i));
+               // No request was set, so this should return 0
                fail_on_test(buf.g_request_fd());
                buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
                if (i == 0) {
                        buf.s_request_fd(-1);
+                       // Can't queue to an invalid request fd
                        fail_on_test(!buf.qbuf(node));
                        buf.s_request_fd(0xdead);
                        fail_on_test(!buf.qbuf(node));
@@ -2140,25 +2197,34 @@ int testRequests(struct node *node, bool test_streaming)
                if (v4l_type_is_video(buf.g_type()))
                        buf.s_field(V4L2_FIELD_ANY);
                if (!(i & 1)) {
+                       // VIDIOC_PREPARE_BUF is incompatible with requests
                        fail_on_test(buf.prepare_buf(node) != EINVAL);
                        buf.s_flags(0);
+                       // Test vivid error injection
                        if (node->inject_error(VIVID_CID_BUF_PREPARE_ERROR))
                                fail_on_test(buf.prepare_buf(node) != EINVAL);
                        fail_on_test(buf.prepare_buf(node));
                        fail_on_test(buf.querybuf(node, i));
+                       // Check that the buffer was prepared
                        fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_PREPARED));
                        buf.s_flags(buf.g_flags() | V4L2_BUF_FLAG_REQUEST_FD);
                        buf.s_request_fd(buf_req_fds[i]);
                }
+               // Queue the buffer to the request
                int err = buf.qbuf(node);
                if (!err) {
+                       // If requests are not supported, this should fail
                        fail_on_test(!supports_requests);
+                       // You can't queue the same buffer again
                        fail_on_test(!buf.qbuf(node));
                } else {
+                       // Can only fail if requests are not supported
                        fail_on_test(supports_requests);
+                       // and should fail with EBADR in that case
                        fail_on_test(err != EBADR);
                }
                if (err) {
+                       // Requests are not supported, so clean up and return
                        fail_on_test(node->streamoff(q.g_type()));
                        fail_on_test(q.reqbufs(node, 0));
                        if (node->is_m2m) {
@@ -2169,11 +2235,14 @@ int testRequests(struct node *node, bool test_streaming)
                        node->reopen();
                        return ENOTTY;
                }
+               // Check flags and request fd
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_IN_REQUEST));
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD));
                fail_on_test(buf.g_request_fd() < 0);
+               // Query the buffer again
                fail_on_test(buf.querybuf(node, i));
+               // Check returned flags and request fd
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_IN_REQUEST));
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD));
@@ -2182,55 +2251,81 @@ int testRequests(struct node *node, bool test_streaming)
                        fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_PREPARED);
                else
                        fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_PREPARED));
+               // Check that you can't queue it again
                buf.s_request_fd(buf_req_fds[i]);
                fail_on_test(!buf.qbuf(node));
 
+               // Set a control in the request, except for every third request.
                ctrl.value = (i & 1) ? valid_qctrl.maximum : 
valid_qctrl.minimum;
                ctrls.request_fd = buf_req_fds[i];
-               fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+               if (i % 3 < 2)
+                       fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+               // Re-init the unqueued request
                fail_on_test(doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_REINIT, nullptr));
 
+               // Make sure that the buffer is no longer in a request
                fail_on_test(buf.querybuf(node, i));
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_IN_REQUEST);
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD);
 
+               // Set the control again
                ctrls.request_fd = buf_req_fds[i];
-               fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
-
+               if (i % 3 < 2)
+                       fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+
+               // After the re-init the buffer is no longer marked for
+               // a request. If a request has been queued before (hence
+               // the 'if (i)' check), then queuing the buffer without
+               // a request must fail since you can't mix the two streamining
+               // models.
                if (i)
                        fail_on_test(!buf.qbuf(node));
                buf.s_flags(buf.g_flags() | V4L2_BUF_FLAG_REQUEST_FD);
                buf.s_request_fd(buf_req_fds[i]);
                buf.s_field(V4L2_FIELD_ANY);
+               // Queue the buffer for the request
                fail_on_test(buf.qbuf(node));
+               // Verify that drivers will replace FIELD_ANY for video output 
queues
                if (v4l_type_is_video(buf.g_type()) && 
v4l_type_is_output(buf.g_type()))
                        fail_on_test(buf.g_field() == V4L2_FIELD_ANY);
+               // Query buffer and check that it is marked as being part of a 
request
                fail_on_test(buf.querybuf(node, i));
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_IN_REQUEST));
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD));
+               // Use vivid to check buffer prepare or request validation 
error injection
                if ((i & 1) && node->inject_error(i > num_bufs / 2 ?
                                                  VIVID_CID_BUF_PREPARE_ERROR :
                                                  VIVID_CID_REQ_VALIDATE_ERROR))
                        fail_on_test(doioctl_fd(buf_req_fds[i],
                                                MEDIA_REQUEST_IOC_QUEUE, 
nullptr) != EINVAL);
+               // Queue the request
                ret = doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_QUEUE, 
nullptr);
                if (node->codec_mask & STATELESS_DECODER) {
+                       // Stateless decoders might require that certain
+                       // controls are present in the request. In that
+                       // case they return ENOENT and we just stop testing
+                       // since we don't know what those controls are.
                        fail_on_test(ret != ENOENT);
                        test_streaming = false;
                        break;
                }
                fail_on_test(ret);
                fail_on_test(buf.querybuf(node, i));
+               // Check that the buffer is now queued up
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_IN_REQUEST);
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD));
                fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_QUEUED));
+               // Re-initing or requeuing the request is no longer possible
                fail_on_test(doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_REINIT, nullptr) != EBUSY);
                fail_on_test(doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_QUEUE, nullptr) != EBUSY);
                if (i >= min_bufs) {
+                       // Close some of the request fds to check that this
+                       // is safe to do
                        close(buf_req_fds[i]);
                        buf_req_fds[i] = -1;
                }
                if (i == min_bufs - 1) {
+                       // Check vivid STREAMON error injection
                        if (node->inject_error(VIVID_CID_START_STR_ERROR))
                                fail_on_test(!node->streamon(q.g_type()));
                        fail_on_test(node->streamon(q.g_type()));
@@ -2242,45 +2337,97 @@ int testRequests(struct node *node, bool test_streaming)
        if (test_streaming) {
                unsigned capture_count;
 
-               fail_on_test(captureBufs(node, node, q, m2m_q, num_bufs,
+               // Continue streaming
+               // For m2m devices captureBufs() behaves a bit odd: you pass
+               // in the total number of output buffers that you want to
+               // stream, but since there are already q.g_buffers() output
+               // buffers queued up (see previous loop), the captureBufs()
+               // function will subtract that from frame_count, so it will
+               // only queue frame_count - q.g_buffers() output buffers.
+               // In order to ensure we captured at least
+               // min_bufs buffers we need to add min_bufs to the frame_count.
+               fail_on_test(captureBufs(node, node, q, m2m_q,
+                                        num_bufs + (node->is_m2m ? min_bufs : 
0),
                                         POLL_MODE_SELECT, capture_count));
        }
        fail_on_test(node->streamoff(q.g_type()));
 
+       // Note that requests min_bufs...2*min_bufs-1 close their filehandles,
+       // so here we just go through the first half of the requests.
        for (unsigned i = 0; test_streaming && i < min_bufs; i++) {
                buffer buf(q);
 
+               // Get the control
                ctrls.request_fd = buf_req_fds[i];
                fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
-               fail_on_test(ctrl.value != ((i & 1) ? valid_qctrl.maximum :
+               bool is_max = i & 1;
+               // Since the control was not set for every third request,
+               // the value will actually be that of the previous request.
+               if (i % 3 == 2)
+                       is_max = !is_max;
+               // Check that the value is as expected
+               fail_on_test(ctrl.value != (is_max ? valid_qctrl.maximum :
                             valid_qctrl.minimum));
+               if (is_vivid) {
+                       // vivid specific: check that the read-only control
+                       // of the completed request has the expected value
+                       // (sequence number & 0xff).
+                       vivid_ro_ctrls.request_fd = buf_req_fds[i];
+                       fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, 
&vivid_ro_ctrls));
+                       if (node->is_video && !node->can_output)
+                               warn_once_on_test(vivid_ro_ctrl.value != 
(int)i);
+               }
                fail_on_test(buf.querybuf(node, i));
+               // Check that all the buffers of the stopped stream are
+               // no longer marked as belonging to a request.
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD);
                fail_on_test(buf.g_request_fd());
                struct pollfd pfd = {
                        buf_req_fds[i],
                        POLLPRI, 0
                };
+               // Check that polling the request fd will immediately return,
+               // indicating that the request has completed.
                fail_on_test(poll(&pfd, 1, 100) != 1);
+               // Requeuing the request must fail
                fail_on_test(doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_QUEUE, nullptr) != EBUSY);
+               // But reinit must succeed.
                fail_on_test(doioctl_fd(buf_req_fds[i], 
MEDIA_REQUEST_IOC_REINIT, nullptr));
                fail_on_test(buf.querybuf(node, i));
                fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD);
                fail_on_test(buf.g_request_fd());
-               fhs.del(buf_req_fds[i]);
                ctrls.request_fd = buf_req_fds[i];
+               // Check that getting controls from a reinited request fails
                fail_on_test(!doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+               // Close the request fd
+               fhs.del(buf_req_fds[i]);
+               buf_req_fds[i] = -1;
        }
+       // Close any remaining open request fds
        for (unsigned i = 0; i < num_requests; i++)
                if (buf_req_fds[i] >= 0)
                        fhs.del(buf_req_fds[i]);
 
+       // Getting the current control value must work
        ctrls.which = 0;
        fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
-       if (test_streaming)
-               fail_on_test(ctrl.value != (((num_bufs - 1) & 1) ? 
valid_qctrl.maximum :
+       // Check the final control value
+       if (test_streaming) {
+               bool is_max = (num_bufs - 1) & 1;
+               if ((num_bufs - 1) % 3 == 2)
+                       is_max = !is_max;
+               fail_on_test(ctrl.value != (is_max ? valid_qctrl.maximum :
                                            valid_qctrl.minimum));
+               if (is_vivid) {
+                       // For vivid check the final read-only value
+                       vivid_ro_ctrls.which = 0;
+                       fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, 
&vivid_ro_ctrls));
+                       if (node->is_video && !node->can_output)
+                               warn_on_test(vivid_ro_ctrl.value != 
(int)(num_bufs - 1));
+               }
+       }
 
+       // Cleanup
        fail_on_test(q.reqbufs(node, 0));
        if (node->is_m2m) {
                fail_on_test(node->streamoff(m2m_q.g_type()));
diff --git a/utils/v4l2-compliance/v4l2-test-controls.cpp 
b/utils/v4l2-compliance/v4l2-test-controls.cpp
index 4be2f61c0532..07685d7247e3 100644
--- a/utils/v4l2-compliance/v4l2-test-controls.cpp
+++ b/utils/v4l2-compliance/v4l2-test-controls.cpp
@@ -738,7 +738,8 @@ int testExtendedControls(struct node *node)
                        if (checkExtendedCtrl(ctrl, qctrl))
                                return fail("s_ext_ctrls returned invalid 
control contents (%08x)\n", qctrl.id);
                }
-               if (qctrl.type == V4L2_CTRL_TYPE_STRING)
+
+               if (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)
                        delete [] ctrl.string;
                ctrl.string = nullptr;
        }

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to