aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-09-03 10:59:04 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2021-09-03 10:59:04 +0200
commit05a468e033af0e4c775aaa10fe4d02c45de698ae (patch)
tree0bfa41cca05127baafcb1eb77aa308c0137d5e50
parentcd769da3e1c2c4f4263f6fd9ad8c0f928219243f (diff)
downloadv4l-utils-05a468e033af0e4c775aaa10fe4d02c45de698ae.tar.gz
v4l2-compliance: add new test for 32/64 bit time handling
When a 32-bit application is running on a 64-bit kernel then there can be two different VIDIOC_DQEVENT ioctls: one using 32-bit time fields, one using 64-bit time fields (year 2038 safe). Test that each version (if available) reports sane values. This test is only run from the 32-bit version of v4l2-compliance. It currently only supports VIDIOC_DQEVENT and not yet the ioctls that use struct v4l2_buffer. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--utils/v4l2-compliance/Makefile.am2
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.cpp2
-rw-r--r--utils/v4l2-compliance/v4l2-compliance.h8
-rw-r--r--utils/v4l2-compliance/v4l2-test-time32-64.cpp182
4 files changed, 193 insertions, 1 deletions
diff --git a/utils/v4l2-compliance/Makefile.am b/utils/v4l2-compliance/Makefile.am
index 6baf1f5c..ef3ba919 100644
--- a/utils/v4l2-compliance/Makefile.am
+++ b/utils/v4l2-compliance/Makefile.am
@@ -13,7 +13,7 @@ v4l2_compliance_SOURCES = v4l2-compliance.cpp v4l2-compliance.h \
v4l2-test-debug.cpp v4l2-test-input-output.cpp \
v4l2-test-controls.cpp v4l2-test-io-config.cpp v4l2-test-formats.cpp v4l2-test-buffers.cpp \
v4l2-test-codecs.cpp v4l2-test-subdevs.cpp v4l2-test-media.cpp v4l2-test-colors.cpp \
- media-info.cpp v4l2-info.cpp
+ media-info.cpp v4l2-info.cpp v4l2-test-time32-64.cpp
v4l2_compliance_CPPFLAGS = -I$(top_srcdir)/utils/common $(GIT_SHA) $(GIT_COMMIT_CNT) $(GIT_COMMIT_DATE)
if WITH_V4L2_COMPLIANCE_LIBV4L
diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp
index a450d487..89923191 100644
--- a/utils/v4l2-compliance/v4l2-compliance.cpp
+++ b/utils/v4l2-compliance/v4l2-compliance.cpp
@@ -1346,6 +1346,8 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
if (node.can_capture)
node.set_interval(min_period);
printf("\ttest Requests: %s\n", ok(testRequests(&node, options[OptStreaming])));
+ if (sizeof(void *) == 4)
+ printf("\ttest TIME32/64: %s\n", ok(testTime32_64(&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 0b05fff7..1e8947d6 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -21,6 +21,10 @@
#ifndef _V4L2_COMPLIANCE_H_
#define _V4L2_COMPLIANCE_H_
+#include <map>
+#include <set>
+#include <string>
+
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
#include <linux/media.h>
@@ -362,6 +366,10 @@ int testReqBufs(struct node *node);
int testReadWrite(struct node *node);
int testExpBuf(struct node *node);
int testBlockingWait(struct node *node);
+
+// 32-bit architecture, 32/64-bit time_t tests
+int testTime32_64(struct node *node);
+
/*
* struct node node:
* the current media node being tested
diff --git a/utils/v4l2-compliance/v4l2-test-time32-64.cpp b/utils/v4l2-compliance/v4l2-test-time32-64.cpp
new file mode 100644
index 00000000..1c515ca3
--- /dev/null
+++ b/utils/v4l2-compliance/v4l2-test-time32-64.cpp
@@ -0,0 +1,182 @@
+/*
+ V4L2 API compliance time32/time64 ioctl tests.
+
+ Copyright (C) 2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+
+#include "compiler.h"
+#include "v4l2-compliance.h"
+
+typedef __s32 old_time32_t;
+
+struct old_timespec32 {
+ old_time32_t tv_sec;
+ __s32 tv_nsec;
+};
+
+struct old_timeval32 {
+ old_time32_t tv_sec;
+ __s32 tv_usec;
+};
+
+/*
+ * The user space interpretation of the 'v4l2_event' differs
+ * based on the 'time_t' definition on 32-bit architectures, so
+ * the kernel has to handle both.
+ * This is the old version for 32-bit architectures.
+ */
+struct v4l2_event_time32 {
+ __u32 type;
+ union {
+ struct v4l2_event_vsync vsync;
+ struct v4l2_event_ctrl ctrl;
+ struct v4l2_event_frame_sync frame_sync;
+ struct v4l2_event_src_change src_change;
+ struct v4l2_event_motion_det motion_det;
+ __u8 data[64];
+ } u;
+ __u32 pending;
+ __u32 sequence;
+ struct old_timespec32 timestamp;
+ __u32 id;
+ __u32 reserved[8];
+};
+
+#define VIDIOC_DQEVENT_TIME32 _IOR('V', 89, struct v4l2_event_time32)
+
+typedef __s64 new_time64_t;
+
+struct new_timespec64 {
+ new_time64_t tv_sec;
+ __s64 tv_nsec;
+};
+
+struct new_timeval64 {
+ new_time64_t tv_sec;
+ __s64 tv_usec;
+};
+
+struct v4l2_event_time64 {
+ __u32 type;
+ union {
+ struct v4l2_event_vsync vsync;
+ struct v4l2_event_ctrl ctrl;
+ struct v4l2_event_frame_sync frame_sync;
+ struct v4l2_event_src_change src_change;
+ struct v4l2_event_motion_det motion_det;
+ __u8 data[64];
+ } u;
+ __u32 pending;
+ __u32 sequence;
+ struct new_timespec64 timestamp;
+ __u32 id;
+ __u32 reserved[8];
+};
+
+#define VIDIOC_DQEVENT_TIME64 _IOR('V', 89, struct v4l2_event_time64)
+
+struct v4l2_buffer_time32 {
+ __u32 index;
+ __u32 type;
+ __u32 bytesused;
+ __u32 flags;
+ __u32 field;
+ struct old_timeval32 timestamp;
+ struct v4l2_timecode timecode;
+ __u32 sequence;
+
+ /* memory location */
+ __u32 memory;
+ union {
+ __u32 offset;
+ unsigned long userptr;
+ struct v4l2_plane *planes;
+ __s32 fd;
+ } m;
+ __u32 length;
+ __u32 reserved2;
+ union {
+ __s32 request_fd;
+ __u32 reserved;
+ };
+};
+#define VIDIOC_QUERYBUF_TIME32 _IOWR('V', 9, struct v4l2_buffer_time32)
+#define VIDIOC_QBUF_TIME32 _IOWR('V', 15, struct v4l2_buffer_time32)
+#define VIDIOC_DQBUF_TIME32 _IOWR('V', 17, struct v4l2_buffer_time32)
+#define VIDIOC_PREPARE_BUF_TIME32 _IOWR('V', 93, struct v4l2_buffer_time32)
+
+int testTime32_64(struct node *node)
+{
+ struct v4l2_event_subscription sub = { 0 };
+ struct v4l2_event_time32 ev32;
+ struct v4l2_event_time64 ev64;
+ struct v4l2_event ev;
+ qctrl_map::iterator iter;
+
+ if (node->controls.empty())
+ return 0;
+
+ fail_on_test(VIDIOC_DQEVENT != VIDIOC_DQEVENT_TIME32 &&
+ VIDIOC_DQEVENT != VIDIOC_DQEVENT_TIME64);
+
+ for (iter = node->controls.begin(); iter != node->controls.end(); ++iter) {
+ test_query_ext_ctrl &qctrl = iter->second;
+ if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ continue;
+
+ info("checking control event '%s' (0x%08x)\n", qctrl.name, qctrl.id);
+ sub.type = V4L2_EVENT_CTRL;
+ sub.id = qctrl.id;
+ sub.flags = V4L2_EVENT_SUB_FL_SEND_INITIAL;
+ fail_on_test(doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub));
+ fail_on_test(doioctl(node, VIDIOC_DQEVENT, &ev));
+ fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
+
+ fail_on_test(doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub));
+ int ret32 = doioctl(node, VIDIOC_DQEVENT_TIME32, &ev32);
+ fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
+
+ fail_on_test(doioctl(node, VIDIOC_SUBSCRIBE_EVENT, &sub));
+ int ret64 = doioctl(node, VIDIOC_DQEVENT_TIME64, &ev64);
+ fail_on_test(doioctl(node, VIDIOC_UNSUBSCRIBE_EVENT, &sub));
+
+ __u64 ev_ts = ev.timestamp.tv_sec * 1000000000ULL + ev.timestamp.tv_nsec;
+
+ if (ret32 != ENOTTY) {
+ fail_on_test(ret32);
+ fail_on_test(ev.type != ev32.type);
+ fail_on_test(ev.id != ev32.id);
+ fail_on_test(check_0(ev32.reserved, sizeof(ev32.reserved)));
+ __u64 ev32_ts = ev32.timestamp.tv_sec * 1000000000ULL + ev32.timestamp.tv_nsec;
+ __s64 delta_ms = (ev32_ts - ev_ts) / 1000000;
+ fail_on_test(delta_ms > 10);
+ info("VIDIOC_DQEVENT 32-bit timespec: %lld ms\n", delta_ms);
+ }
+
+ if (ret64 != ENOTTY) {
+ fail_on_test(ret64);
+ fail_on_test(ev.type != ev64.type);
+ fail_on_test(ev.id != ev64.id);
+ fail_on_test(check_0(ev64.reserved, sizeof(ev64.reserved)));
+ __u64 ev64_ts = ev64.timestamp.tv_sec * 1000000000ULL + ev64.timestamp.tv_nsec;
+ __s64 delta_ms = (ev64_ts - ev_ts) / 1000000;
+ fail_on_test(delta_ms > 10);
+ info("VIDIOC_DQEVENT 64-bit timespec: %lld ms\n", delta_ms);
+ }
+
+ break;
+ }
+ return 0;
+}