summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2013-03-10 13:12:25 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-24 12:01:26 -0300
commit73f35418a1e921443b5c9f4c58ae70df8b9d1bb6 (patch)
tree16c3041e01fd356b9bf7ff65b890d9a86f0d45f6
parent2180f92def1921397f422f278b3cc65751b749cc (diff)
downloadlinux-73f35418a1e921443b5c9f4c58ae70df8b9d1bb6.tar.gz
linux-73f35418a1e921443b5c9f4c58ae70df8b9d1bb6.tar.bz2
linux-73f35418a1e921443b5c9f4c58ae70df8b9d1bb6.zip
[media] v4l2-ioctl: check if an ioctl is valid
Just checking if the op exists isn't correct, you should check if the ioctl is valid (which implies that the op exists as well). One exception is g_std: if current_norm is non-zero, then the g_std op may be absent. This sort of weird behavior is one of the reasons why I am trying to get rid of current_norm. This patch fixes the case where the g/s_std op is set, but these ioctls are disabled. This can happen in drivers supporting multiple models, some that have TV input (and support the STD API) and some that have a sensor (and do not support the STD API). In the latter case qv4l2 would still show the Standards combobox. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 168b51e193cd..72c22fde2b69 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -35,6 +35,8 @@
memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
+#define is_valid_ioctl(vfd, cmd) test_bit(_IOC_NR(cmd), (vfd)->valid_ioctls)
+
struct std_descr {
v4l2_std_id std;
const char *descr;
@@ -1005,6 +1007,7 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,
static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vfd = video_devdata(file);
struct v4l2_input *p = arg;
/*
@@ -1013,11 +1016,11 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
* driver. If the driver doesn't support these
* for a specific input, it must override these flags.
*/
- if (ops->vidioc_s_std)
+ if (is_valid_ioctl(vfd, VIDIOC_S_STD))
p->capabilities |= V4L2_IN_CAP_STD;
- if (ops->vidioc_s_dv_preset)
+ if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET))
p->capabilities |= V4L2_IN_CAP_PRESETS;
- if (ops->vidioc_s_dv_timings)
+ if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS))
p->capabilities |= V4L2_IN_CAP_DV_TIMINGS;
return ops->vidioc_enum_input(file, fh, p);
@@ -1026,6 +1029,7 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vfd = video_devdata(file);
struct v4l2_output *p = arg;
/*
@@ -1034,11 +1038,11 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops,
* driver. If the driver doesn't support these
* for a specific output, it must override these flags.
*/
- if (ops->vidioc_s_std)
+ if (is_valid_ioctl(vfd, VIDIOC_S_STD))
p->capabilities |= V4L2_OUT_CAP_STD;
- if (ops->vidioc_s_dv_preset)
+ if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET))
p->capabilities |= V4L2_OUT_CAP_PRESETS;
- if (ops->vidioc_s_dv_timings)
+ if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS))
p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS;
return ops->vidioc_enum_output(file, fh, p);
@@ -1521,7 +1525,7 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return -EINVAL;
p->parm.capture.readbuffers = 2;
- if (ops->vidioc_g_std)
+ if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std)
ret = ops->vidioc_g_std(file, fh, &std);
if (ret == 0)
v4l2_video_std_frame_period(std,
@@ -1881,7 +1885,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
return -EINVAL;
if (ops->vidioc_enum_freq_bands)
return ops->vidioc_enum_freq_bands(file, fh, p);
- if (ops->vidioc_g_tuner) {
+ if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) {
struct v4l2_tuner t = {
.index = p->tuner,
.type = type,
@@ -1899,7 +1903,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB;
return 0;
}
- if (ops->vidioc_g_modulator) {
+ if (is_valid_ioctl(vfd, VIDIOC_G_MODULATOR)) {
struct v4l2_modulator m = {
.index = p->tuner,
};