mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
V4L/DVB (4189): Add videodev support for VIDIOC_S/G/TRY_EXT_CTRLS.
videodev.c copies the control list specified in struct v4l2_ext_controls to kernel space. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
4f34171212
commit
0597691456
2 changed files with 109 additions and 2 deletions
|
@ -190,10 +190,15 @@ video_usercopy(struct inode *inode, struct file *file,
|
|||
void *mbuf = NULL;
|
||||
void *parg = NULL;
|
||||
int 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)) {
|
||||
|
@ -215,19 +220,47 @@ video_usercopy(struct inode *inode, struct file *file,
|
|||
|
||||
err = -EFAULT;
|
||||
if (_IOC_DIR(cmd) & _IOC_WRITE)
|
||||
if (copy_from_user(parg, (void __user *)arg,
|
||||
_IOC_SIZE(cmd)))
|
||||
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* call driver */
|
||||
err = func(inode, 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))
|
||||
{
|
||||
|
@ -993,6 +1026,39 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
|
|||
ret=vfd->vidioc_s_ctrl(file, fh, p);
|
||||
break;
|
||||
}
|
||||
case VIDIOC_G_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *p = arg;
|
||||
|
||||
if (vfd->vidioc_g_ext_ctrls) {
|
||||
dbgarg(cmd, "count=%d\n", p->count);
|
||||
|
||||
ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIDIOC_S_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *p = arg;
|
||||
|
||||
if (vfd->vidioc_s_ext_ctrls) {
|
||||
dbgarg(cmd, "count=%d\n", p->count);
|
||||
|
||||
ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIDIOC_TRY_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *p = arg;
|
||||
|
||||
if (vfd->vidioc_try_ext_ctrls) {
|
||||
dbgarg(cmd, "count=%d\n", p->count);
|
||||
|
||||
ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VIDIOC_QUERYMENU:
|
||||
{
|
||||
struct v4l2_querymenu *p=arg;
|
||||
|
@ -1326,10 +1392,15 @@ int video_ioctl2 (struct inode *inode, struct file *file,
|
|||
void *mbuf = NULL;
|
||||
void *parg = NULL;
|
||||
int 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)) {
|
||||
|
@ -1356,13 +1427,43 @@ int video_ioctl2 (struct inode *inode, struct file *file,
|
|||
break;
|
||||
}
|
||||
|
||||
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(inode, 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))
|
||||
{
|
||||
|
|
|
@ -232,6 +232,12 @@ struct video_device
|
|||
struct v4l2_control *a);
|
||||
int (*vidioc_s_ctrl) (struct file *file, void *fh,
|
||||
struct v4l2_control *a);
|
||||
int (*vidioc_g_ext_ctrls) (struct file *file, void *fh,
|
||||
struct v4l2_ext_controls *a);
|
||||
int (*vidioc_s_ext_ctrls) (struct file *file, void *fh,
|
||||
struct v4l2_ext_controls *a);
|
||||
int (*vidioc_try_ext_ctrls) (struct file *file, void *fh,
|
||||
struct v4l2_ext_controls *a);
|
||||
int (*vidioc_querymenu) (struct file *file, void *fh,
|
||||
struct v4l2_querymenu *a);
|
||||
|
||||
|
|
Loading…
Reference in a new issue