diff options
author | Arnd Bergmann <arnd@arndb.de> | 2019-12-16 15:15:03 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2020-01-03 15:47:57 +0100 |
commit | 1a6c0b36dd19c51cdd76895d009c5deba2286ebb (patch) | |
tree | 0da2a0a378af85d587368746db2a2ea8af437487 /drivers/media/v4l2-core/v4l2-ioctl.c | |
parent | c8ef1a6076bfb986052ff8fd8f5eb3b3a3f1048e (diff) | |
download | linux-1a6c0b36dd19c51cdd76895d009c5deba2286ebb.tar.gz linux-1a6c0b36dd19c51cdd76895d009c5deba2286ebb.tar.bz2 linux-1a6c0b36dd19c51cdd76895d009c5deba2286ebb.zip |
media: v4l2-core: fix VIDIOC_DQEVENT for time64 ABI
The v4l2_event structure contains a 'struct timespec' member that is
defined by the user space C library, creating an ABI incompatibility
when that gets updated to a 64-bit time_t.
While passing a 32-bit time_t here would be sufficient for CLOCK_MONOTONIC
timestamps, simply redefining the structure to use the kernel's
__kernel_old_timespec would not work for any library that uses a copy
of the linux/videodev2.h header file rather than including the copy from
the latest kernel headers.
This means the kernel has to be changed to handle both versions of the
structure layout on a 32-bit architecture. The easiest way to do this
is during the copy from/to user space.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ioctl.c')
-rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 1f22b1355778..f13b232e6c31 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -821,7 +821,7 @@ static void v4l_print_event(const void *arg, bool write_only) const struct v4l2_event *p = arg; const struct v4l2_event_ctrl *c; - pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, timestamp=%lu.%9.9lu\n", + pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, timestamp=%llu.%9.9llu\n", p->type, p->pending, p->sequence, p->id, p->timestamp.tv_sec, p->timestamp.tv_nsec); switch (p->type) { @@ -3025,6 +3025,13 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, static unsigned int video_translate_cmd(unsigned int cmd) { + switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT_TIME32: + return VIDIOC_DQEVENT; +#endif + } + return cmd; } @@ -3074,6 +3081,26 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd) return 0; switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT_TIME32: { + struct v4l2_event *ev = parg; + struct v4l2_event_time32 ev32 = { + .type = ev->type, + .pending = ev->pending, + .sequence = ev->sequence, + .timestamp.tv_sec = ev->timestamp.tv_sec, + .timestamp.tv_nsec = ev->timestamp.tv_nsec, + .id = ev->id, + }; + + memcpy(&ev32.u, &ev->u, sizeof(ev->u)); + memcpy(&ev32.reserved, &ev->reserved, sizeof(ev->reserved)); + + if (copy_to_user(arg, &ev32, sizeof(ev32))) + return -EFAULT; + break; + } +#endif default: /* Copy results into user buffer */ if (copy_to_user(arg, parg, _IOC_SIZE(cmd))) |