forked from Minki/linux
media: v4l2-core: fix v4l2_buffer handling for time64 ABI
The v4l2_buffer structure contains a 'struct timeval' member that is defined by the user space C library, creating an ABI incompatibility when that gets updated to a 64-bit time_t. As in v4l2_event, handle this with a special case in video_put_user() and video_get_user() to replace the memcpy there. Since the structure also contains a pointer, there are now two native versions (on 32-bit systems) as well as two compat versions (on 64-bit systems), which unfortunately complicates the compat handler quite a bit. Duplicating the existing handlers for the new types is a safe conversion for now, but unfortunately this may turn into a maintenance burden later. A larger-scale rework of the compat code might be a better alternative, but is out of scope of the y2038 work. Sparc64 needs a special case because of their special suseconds_t definition. 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>
This commit is contained in:
parent
1a6c0b36dd
commit
577c89b0ce
@ -474,10 +474,10 @@ static void v4l_print_buffer(const void *arg, bool write_only)
|
||||
const struct v4l2_plane *plane;
|
||||
int i;
|
||||
|
||||
pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
|
||||
p->timestamp.tv_sec / 3600,
|
||||
(int)(p->timestamp.tv_sec / 60) % 60,
|
||||
(int)(p->timestamp.tv_sec % 60),
|
||||
pr_cont("%02d:%02d:%02d.%09ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
|
||||
(int)p->timestamp.tv_sec / 3600,
|
||||
((int)p->timestamp.tv_sec / 60) % 60,
|
||||
((int)p->timestamp.tv_sec % 60),
|
||||
(long)p->timestamp.tv_usec,
|
||||
p->index,
|
||||
prt_names(p->type, v4l2_type_names), p->request_fd,
|
||||
@ -3029,6 +3029,14 @@ static unsigned int video_translate_cmd(unsigned int cmd)
|
||||
#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
case VIDIOC_DQEVENT_TIME32:
|
||||
return VIDIOC_DQEVENT;
|
||||
case VIDIOC_QUERYBUF_TIME32:
|
||||
return VIDIOC_QUERYBUF;
|
||||
case VIDIOC_QBUF_TIME32:
|
||||
return VIDIOC_QBUF;
|
||||
case VIDIOC_DQBUF_TIME32:
|
||||
return VIDIOC_DQBUF;
|
||||
case VIDIOC_PREPARE_BUF_TIME32:
|
||||
return VIDIOC_PREPARE_BUF;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3047,6 +3055,39 @@ static int video_get_user(void __user *arg, void *parg, unsigned int cmd,
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
case VIDIOC_QUERYBUF_TIME32:
|
||||
case VIDIOC_QBUF_TIME32:
|
||||
case VIDIOC_DQBUF_TIME32:
|
||||
case VIDIOC_PREPARE_BUF_TIME32: {
|
||||
struct v4l2_buffer_time32 vb32;
|
||||
struct v4l2_buffer *vb = parg;
|
||||
|
||||
if (copy_from_user(&vb32, arg, sizeof(vb32)))
|
||||
return -EFAULT;
|
||||
|
||||
*vb = (struct v4l2_buffer) {
|
||||
.index = vb32.index,
|
||||
.type = vb32.type,
|
||||
.bytesused = vb32.bytesused,
|
||||
.flags = vb32.flags,
|
||||
.field = vb32.field,
|
||||
.timestamp.tv_sec = vb32.timestamp.tv_sec,
|
||||
.timestamp.tv_usec = vb32.timestamp.tv_usec,
|
||||
.timecode = vb32.timecode,
|
||||
.sequence = vb32.sequence,
|
||||
.memory = vb32.memory,
|
||||
.m.userptr = vb32.m.userptr,
|
||||
.length = vb32.length,
|
||||
.request_fd = vb32.request_fd,
|
||||
};
|
||||
|
||||
if (cmd == VIDIOC_QUERYBUF_TIME32)
|
||||
vb->request_fd = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
/*
|
||||
* In some cases, only a few fields are used as input,
|
||||
@ -3100,6 +3141,31 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
case VIDIOC_QUERYBUF_TIME32:
|
||||
case VIDIOC_QBUF_TIME32:
|
||||
case VIDIOC_DQBUF_TIME32:
|
||||
case VIDIOC_PREPARE_BUF_TIME32: {
|
||||
struct v4l2_buffer *vb = parg;
|
||||
struct v4l2_buffer_time32 vb32 = {
|
||||
.index = vb->index,
|
||||
.type = vb->type,
|
||||
.bytesused = vb->bytesused,
|
||||
.flags = vb->flags,
|
||||
.field = vb->field,
|
||||
.timestamp.tv_sec = vb->timestamp.tv_sec,
|
||||
.timestamp.tv_usec = vb->timestamp.tv_usec,
|
||||
.timecode = vb->timecode,
|
||||
.sequence = vb->sequence,
|
||||
.memory = vb->memory,
|
||||
.m.userptr = vb->m.userptr,
|
||||
.length = vb->length,
|
||||
.request_fd = vb->request_fd,
|
||||
};
|
||||
|
||||
if (copy_to_user(arg, &vb32, sizeof(vb32)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
/* Copy results into user buffer */
|
||||
|
@ -749,4 +749,34 @@ struct v4l2_event_time32 {
|
||||
|
||||
#define VIDIOC_DQEVENT_TIME32 _IOR('V', 89, struct v4l2_event_time32)
|
||||
|
||||
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)
|
||||
|
||||
#endif /* _V4L2_IOCTL_H */
|
||||
|
@ -912,6 +912,25 @@ struct v4l2_jpegcompression {
|
||||
/*
|
||||
* M E M O R Y - M A P P I N G B U F F E R S
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/*
|
||||
* This corresponds to the user space version of timeval
|
||||
* for 64-bit time_t. sparc64 is different from everyone
|
||||
* else, using the microseconds in the wrong half of the
|
||||
* second 64-bit word.
|
||||
*/
|
||||
struct __kernel_v4l2_timeval {
|
||||
long long tv_sec;
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
int tv_usec;
|
||||
int __pad;
|
||||
#else
|
||||
long long tv_usec;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
struct v4l2_requestbuffers {
|
||||
__u32 count;
|
||||
__u32 type; /* enum v4l2_buf_type */
|
||||
@ -997,7 +1016,11 @@ struct v4l2_buffer {
|
||||
__u32 bytesused;
|
||||
__u32 flags;
|
||||
__u32 field;
|
||||
#ifdef __KERNEL__
|
||||
struct __kernel_v4l2_timeval timestamp;
|
||||
#else
|
||||
struct timeval timestamp;
|
||||
#endif
|
||||
struct v4l2_timecode timecode;
|
||||
__u32 sequence;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user