diff options
author | Hans Verkuil <hverkuil-cisco@xs4all.nl> | 2021-09-03 10:59:04 +0200 |
---|---|---|
committer | Hans Verkuil <hverkuil-cisco@xs4all.nl> | 2021-09-03 10:59:04 +0200 |
commit | 05a468e033af0e4c775aaa10fe4d02c45de698ae (patch) | |
tree | 0bfa41cca05127baafcb1eb77aa308c0137d5e50 | |
parent | cd769da3e1c2c4f4263f6fd9ad8c0f928219243f (diff) | |
download | v4l-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.am | 2 | ||||
-rw-r--r-- | utils/v4l2-compliance/v4l2-compliance.cpp | 2 | ||||
-rw-r--r-- | utils/v4l2-compliance/v4l2-compliance.h | 8 | ||||
-rw-r--r-- | utils/v4l2-compliance/v4l2-test-time32-64.cpp | 182 |
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; +} |