aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/v4l2-core/v4l2-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ioctl.c')
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c184
1 files changed, 116 insertions, 68 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index eeff398fbdcc..3198abdd538c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -8,6 +8,7 @@
* Mauro Carvalho Chehab <mchehab@kernel.org> (version 2)
*/
+#include <linux/compat.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -1402,6 +1403,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break;
case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break;
case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break;
+ case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break;
+ case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break;
default:
/* Compressed formats */
@@ -1581,7 +1584,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
- struct v4l2_clip __user *clips = p->fmt.win.clips;
+ struct v4l2_clip *clips = p->fmt.win.clips;
u32 clipcount = p->fmt.win.clipcount;
void __user *bitmap = p->fmt.win.bitmap;
@@ -3083,6 +3086,27 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
}
break;
}
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT: {
+ struct v4l2_format *fmt = parg;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_OVERLAY &&
+ fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+ break;
+ if (fmt->fmt.win.clipcount > 2048)
+ return -EINVAL;
+ if (!fmt->fmt.win.clipcount)
+ break;
+
+ *user_ptr = (void __user *)fmt->fmt.win.clips;
+ *kernel_ptr = (void **)&fmt->fmt.win.clips;
+ *array_size = sizeof(struct v4l2_clip)
+ * fmt->fmt.win.clipcount;
+
+ ret = 1;
+ break;
+ }
}
return ret;
@@ -3104,14 +3128,18 @@ static unsigned int video_translate_cmd(unsigned int cmd)
return VIDIOC_PREPARE_BUF;
#endif
}
+ if (in_compat_syscall())
+ return v4l2_compat_translate_cmd(cmd);
return cmd;
}
-static int video_get_user(void __user *arg, void *parg, unsigned int cmd,
+static int video_get_user(void __user *arg, void *parg,
+ unsigned int real_cmd, unsigned int cmd,
bool *always_copy)
{
- unsigned int n = _IOC_SIZE(cmd);
+ unsigned int n = _IOC_SIZE(real_cmd);
+ int err = 0;
if (!(_IOC_DIR(cmd) & _IOC_WRITE)) {
/* read-only ioctl */
@@ -3119,73 +3147,82 @@ static int video_get_user(void __user *arg, void *parg, unsigned int cmd,
return 0;
}
- 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;
+ /*
+ * In some cases, only a few fields are used as input,
+ * i.e. when the app sets "index" and then the driver
+ * fills in the rest of the structure for the thing
+ * with that index. We only need to copy up the first
+ * non-input field.
+ */
+ if (v4l2_is_known_ioctl(real_cmd)) {
+ u32 flags = v4l2_ioctls[_IOC_NR(real_cmd)].flags;
- break;
+ if (flags & INFO_FL_CLEAR_MASK)
+ n = (flags & INFO_FL_CLEAR_MASK) >> 16;
+ *always_copy = flags & INFO_FL_ALWAYS_COPY;
}
-#endif
- default:
- /*
- * In some cases, only a few fields are used as input,
- * i.e. when the app sets "index" and then the driver
- * fills in the rest of the structure for the thing
- * with that index. We only need to copy up the first
- * non-input field.
- */
- if (v4l2_is_known_ioctl(cmd)) {
- u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags;
-
- if (flags & INFO_FL_CLEAR_MASK)
- n = (flags & INFO_FL_CLEAR_MASK) >> 16;
- *always_copy = flags & INFO_FL_ALWAYS_COPY;
- }
+ if (cmd == real_cmd) {
if (copy_from_user(parg, (void __user *)arg, n))
- return -EFAULT;
-
- /* zero out anything we don't copy from userspace */
- if (n < _IOC_SIZE(cmd))
- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
- break;
+ err = -EFAULT;
+ } else if (in_compat_syscall()) {
+ err = v4l2_compat_get_user(arg, parg, cmd);
+ } else {
+ 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,
+ };
+ break;
+ }
+#endif
+ }
}
- return 0;
+ /* zero out anything we don't copy from userspace */
+ if (!err && n < _IOC_SIZE(real_cmd))
+ memset((u8 *)parg + n, 0, _IOC_SIZE(real_cmd) - n);
+ return err;
}
-static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
+static int video_put_user(void __user *arg, void *parg,
+ unsigned int real_cmd, unsigned int cmd)
{
if (!(_IOC_DIR(cmd) & _IOC_READ))
return 0;
+ if (cmd == real_cmd) {
+ /* Copy results into user buffer */
+ if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ return 0;
+ }
+
+ if (in_compat_syscall())
+ return v4l2_compat_put_user(arg, parg, cmd);
+
switch (cmd) {
#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_DQEVENT_TIME32: {
@@ -3236,11 +3273,6 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
break;
}
#endif
- default:
- /* Copy results into user buffer */
- if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
- return -EFAULT;
- break;
}
return 0;
@@ -3274,8 +3306,8 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
parg = mbuf;
}
- err = video_get_user((void __user *)arg, parg, orig_cmd,
- &always_copy);
+ err = video_get_user((void __user *)arg, parg, cmd,
+ orig_cmd, &always_copy);
if (err)
goto out;
}
@@ -3297,7 +3329,14 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
if (NULL == mbuf)
goto out_array_args;
err = -EFAULT;
- if (copy_from_user(mbuf, user_ptr, array_size))
+ if (in_compat_syscall())
+ err = v4l2_compat_get_array_args(file, mbuf, user_ptr,
+ array_size, orig_cmd,
+ parg);
+ else
+ err = copy_from_user(mbuf, user_ptr, array_size) ?
+ -EFAULT : 0;
+ if (err)
goto out_array_args;
*kernel_ptr = mbuf;
}
@@ -3318,8 +3357,17 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
if (has_array_args) {
*kernel_ptr = (void __force *)user_ptr;
- if (copy_to_user(user_ptr, mbuf, array_size))
+ if (in_compat_syscall()) {
+ int put_err;
+
+ put_err = v4l2_compat_put_array_args(file, user_ptr, mbuf,
+ array_size, orig_cmd,
+ parg);
+ if (put_err)
+ err = put_err;
+ } else if (copy_to_user(user_ptr, mbuf, array_size)) {
err = -EFAULT;
+ }
goto out_array_args;
}
/*
@@ -3330,7 +3378,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
goto out;
out_array_args:
- if (video_put_user((void __user *)arg, parg, orig_cmd))
+ if (video_put_user((void __user *)arg, parg, cmd, orig_cmd))
err = -EFAULT;
out:
kvfree(mbuf);