Commit d8799b46 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (8112): videodev: improve extended control support in video_ioctl2()

- add sanity checks for the extended controls argument.
- if the driver only supports extended controls, then convert
  old-style controls to an extended control callback.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 36ecd495
...@@ -710,6 +710,29 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd, ...@@ -710,6 +710,29 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
printk(KERN_CONT "\n"); printk(KERN_CONT "\n");
}; };
static inline int check_ext_ctrls(struct v4l2_ext_controls *c)
{
__u32 i;
/* zero the reserved fields */
c->reserved[0] = c->reserved[1] = 0;
for (i = 0; i < c->count; i++) {
c->controls[i].reserved2[0] = 0;
c->controls[i].reserved2[1] = 0;
}
/* V4L2_CID_PRIVATE_BASE cannot be used as control class
* when using extended controls. */
if (c->ctrl_class == V4L2_CID_PRIVATE_BASE)
return 0;
/* Check that all controls are from the same control class. */
for (i = 0; i < c->count; i++) {
if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
c->error_idx = i;
return 0;
}
}
return 1;
}
static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
{ {
...@@ -1392,10 +1415,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ...@@ -1392,10 +1415,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
{ {
struct v4l2_control *p = arg; struct v4l2_control *p = arg;
if (!vfd->vidioc_g_ctrl) if (vfd->vidioc_g_ctrl)
ret = vfd->vidioc_g_ctrl(file, fh, p);
else if (vfd->vidioc_g_ext_ctrls) {
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
ctrls.count = 1;
ctrls.controls = &ctrl;
ctrl.id = p->id;
ctrl.value = p->value;
if (check_ext_ctrls(&ctrls)) {
ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls);
if (ret == 0)
p->value = ctrl.value;
}
} else
break; break;
ret = vfd->vidioc_g_ctrl(file, fh, p);
if (!ret) if (!ret)
dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
else else
...@@ -1405,21 +1442,39 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ...@@ -1405,21 +1442,39 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
{ {
struct v4l2_control *p = arg; struct v4l2_control *p = arg;
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;
if (!vfd->vidioc_s_ctrl) if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls)
break; break;
dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
ret = vfd->vidioc_s_ctrl(file, fh, p); if (vfd->vidioc_s_ctrl) {
ret = vfd->vidioc_s_ctrl(file, fh, p);
break;
}
if (!vfd->vidioc_s_ext_ctrls)
break;
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
ctrls.count = 1;
ctrls.controls = &ctrl;
ctrl.id = p->id;
ctrl.value = p->value;
if (check_ext_ctrls(&ctrls))
ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls);
break; break;
} }
case VIDIOC_G_EXT_CTRLS: case VIDIOC_G_EXT_CTRLS:
{ {
struct v4l2_ext_controls *p = arg; struct v4l2_ext_controls *p = arg;
p->error_idx = p->count;
if (!vfd->vidioc_g_ext_ctrls) if (!vfd->vidioc_g_ext_ctrls)
break; break;
ret = vfd->vidioc_g_ext_ctrls(file, fh, p); if (check_ext_ctrls(p))
ret = vfd->vidioc_g_ext_ctrls(file, fh, p);
v4l_print_ext_ctrls(cmd, vfd, p, !ret); v4l_print_ext_ctrls(cmd, vfd, p, !ret);
break; break;
} }
...@@ -1427,22 +1482,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ...@@ -1427,22 +1482,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
{ {
struct v4l2_ext_controls *p = arg; struct v4l2_ext_controls *p = arg;
if (vfd->vidioc_s_ext_ctrls) { p->error_idx = p->count;
v4l_print_ext_ctrls(cmd, vfd, p, 1); if (!vfd->vidioc_s_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
if (check_ext_ctrls(p))
ret = vfd->vidioc_s_ext_ctrls(file, fh, p); ret = vfd->vidioc_s_ext_ctrls(file, fh, p);
}
break; break;
} }
case VIDIOC_TRY_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS:
{ {
struct v4l2_ext_controls *p = arg; struct v4l2_ext_controls *p = arg;
if (vfd->vidioc_try_ext_ctrls) { p->error_idx = p->count;
v4l_print_ext_ctrls(cmd, vfd, p, 1); if (!vfd->vidioc_try_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
if (check_ext_ctrls(p))
ret = vfd->vidioc_try_ext_ctrls(file, fh, p); ret = vfd->vidioc_try_ext_ctrls(file, fh, p);
}
break; break;
} }
case VIDIOC_QUERYMENU: case VIDIOC_QUERYMENU:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment