/* V4L2 API compliance time32/time64 ioctl tests. Copyright (C) 2021 Hans Verkuil 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 #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; if (node->controls.empty()) return 0; fail_on_test(VIDIOC_DQEVENT != VIDIOC_DQEVENT_TIME32 && VIDIOC_DQEVENT != VIDIOC_DQEVENT_TIME64); for (const auto &control : node->controls) { const test_query_ext_ctrl &qctrl = control.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_val(delta_ms > 500, (int)delta_ms); 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_val(delta_ms > 500, (int)delta_ms); info("VIDIOC_DQEVENT 64-bit timespec: %lld ms\n", delta_ms); } break; } return 0; }