Commit 50085270 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Mauro Carvalho Chehab

media: v4l2: remaining compat handlers

There are eight remaining ioctl commands handled by copying
incompatible data structures in v4l2_compat_ioctl32(),
all of them fairly simple.

Change them to instead go through the native ioctl
infrastructure and only special-case the data copy.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 566f960d
......@@ -338,27 +338,23 @@ struct v4l2_standard32 {
__u32 reserved[4];
};
static int get_v4l2_standard32(struct v4l2_standard __user *p64,
static int get_v4l2_standard32(struct v4l2_standard *p64,
struct v4l2_standard32 __user *p32)
{
/* other fields are not set by the user, nor used by the driver */
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p64->index, &p32->index))
return -EFAULT;
return 0;
return get_user(p64->index, &p32->index);
}
static int put_v4l2_standard32(struct v4l2_standard __user *p64,
static int put_v4l2_standard32(struct v4l2_standard *p64,
struct v4l2_standard32 __user *p32)
{
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p32->index, &p64->index) ||
assign_in_user(&p32->id, &p64->id) ||
copy_in_user(p32->name, p64->name, sizeof(p32->name)) ||
copy_in_user(&p32->frameperiod, &p64->frameperiod,
if (put_user(p64->index, &p32->index) ||
put_user(p64->id, &p32->id) ||
copy_to_user(p32->name, p64->name, sizeof(p32->name)) ||
copy_to_user(&p32->frameperiod, &p64->frameperiod,
sizeof(p32->frameperiod)) ||
assign_in_user(&p32->framelines, &p64->framelines) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
put_user(p64->framelines, &p32->framelines) ||
copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}
......@@ -689,33 +685,30 @@ struct v4l2_framebuffer32 {
} fmt;
};
static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
struct v4l2_framebuffer32 __user *p32)
{
compat_caddr_t tmp;
if (!access_ok(p32, sizeof(*p32)) ||
get_user(tmp, &p32->base) ||
put_user_force(compat_ptr(tmp), &p64->base) ||
assign_in_user(&p64->capability, &p32->capability) ||
assign_in_user(&p64->flags, &p32->flags) ||
copy_in_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
if (get_user(tmp, &p32->base) ||
get_user(p64->capability, &p32->capability) ||
get_user(p64->flags, &p32->flags) ||
copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
return -EFAULT;
p64->base = (void __force *)compat_ptr(tmp);
return 0;
}
static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
static int put_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
struct v4l2_framebuffer32 __user *p32)
{
void *base;
if (!access_ok(p32, sizeof(*p32)) ||
get_user(base, &p64->base) ||
put_user(ptr_to_compat((void __user *)base), &p32->base) ||
assign_in_user(&p32->capability, &p64->capability) ||
assign_in_user(&p32->flags, &p64->flags) ||
copy_in_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
if (put_user((uintptr_t)p64->base, &p32->base) ||
put_user(p64->capability, &p32->capability) ||
put_user(p64->flags, &p32->flags) ||
copy_to_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
return -EFAULT;
return 0;
}
......@@ -735,18 +728,18 @@ struct v4l2_input32 {
* The 64-bit v4l2_input struct has extra padding at the end of the struct.
* Otherwise it is identical to the 32-bit version.
*/
static inline int get_v4l2_input32(struct v4l2_input __user *p64,
static inline int get_v4l2_input32(struct v4l2_input *p64,
struct v4l2_input32 __user *p32)
{
if (copy_in_user(p64, p32, sizeof(*p32)))
if (copy_from_user(p64, p32, sizeof(*p32)))
return -EFAULT;
return 0;
}
static inline int put_v4l2_input32(struct v4l2_input __user *p64,
static inline int put_v4l2_input32(struct v4l2_input *p64,
struct v4l2_input32 __user *p32)
{
if (copy_in_user(p32, p64, sizeof(*p32)))
if (copy_to_user(p32, p64, sizeof(*p32)))
return -EFAULT;
return 0;
}
......@@ -880,38 +873,38 @@ struct v4l2_event32_time32 {
__u32 reserved[8];
};
static int put_v4l2_event32(struct v4l2_event __user *p64,
static int put_v4l2_event32(struct v4l2_event *p64,
struct v4l2_event32 __user *p32)
{
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p32->type, &p64->type) ||
copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) ||
assign_in_user(&p32->pending, &p64->pending) ||
assign_in_user(&p32->sequence, &p64->sequence) ||
assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) ||
assign_in_user(&p32->id, &p64->id) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
if (put_user(p64->type, &p32->type) ||
copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
put_user(p64->pending, &p32->pending) ||
put_user(p64->sequence, &p32->sequence) ||
put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
put_user(p64->id, &p32->id) ||
copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}
static int put_v4l2_event32_time32(struct v4l2_event_time32 __user *p64,
#ifdef CONFIG_COMPAT_32BIT_TIME
static int put_v4l2_event32_time32(struct v4l2_event *p64,
struct v4l2_event32_time32 __user *p32)
{
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p32->type, &p64->type) ||
copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) ||
assign_in_user(&p32->pending, &p64->pending) ||
assign_in_user(&p32->sequence, &p64->sequence) ||
assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) ||
assign_in_user(&p32->id, &p64->id) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
if (put_user(p64->type, &p32->type) ||
copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
put_user(p64->pending, &p32->pending) ||
put_user(p64->sequence, &p32->sequence) ||
put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
put_user(p64->id, &p32->id) ||
copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
return -EFAULT;
return 0;
}
#endif
#endif
struct v4l2_edid32 {
__u32 pad;
......@@ -921,34 +914,23 @@ struct v4l2_edid32 {
compat_caddr_t edid;
};
static int get_v4l2_edid32(struct v4l2_edid __user *p64,
static int get_v4l2_edid32(struct v4l2_edid *p64,
struct v4l2_edid32 __user *p32)
{
compat_uptr_t tmp;
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p64->pad, &p32->pad) ||
assign_in_user(&p64->start_block, &p32->start_block) ||
assign_in_user_cast(&p64->blocks, &p32->blocks) ||
get_user(tmp, &p32->edid) ||
put_user_force(compat_ptr(tmp), &p64->edid) ||
copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved)))
compat_uptr_t edid;
if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) ||
get_user(edid, &p32->edid))
return -EFAULT;
p64->edid = (void __force *)compat_ptr(edid);
return 0;
}
static int put_v4l2_edid32(struct v4l2_edid __user *p64,
static int put_v4l2_edid32(struct v4l2_edid *p64,
struct v4l2_edid32 __user *p32)
{
void *edid;
if (!access_ok(p32, sizeof(*p32)) ||
assign_in_user(&p32->pad, &p64->pad) ||
assign_in_user(&p32->start_block, &p64->start_block) ||
assign_in_user(&p32->blocks, &p64->blocks) ||
get_user(edid, &p64->edid) ||
put_user(ptr_to_compat((void __user *)edid), &p32->edid) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid)))
return -EFAULT;
return 0;
}
......@@ -994,6 +976,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
return VIDIOC_S_FMT;
case VIDIOC_TRY_FMT32:
return VIDIOC_TRY_FMT;
case VIDIOC_G_FBUF32:
return VIDIOC_G_FBUF;
case VIDIOC_S_FBUF32:
return VIDIOC_S_FBUF;
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
return VIDIOC_QUERYBUF;
......@@ -1020,6 +1006,22 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
return VIDIOC_TRY_EXT_CTRLS;
case VIDIOC_PREPARE_BUF32:
return VIDIOC_PREPARE_BUF;
case VIDIOC_ENUMSTD32:
return VIDIOC_ENUMSTD;
case VIDIOC_ENUMINPUT32:
return VIDIOC_ENUMINPUT;
case VIDIOC_G_EDID32:
return VIDIOC_G_EDID;
case VIDIOC_S_EDID32:
return VIDIOC_S_EDID;
#ifdef CONFIG_X86_64
case VIDIOC_DQEVENT32:
return VIDIOC_DQEVENT;
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_DQEVENT32_TIME32:
return VIDIOC_DQEVENT;
#endif
#endif
}
return cmd;
}
......@@ -1031,6 +1033,9 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_S_FMT32:
case VIDIOC_TRY_FMT32:
return get_v4l2_format32(parg, arg);
case VIDIOC_S_FBUF32:
return get_v4l2_framebuffer32(parg, arg);
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
......@@ -1051,6 +1056,16 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_CREATE_BUFS32:
return get_v4l2_create32(parg, arg);
case VIDIOC_ENUMSTD32:
return get_v4l2_standard32(parg, arg);
case VIDIOC_ENUMINPUT32:
return get_v4l2_input32(parg, arg);
case VIDIOC_G_EDID32:
case VIDIOC_S_EDID32:
return get_v4l2_edid32(parg, arg);
}
return 0;
}
......@@ -1062,6 +1077,9 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_S_FMT32:
case VIDIOC_TRY_FMT32:
return put_v4l2_format32(parg, arg);
case VIDIOC_G_FBUF32:
return put_v4l2_framebuffer32(parg, arg);
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF32_TIME32:
case VIDIOC_QBUF32_TIME32:
......@@ -1082,6 +1100,24 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
case VIDIOC_CREATE_BUFS32:
return put_v4l2_create32(parg, arg);
case VIDIOC_ENUMSTD32:
return put_v4l2_standard32(parg, arg);
case VIDIOC_ENUMINPUT32:
return put_v4l2_input32(parg, arg);
case VIDIOC_G_EDID32:
case VIDIOC_S_EDID32:
return put_v4l2_edid32(parg, arg);
#ifdef CONFIG_X86_64
case VIDIOC_DQEVENT32:
return put_v4l2_event32(parg, arg);
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_DQEVENT32_TIME32:
return put_v4l2_event32_time32(parg, arg);
#endif
#endif
}
return 0;
}
......@@ -1327,16 +1363,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
* 1. When struct size is different, converts the command.
*/
switch (cmd) {
case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break;
case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break;
case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break;
case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break;
#ifdef CONFIG_X86_64
case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break;
case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break;
#endif
case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break;
case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break;
default: ncmd = cmd; break;
}
......@@ -1346,53 +1372,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
* argument into it.
*/
switch (cmd) {
case VIDIOC_G_EDID32:
case VIDIOC_S_EDID32:
err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
if (!err)
err = get_v4l2_edid32(new_p64, p32);
compatible_arg = 0;
break;
case VIDIOC_S_FBUF32:
err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
&new_p64);
if (!err)
err = get_v4l2_framebuffer32(new_p64, p32);
compatible_arg = 0;
break;
case VIDIOC_G_FBUF32:
err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
&new_p64);
compatible_arg = 0;
break;
case VIDIOC_ENUMSTD32:
err = alloc_userspace(sizeof(struct v4l2_standard), 0,
&new_p64);
if (!err)
err = get_v4l2_standard32(new_p64, p32);
compatible_arg = 0;
break;
case VIDIOC_ENUMINPUT32:
err = alloc_userspace(sizeof(struct v4l2_input), 0, &new_p64);
if (!err)
err = get_v4l2_input32(new_p64, p32);
compatible_arg = 0;
break;
#ifdef CONFIG_X86_64
case VIDIOC_DQEVENT32:
err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64);
compatible_arg = 0;
break;
case VIDIOC_DQEVENT32_TIME32:
err = alloc_userspace(sizeof(struct v4l2_event_time32), 0, &new_p64);
compatible_arg = 0;
break;
#endif
}
if (err)
return err;
......@@ -1414,55 +1393,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
if (err == -ENOTTY)
return err;
/*
* 4. Special case: even after an error we need to put the
* results back for some ioctls.
*
* In the case of EXT_CTRLS, the error_idx will contain information
* on which control failed.
*
* In the case of S_EDID, the driver can return E2BIG and set
* the blocks to maximum allowed value.
*/
switch (cmd) {
case VIDIOC_S_EDID32:
if (put_v4l2_edid32(new_p64, p32))
err = -EFAULT;
break;
}
if (err)
return err;
/*
* 5. Copy the data returned at the 64 bits userspace pointer to
* the original 32 bits structure.
*/
switch (cmd) {
case VIDIOC_G_FBUF32:
err = put_v4l2_framebuffer32(new_p64, p32);
break;
#ifdef CONFIG_X86_64
case VIDIOC_DQEVENT32:
err = put_v4l2_event32(new_p64, p32);
break;
case VIDIOC_DQEVENT32_TIME32:
err = put_v4l2_event32_time32(new_p64, p32);
break;
#endif
case VIDIOC_G_EDID32:
err = put_v4l2_edid32(new_p64, p32);
break;
case VIDIOC_ENUMSTD32:
err = put_v4l2_standard32(new_p64, p32);
break;
case VIDIOC_ENUMINPUT32:
err = put_v4l2_input32(new_p64, p32);
break;
}
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment