aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-01-06 09:21:53 +0100
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2021-01-06 09:21:53 +0100
commit4739a67dac10389559cffa6450a9ad88d37629ac (patch)
treeb6a702e6f31dc3bc0f8e34142e0833ac325ebdab
parentc83b0bda1f82947687e8b8645b78f6d2b7e7fcee (diff)
v4l2-compliance: test polling and disconnecting
Test that disconnecting a device will wake up any processes that are using select or poll. This can only be tested with the vivid driver that enabled the DISCONNECT control. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.cpp8
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.h5
-rw-r--r--utils/v4l2-compliance/v4l2-test-controls.cpp87
3 files changed, 98 insertions, 2 deletions
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index 2d4d10db..9e7b14c7 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -1438,6 +1438,14 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
* S_SELECTION flags tests
*/
+ if (is_vivid &&
+ node.controls.find(VIVID_CID_DISCONNECT) != node.controls.end()) {
+ if (node.node2)
+ node.node2->close();
+ node.node2 = NULL;
+ printf("\ttest Disconnect: %s\n\n", ok(testVividDisconnect(&node)));
+ }
+
restoreState();
show_total:
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index 5cfe870b..c0cc57db 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -70,6 +70,10 @@ enum poll_mode {
#define IS_ENCODER(node) ((node)->codec_mask & (JPEG_ENCODER | STATEFUL_ENCODER | STATELESS_ENCODER))
#define IS_DECODER(node) ((node)->codec_mask & (JPEG_DECODER | STATEFUL_DECODER | STATELESS_DECODER))
+#define V4L2_CTRL_CLASS_VIVID 0x00f00000
+#define VIVID_CID_VIVID_BASE (V4L2_CTRL_CLASS_VIVID | 0xf000)
+#define VIVID_CID_DISCONNECT (VIVID_CID_VIVID_BASE + 65)
+
struct test_query_ext_ctrl: v4l2_query_ext_ctrl {
__u64 menu_mask;
};
@@ -296,6 +300,7 @@ int testQueryControls(struct node *node);
int testSimpleControls(struct node *node);
int testExtendedControls(struct node *node);
int testEvents(struct node *node);
+int testVividDisconnect(struct node *node);
int testJpegComp(struct node *node);
// I/O configuration ioctl tests
diff --git a/utils/v4l2-compliance/v4l2-test-controls.cpp b/utils/v4l2-compliance/v4l2-test-controls.cpp
index 839132b6..9a68b7e8 100644
--- a/utils/v4l2-compliance/v4l2-test-controls.cpp
+++ b/utils/v4l2-compliance/v4l2-test-controls.cpp
@@ -23,12 +23,12 @@
#include <vector>
#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/epoll.h>
#include "compiler.h"
#include "v4l2-compliance.h"
-#define V4L2_CTRL_CLASS_VIVID 0x00f00000
-
static int checkQCtrl(struct node *node, struct test_query_ext_ctrl &qctrl)
{
struct v4l2_querymenu qmenu;
@@ -901,6 +901,89 @@ int testEvents(struct node *node)
return 0;
}
+int testVividDisconnect(struct node *node)
+{
+ // Test that disconnecting a device will wake up any processes
+ // that are using select or poll.
+ //
+ // This can only be tested with the vivid driver that enabled
+ // the DISCONNECT control.
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ struct timeval tv = { 5, 0 };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(node->g_fd(), &fds);
+ int res = select(node->g_fd() + 1, nullptr, nullptr, &fds, &tv);
+ // No POLLPRI seen
+ if (res != 1)
+ exit(1);
+ // POLLPRI seen, but didn't wake up
+ if (!tv.tv_sec)
+ exit(2);
+ v4l2_event ev = {};
+ // Woke up on POLLPRI, but VIDIOC_DQEVENT didn't return
+ // the ENODEV error.
+ if (doioctl(node, VIDIOC_DQEVENT, &ev) != ENODEV)
+ exit(3);
+ exit(0);
+ }
+ v4l2_control ctrl = { VIVID_CID_DISCONNECT, 0 };
+ sleep(1);
+ fail_on_test(doioctl(node, VIDIOC_S_CTRL, &ctrl));
+ int wstatus;
+ fail_on_test(waitpid(pid, &wstatus, 0) != pid);
+ fail_on_test(!WIFEXITED(wstatus));
+ if (WEXITSTATUS(wstatus))
+ return fail("select child exited with status %d\n", WEXITSTATUS(wstatus));
+
+ node->reopen();
+
+ pid = fork();
+ if (pid == 0) {
+ struct epoll_event ep_ev;
+ int epollfd = epoll_create1(0);
+
+ if (epollfd < 0)
+ exit(1);
+
+ ep_ev.events = 0;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, node->g_fd(), &ep_ev))
+ exit(2);
+
+ ep_ev.events = EPOLLPRI;
+ ep_ev.data.fd = node->g_fd();
+ if (epoll_ctl(epollfd, EPOLL_CTL_MOD, node->g_fd(), &ep_ev))
+ exit(3);
+ int ret = epoll_wait(epollfd, &ep_ev, 1, 5000);
+ if (ret == 0)
+ exit(4);
+ if (ret < 0)
+ exit(5);
+ if (ret != 1)
+ exit(6);
+ if (!(ep_ev.events & EPOLLPRI))
+ exit(7);
+ if (!(ep_ev.events & EPOLLERR))
+ exit(8);
+ v4l2_event ev = {};
+ // Woke up on POLLPRI, but VIDIOC_DQEVENT didn't return
+ // the ENODEV error.
+ if (doioctl(node, VIDIOC_DQEVENT, &ev) != ENODEV)
+ exit(9);
+ exit(0);
+ }
+ sleep(1);
+ fail_on_test(doioctl(node, VIDIOC_S_CTRL, &ctrl));
+ fail_on_test(waitpid(pid, &wstatus, 0) != pid);
+ fail_on_test(!WIFEXITED(wstatus));
+ if (WEXITSTATUS(wstatus))
+ return fail("epoll child exited with status %d\n", WEXITSTATUS(wstatus));
+ return 0;
+}
+
int testJpegComp(struct node *node)
{
struct v4l2_jpegcompression jc;

Privacy Policy