diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index f34d524ccb09..a83131bd00b2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -1387,6 +1387,27 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
1387 | return -EINVAL; | 1387 | return -EINVAL; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | /* | ||
1391 | * FIXME: This is an indirect way to check if a control exists at a | ||
1392 | * subdev. Instead of that hack, maybe the better would be to change all | ||
1393 | * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported. | ||
1394 | */ | ||
1395 | static int check_subdev_ctrl(struct em28xx *dev, int id) | ||
1396 | { | ||
1397 | struct v4l2_queryctrl qc; | ||
1398 | |||
1399 | memset(&qc, 0, sizeof(qc)); | ||
1400 | qc.id = id; | ||
1401 | |||
1402 | /* enumerate V4L2 device controls */ | ||
1403 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc); | ||
1404 | |||
1405 | if (qc.type) | ||
1406 | return 0; | ||
1407 | else | ||
1408 | return -EINVAL; | ||
1409 | } | ||
1410 | |||
1390 | static int vidioc_g_ctrl(struct file *file, void *priv, | 1411 | static int vidioc_g_ctrl(struct file *file, void *priv, |
1391 | struct v4l2_control *ctrl) | 1412 | struct v4l2_control *ctrl) |
1392 | { | 1413 | { |
@@ -1399,7 +1420,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
1399 | return rc; | 1420 | return rc; |
1400 | rc = 0; | 1421 | rc = 0; |
1401 | 1422 | ||
1402 | |||
1403 | /* Set an AC97 control */ | 1423 | /* Set an AC97 control */ |
1404 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) | 1424 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) |
1405 | rc = ac97_get_ctrl(dev, ctrl); | 1425 | rc = ac97_get_ctrl(dev, ctrl); |
@@ -1408,6 +1428,9 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
1408 | 1428 | ||
1409 | /* It were not an AC97 control. Sends it to the v4l2 dev interface */ | 1429 | /* It were not an AC97 control. Sends it to the v4l2 dev interface */ |
1410 | if (rc == 1) { | 1430 | if (rc == 1) { |
1431 | if (check_subdev_ctrl(dev, ctrl->id)) | ||
1432 | return -EINVAL; | ||
1433 | |||
1411 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); | 1434 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); |
1412 | rc = 0; | 1435 | rc = 0; |
1413 | } | 1436 | } |
@@ -1434,8 +1457,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1434 | 1457 | ||
1435 | /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ | 1458 | /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ |
1436 | if (rc == 1) { | 1459 | if (rc == 1) { |
1437 | rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); | 1460 | rc = check_subdev_ctrl(dev, ctrl->id); |
1438 | 1461 | if (!rc) | |
1462 | v4l2_device_call_all(&dev->v4l2_dev, 0, | ||
1463 | core, s_ctrl, ctrl); | ||
1439 | /* | 1464 | /* |
1440 | * In the case of non-AC97 volume controls, we still need | 1465 | * In the case of non-AC97 volume controls, we still need |
1441 | * to do some setups at em28xx, in order to mute/unmute | 1466 | * to do some setups at em28xx, in order to mute/unmute |
@@ -1452,7 +1477,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1452 | rc = em28xx_audio_analog_set(dev); | 1477 | rc = em28xx_audio_analog_set(dev); |
1453 | } | 1478 | } |
1454 | } | 1479 | } |
1455 | return rc; | 1480 | return (rc < 0) ? rc : 0; |
1456 | } | 1481 | } |
1457 | 1482 | ||
1458 | static int vidioc_g_tuner(struct file *file, void *priv, | 1483 | static int vidioc_g_tuner(struct file *file, void *priv, |