diff options
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.patch | 297 |
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 + |