aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2018-09-01 13:55:30 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2018-09-01 14:03:13 +0200
commitb551f293d9e6c36ac6bce525d681ad2a62068e86 (patch)
treefecd6ebd3842186f7e72356f1e885b93998d7de2
parentd7d95f821ce6dd9c21f549524e731ba2b40f5c7b (diff)
v4l2-compliance: add request compliance testsrequest
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.cpp1
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.h1
-rw-r--r--utils/v4l2-compliance/v4l2-test-buffers.cpp308
3 files changed, 307 insertions, 3 deletions
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index 7167f549..a3fabe31 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -987,6 +987,7 @@ void testNode(struct node &node, struct node &expbuf_node, media_type type,
printf("Buffer ioctls%s:\n", suffix);
printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
printf("\ttest VIDIOC_EXPBUF: %s\n", ok(testExpBuf(&node)));
+ printf("\ttest Requests: %s\n", ok(testRequests(&node)));
printf("\n");
}
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index f7c90c13..7ca46813 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -265,6 +265,7 @@ int testBlockingWait(struct node *node);
int testMmap(struct node *node, unsigned frame_count);
int testUserPtr(struct node *node, unsigned frame_count);
int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count);
+int testRequests(struct node *node);
void streamAllFormats(struct node *node);
// Color tests
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index d654a7cd..dca21ae1 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -30,6 +30,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
+#include <poll.h>
#include <sys/ioctl.h>
#include <map>
#include <vector>
@@ -58,6 +59,22 @@ struct buf_seq {
static struct buf_seq last_seq, last_m2m_seq;
+static int buf_req_fds[VIDEO_MAX_FRAME * 2];
+
+static inline int named_ioctl_fd(int fd, bool trace, const char *cmd_name, unsigned long cmd, void *arg)
+{
+ int retval;
+ int e;
+
+ retval = ioctl(fd, cmd, arg);
+ e = retval == 0 ? 0 : errno;
+ if (trace)
+ fprintf(stderr, "\t\t%s returned %d (%s)\n",
+ cmd_name, retval, strerror(e));
+ return retval == -1 ? e : (retval ? -1 : 0);
+}
+#define doioctl_fd(fd, r, p) named_ioctl_fd((fd), node->g_trace(), #r, r, p)
+
enum QueryBufMode {
Unqueued,
Prepared,
@@ -148,7 +165,7 @@ private:
s_timestamp_ts(ts);
s_timestamp_src(V4L2_BUF_FLAG_TSTAMP_SRC_SOE);
}
- s_flags(V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME);
+ s_flags(g_flags() | V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME);
tc.type = V4L2_TC_TYPE_30FPS;
tc.flags = V4L2_TC_USERBITS_8BITCHARS;
tc.frames = ts.tv_nsec * 30 / 1000000000;
@@ -197,7 +214,11 @@ int buffer::check(unsigned type, unsigned memory, unsigned index,
fail_on_test(g_memory() != memory);
fail_on_test(g_index() >= VIDEO_MAX_FRAME);
fail_on_test(g_index() != index);
- fail_on_test(buf.reserved2 || buf.reserved);
+ fail_on_test(buf.reserved2);
+ if (g_flags() & V4L2_BUF_FLAG_REQUEST_FD)
+ fail_on_test(g_request_fd() < 0);
+ else
+ fail_on_test(g_request_fd());
fail_on_test(timestamp != V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC &&
timestamp != V4L2_BUF_FLAG_TIMESTAMP_COPY);
fail_on_test(timestamp_src != V4L2_BUF_FLAG_TSTAMP_SRC_SOE &&
@@ -219,6 +240,11 @@ int buffer::check(unsigned type, unsigned memory, unsigned index,
buf_states++;
if (g_flags() & V4L2_BUF_FLAG_PREPARED)
buf_states++;
+ if (g_flags() & V4L2_BUF_FLAG_IN_REQUEST) {
+ fail_on_test(!(g_flags() & V4L2_BUF_FLAG_REQUEST_FD));
+ if (!(g_flags() & V4L2_BUF_FLAG_PREPARED))
+ buf_states++;
+ }
fail_on_test(buf_states > 1);
fail_on_test(buf.length == 0);
if (v4l_type_is_planar(g_type())) {
@@ -679,8 +705,19 @@ static int captureBufs(struct node *node, const cv4l_queue &q,
sizeof(orig_buf.timecode)));
}
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
+ if (buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD) {
+ buf.querybuf(node, buf.g_index());
+ fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD);
+ fail_on_test(buf.g_request_fd());
+ fail_on_test(!buf.qbuf(node));
+ buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
+ buf.s_request_fd(buf_req_fds[2 * frame_count - count]);
+ }
fail_on_test(buf.qbuf(node));
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
+ if (buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD)
+ fail_on_test(doioctl_fd(buf_req_fds[2 * frame_count - count],
+ MEDIA_REQUEST_IOC_QUEUE, 0));
if (--count == 0)
break;
}
@@ -708,6 +745,7 @@ static int captureBufs(struct node *node, const cv4l_queue &q,
sizeof(orig_buf.timecode)));
}
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
+ buf.s_flags(buf.g_flags() & ~V4L2_BUF_FLAG_REQUEST_FD);
fail_on_test(buf.qbuf(node));
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
}
@@ -725,10 +763,12 @@ static int setupM2M(struct node *node, cv4l_queue &q)
last_m2m_seq.init();
fail_on_test(q.reqbufs(node, 2));
+ fail_on_test(node->streamon(q.g_type()));
for (unsigned i = 0; i < q.g_buffers(); i++) {
buffer buf(q);
fail_on_test(buf.querybuf(node, i));
+ buf.s_flags(buf.g_flags() & ~V4L2_BUF_FLAG_REQUEST_FD);
fail_on_test(buf.qbuf(node));
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
}
@@ -738,7 +778,6 @@ static int setupM2M(struct node *node, cv4l_queue &q)
node->g_fmt(fmt);
last_m2m_seq.last_field = fmt.g_field();
}
- fail_on_test(node->streamon(q.g_type()));
return 0;
}
@@ -882,6 +921,8 @@ int testMmap(struct node *node, unsigned frame_count)
fail_on_test(buf.querybuf(node, i));
fail_on_test(buf.qbuf(node));
fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE);
+ fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_REQUEST_FD);
+ fail_on_test(buf.g_request_fd());
}
// calling STREAMOFF...
fail_on_test(node->streamoff(q.g_type()));
@@ -1171,6 +1212,267 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count
return 0;
}
+int testRequests(struct node *node)
+{
+ int media_fd = mi_get_media_fd(node->g_fd());
+ int req_fd;
+ qctrl_map::iterator iter;
+ struct test_query_ext_ctrl valid_qctrl;
+ v4l2_ext_controls ctrls;
+ v4l2_ext_control ctrl;
+ bool have_controls;
+ int ret;
+
+ memset(&valid_qctrl, 0, sizeof(valid_qctrl));
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(&ctrl, 0, sizeof(ctrl));
+ for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
+ test_query_ext_ctrl &qctrl = iter->second;
+
+ if (qctrl.type != V4L2_CTRL_TYPE_INTEGER &&
+ qctrl.type != V4L2_CTRL_TYPE_BOOLEAN)
+ continue;
+ if (qctrl.minimum != qctrl.maximum) {
+ valid_qctrl = qctrl;
+ ctrl.id = qctrl.id;
+ break;
+ }
+ }
+
+ ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
+ ret = doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
+ fail_on_test(ret != EINVAL && ret != EACCES && ret != ENOTTY);
+ have_controls = ret != ENOTTY;
+
+ if (media_fd < 0 || ret == EACCES)
+ return ENOTTY;
+ if (have_controls) {
+ ctrls.request_fd = 10;
+ doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls);
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != EINVAL);
+ }
+ fail_on_test(doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd));
+ fail_on_test(req_fd < 0);
+ if (have_controls) {
+ ctrls.request_fd = req_fd;
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != EACCES);
+ }
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, 0) != ENOENT);
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, 0));
+ close(media_fd);
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, 0) != ENOENT);
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, 0));
+ close(req_fd);
+ if (have_controls)
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != EINVAL);
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_QUEUE, 0) != EBADF);
+ fail_on_test(doioctl_fd(req_fd, MEDIA_REQUEST_IOC_REINIT, 0) != EBADF);
+
+ media_fd = mi_get_media_fd(node->g_fd());
+ fail_on_test(doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd));
+ ctrls.count = 1;
+ ctrls.controls = &ctrl;
+ if (have_controls) {
+ ctrl.value = valid_qctrl.minimum;
+ ctrls.which = 0;
+ 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;
+ fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+ ctrl.value = valid_qctrl.minimum;
+ ctrls.request_fd = req_fd;
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != EACCES);
+ ctrls.which = 0;
+ 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;
+ fail_on_test(!doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != EACCES);
+ }
+ ctrl.id = valid_qctrl.id;
+ close(req_fd);
+ close(media_fd);
+ node->reopen();
+
+ int type = node->is_planar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (node->can_output)
+ type = v4l_type_invert(type);
+
+ if (!(node->valid_buftypes & (1 << type)))
+ return ENOTTY;
+
+ buffer_info.clear();
+
+ cv4l_queue q(type, V4L2_MEMORY_MMAP);
+ cv4l_queue m2m_q(v4l_type_invert(type));
+
+ q.init(type, V4L2_MEMORY_MMAP);
+ fail_on_test(q.reqbufs(node, 2));
+ unsigned num_bufs = q.g_buffers();
+ unsigned num_requests = 2 * num_bufs;
+ last_seq.init();
+
+ media_fd = mi_get_media_fd(node->g_fd());
+
+ for (unsigned i = 0; i < num_requests; i++) {
+ fail_on_test(doioctl_fd(media_fd, MEDIA_IOC_REQUEST_ALLOC, &buf_req_fds[i]));
+ fail_on_test(buf_req_fds[i] < 0);
+ fail_on_test(!doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_QUEUE, 0));
+ }
+ close(media_fd);
+
+ buffer buf(q);
+
+ fail_on_test(buf.querybuf(node, 0));
+ fail_on_test(buf.qbuf(node));
+ fail_on_test(buf.querybuf(node, 1));
+ buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
+ buf.s_request_fd(buf_req_fds[1]);
+ fail_on_test(!buf.qbuf(node));
+
+ node->reopen();
+
+ q.init(type, V4L2_MEMORY_MMAP);
+ fail_on_test(q.reqbufs(node, 2));
+
+ fail_on_test(node->streamon(q.g_type()));
+ if (node->is_m2m) {
+ fail_on_test(m2m_q.reqbufs(node, 2));
+ fail_on_test(node->streamon(m2m_q.g_type()));
+
+ buffer buf(m2m_q);
+
+ fail_on_test(buf.querybuf(node, 0));
+ buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
+ buf.s_request_fd(buf_req_fds[0]);
+ fail_on_test(!buf.qbuf(node));
+ fail_on_test(node->streamoff(m2m_q.g_type()));
+ fail_on_test(m2m_q.reqbufs(node, 0));
+
+ fail_on_test(setupM2M(node, m2m_q));
+ }
+
+ ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
+ // Test queuing buffers...
+ for (unsigned i = 0; i < num_bufs; i++) {
+ buffer buf(q);
+
+ fail_on_test(buf.querybuf(node, i));
+ fail_on_test(buf.g_request_fd());
+ buf.s_flags(V4L2_BUF_FLAG_REQUEST_FD);
+ if (i == 0) {
+ buf.s_request_fd(-1);
+ fail_on_test(!buf.qbuf(node));
+ buf.s_request_fd(0xdead);
+ fail_on_test(!buf.qbuf(node));
+ }
+ buf.s_request_fd(buf_req_fds[i]);
+ if (!(i & 1)) {
+ fail_on_test(buf.prepare_buf(node) != EINVAL);
+ buf.s_flags(0);
+ fail_on_test(buf.prepare_buf(node));
+ fail_on_test(buf.querybuf(node, i));
+ 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]);
+ }
+ fail_on_test(buf.qbuf(node));
+ 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);
+ fail_on_test(buf.querybuf(node, i));
+ 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);
+ if (i & 1)
+ fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_PREPARED);
+ else
+ fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_PREPARED));
+ buf.s_request_fd(buf_req_fds[i]);
+ fail_on_test(!buf.qbuf(node));
+
+ 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));
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_REINIT, 0));
+
+ 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);
+
+ ctrls.request_fd = buf_req_fds[i];
+ fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+
+ 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]);
+ fail_on_test(buf.qbuf(node));
+ 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));
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_QUEUE, 0));
+ 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));
+ fail_on_test(!(buf.g_flags() & V4L2_BUF_FLAG_QUEUED));
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_REINIT, 0) != EBUSY);
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_QUEUE, 0) != EBUSY);
+ }
+
+ fail_on_test(node->g_fmt(cur_fmt, q.g_type()));
+
+ fail_on_test(captureBufs(node, q, m2m_q, num_bufs, true));
+ fail_on_test(node->streamoff(q.g_type()));
+
+ for (unsigned i = 0; i < num_bufs; i++) {
+ buffer buf(q);
+
+ 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 :
+ valid_qctrl.minimum));
+ 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());
+ struct pollfd pfd = {
+ buf_req_fds[i],
+ POLLPRI, 0
+ };
+ fail_on_test(poll(&pfd, 1, 100) != 1);
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_QUEUE, 0) != EBUSY);
+ fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_REINIT, 0));
+ 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());
+ close(buf_req_fds[i]);
+ ctrls.request_fd = buf_req_fds[i];
+ fail_on_test(!doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+ }
+ for (unsigned i = num_bufs; i < num_requests; i++)
+ close(buf_req_fds[i]);
+
+ ctrls.which = 0;
+ fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+ fail_on_test(ctrl.value != (((num_bufs - 1) & 1) ? valid_qctrl.maximum :
+ valid_qctrl.minimum));
+
+ fail_on_test(q.reqbufs(node, 0));
+ if (node->is_m2m) {
+ fail_on_test(node->streamoff(m2m_q.g_type()));
+ m2m_q.munmap_bufs(node);
+ fail_on_test(m2m_q.reqbufs(node, 0));
+ }
+
+ return 0;
+}
+
static int testBlockingDQBuf(struct node *node, cv4l_queue &q)
{
int pid_dqbuf;

Privacy Policy