summaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch')
-rw-r--r--recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch297
1 files changed, 297 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch b/recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
new file mode 100644
index 0000000000..f212020188
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.37/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
@@ -0,0 +1,297 @@
+From d71c2e533be956a95e4ddde8b87f657ada3c9de3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 12 Jul 2010 16:09:41 +0200
+Subject: [PATCH 01/43] v4l: Share code between video_usercopy and video_ioctl2
+
+The two functions are mostly identical. They handle the copy_from_user
+and copy_to_user operations related with V4L2 ioctls and call the real
+ioctl handler.
+
+Create a __video_usercopy function that implements the core of
+video_usercopy and video_ioctl2, and call that function from both.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-ioctl.c | 218 ++++++++++++-------------------------
+ 1 files changed, 71 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index dd9283f..1e01554 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -374,35 +374,62 @@ video_fix_command(unsigned int cmd)
+ }
+ #endif
+
+-/*
+- * Obsolete usercopy function - Should be removed soon
+- */
+-long
+-video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++/* 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. */
++static unsigned long cmd_input_size(unsigned int cmd)
++{
++ /* Size of structure up to and including 'field' */
++#define CMDINSIZE(cmd, type, field) \
++ case VIDIOC_##cmd: \
++ return offsetof(struct v4l2_##type, field) + \
++ sizeof(((struct v4l2_##type *)0)->field);
++
++ switch (cmd) {
++ CMDINSIZE(ENUM_FMT, fmtdesc, type);
++ CMDINSIZE(G_FMT, format, type);
++ CMDINSIZE(QUERYBUF, buffer, type);
++ CMDINSIZE(G_PARM, streamparm, type);
++ CMDINSIZE(ENUMSTD, standard, index);
++ CMDINSIZE(ENUMINPUT, input, index);
++ CMDINSIZE(G_CTRL, control, id);
++ CMDINSIZE(G_TUNER, tuner, index);
++ CMDINSIZE(QUERYCTRL, queryctrl, id);
++ CMDINSIZE(QUERYMENU, querymenu, index);
++ CMDINSIZE(ENUMOUTPUT, output, index);
++ CMDINSIZE(G_MODULATOR, modulator, index);
++ CMDINSIZE(G_FREQUENCY, frequency, tuner);
++ CMDINSIZE(CROPCAP, cropcap, type);
++ CMDINSIZE(G_CROP, crop, type);
++ CMDINSIZE(ENUMAUDIO, audio, index);
++ CMDINSIZE(ENUMAUDOUT, audioout, index);
++ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
++ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
++ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
++ default:
++ return _IOC_SIZE(cmd);
++ }
++}
++
++static long
++__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ v4l2_kioctl func)
+ {
+ char sbuf[128];
+ void *mbuf = NULL;
+- void *parg = NULL;
++ void *parg = (void *)arg;
+ long err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+
+-#ifdef __OLD_VIDIOC_
+- cmd = video_fix_command(cmd);
+-#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+- switch (_IOC_DIR(cmd)) {
+- case _IOC_NONE:
+- parg = NULL;
+- break;
+- case _IOC_READ:
+- case _IOC_WRITE:
+- case (_IOC_WRITE | _IOC_READ):
++ if (_IOC_DIR(cmd) != _IOC_NONE) {
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+@@ -414,11 +441,21 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ }
+
+ err = -EFAULT;
+- if (_IOC_DIR(cmd) & _IOC_WRITE)
+- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
++ if (_IOC_DIR(cmd) & _IOC_WRITE) {
++ unsigned long n = cmd_input_size(cmd);
++
++ if (copy_from_user(parg, (void __user *)arg, n))
+ goto out;
+- break;
++
++ /* zero out anything we don't copy from userspace */
++ if (n < _IOC_SIZE(cmd))
++ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
++ } else {
++ /* read-only ioctl */
++ memset(parg, 0, _IOC_SIZE(cmd));
++ }
+ }
++
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+@@ -440,7 +477,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ }
+ }
+
+- /* call driver */
++ /* Handles IOCTL */
+ err = func(file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -EINVAL;
+@@ -469,6 +506,19 @@ out:
+ kfree(mbuf);
+ return err;
+ }
++
++/*
++ * Obsolete usercopy function - Should be removed soon
++ */
++long
++video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++ v4l2_kioctl func)
++{
++#ifdef __OLD_VIDIOC_
++ cmd = video_fix_command(cmd);
++#endif
++ return __video_usercopy(file, cmd, arg, func);
++}
+ EXPORT_SYMBOL(video_usercopy);
+
+ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+@@ -2041,138 +2091,12 @@ static long __video_do_ioctl(struct file *file,
+ return ret;
+ }
+
+-/* 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. */
+-static unsigned long cmd_input_size(unsigned int cmd)
+-{
+- /* Size of structure up to and including 'field' */
+-#define CMDINSIZE(cmd, type, field) \
+- case VIDIOC_##cmd: \
+- return offsetof(struct v4l2_##type, field) + \
+- sizeof(((struct v4l2_##type *)0)->field);
+-
+- switch (cmd) {
+- CMDINSIZE(ENUM_FMT, fmtdesc, type);
+- CMDINSIZE(G_FMT, format, type);
+- CMDINSIZE(QUERYBUF, buffer, type);
+- CMDINSIZE(G_PARM, streamparm, type);
+- CMDINSIZE(ENUMSTD, standard, index);
+- CMDINSIZE(ENUMINPUT, input, index);
+- CMDINSIZE(G_CTRL, control, id);
+- CMDINSIZE(G_TUNER, tuner, index);
+- CMDINSIZE(QUERYCTRL, queryctrl, id);
+- CMDINSIZE(QUERYMENU, querymenu, index);
+- CMDINSIZE(ENUMOUTPUT, output, index);
+- CMDINSIZE(G_MODULATOR, modulator, index);
+- CMDINSIZE(G_FREQUENCY, frequency, tuner);
+- CMDINSIZE(CROPCAP, cropcap, type);
+- CMDINSIZE(G_CROP, crop, type);
+- CMDINSIZE(ENUMAUDIO, audio, index);
+- CMDINSIZE(ENUMAUDOUT, audioout, index);
+- CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
+- CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
+- CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
+- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
+- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
+- default:
+- return _IOC_SIZE(cmd);
+- }
+-}
+-
+ long video_ioctl2(struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+- char sbuf[128];
+- void *mbuf = NULL;
+- void *parg = (void *)arg;
+- long err = -EINVAL;
+- int is_ext_ctrl;
+- size_t ctrls_size = 0;
+- void __user *user_ptr = NULL;
+-
+ #ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+ #endif
+- is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+- cmd == VIDIOC_TRY_EXT_CTRLS);
+-
+- /* Copy arguments into temp kernel buffer */
+- if (_IOC_DIR(cmd) != _IOC_NONE) {
+- if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+- parg = sbuf;
+- } else {
+- /* too big to allocate from stack */
+- mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+- if (NULL == mbuf)
+- return -ENOMEM;
+- parg = mbuf;
+- }
+-
+- err = -EFAULT;
+- if (_IOC_DIR(cmd) & _IOC_WRITE) {
+- unsigned long n = cmd_input_size(cmd);
+-
+- if (copy_from_user(parg, (void __user *)arg, n))
+- goto out;
+-
+- /* zero out anything we don't copy from userspace */
+- if (n < _IOC_SIZE(cmd))
+- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+- } else {
+- /* read-only ioctl */
+- memset(parg, 0, _IOC_SIZE(cmd));
+- }
+- }
+-
+- if (is_ext_ctrl) {
+- struct v4l2_ext_controls *p = parg;
+-
+- /* In case of an error, tell the caller that it wasn't
+- a specific control that caused it. */
+- p->error_idx = p->count;
+- user_ptr = (void __user *)p->controls;
+- if (p->count) {
+- ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+- /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+- mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+- err = -ENOMEM;
+- if (NULL == mbuf)
+- goto out_ext_ctrl;
+- err = -EFAULT;
+- if (copy_from_user(mbuf, user_ptr, ctrls_size))
+- goto out_ext_ctrl;
+- p->controls = mbuf;
+- }
+- }
+-
+- /* Handles IOCTL */
+- err = __video_do_ioctl(file, cmd, parg);
+- if (err == -ENOIOCTLCMD)
+- err = -EINVAL;
+- if (is_ext_ctrl) {
+- struct v4l2_ext_controls *p = parg;
+-
+- p->controls = (void *)user_ptr;
+- if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+- err = -EFAULT;
+- goto out_ext_ctrl;
+- }
+- if (err < 0)
+- goto out;
+-
+-out_ext_ctrl:
+- /* Copy results into user buffer */
+- switch (_IOC_DIR(cmd)) {
+- case _IOC_READ:
+- case (_IOC_WRITE | _IOC_READ):
+- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+- err = -EFAULT;
+- break;
+- }
+-
+-out:
+- kfree(mbuf);
+- return err;
++ return __video_usercopy(file, cmd, arg, __video_do_ioctl);
+ }
+ EXPORT_SYMBOL(video_ioctl2);
+--
+1.6.6.1
+