| /* |
| 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_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; |
| } |