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.pinch...@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 0eeceae..486eaba 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -373,35 +373,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 {
@@ -413,11 +440,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;
 
@@ -439,7 +476,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;
@@ -468,6 +505,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,
@@ -2021,138 +2071,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.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to