diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-09-11 06:35:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-05 15:30:12 -0500 |
commit | 2c2a053626cb712d6006cb10f2760a6018a65631 (patch) | |
tree | 60cd7384da0e95c26ab43d352ee4e155dbeb9f56 /drivers/media | |
parent | ed986d1fee77bbbb62291a1db1c7edbb00d99515 (diff) |
[media] tm6000: fix querycap and input/tuner compliance issues
- add device_caps support
- fix bus_info
- fix numerous tuner-related problems due to incorrect tests
and setting v4l2_tuner fields to wrong values.
- remove (audio) input support from the radio: it doesn't belong
there. This also fixed a nasty issue where opening the radio
would set dev->input to 5 for no good reason. This was never
set back to a valid TV input after closing the radio device,
thus leaving it at 5 which is out of bounds of the vinput
card array.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/tm6000/tm6000-video.c | 147 |
1 files changed, 31 insertions, 116 deletions
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index e3c567c27918..7a653b263678 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c | |||
@@ -948,16 +948,21 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
948 | struct v4l2_capability *cap) | 948 | struct v4l2_capability *cap) |
949 | { | 949 | { |
950 | struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; | 950 | struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; |
951 | struct video_device *vdev = video_devdata(file); | ||
951 | 952 | ||
952 | strlcpy(cap->driver, "tm6000", sizeof(cap->driver)); | 953 | strlcpy(cap->driver, "tm6000", sizeof(cap->driver)); |
953 | strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); | 954 | strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); |
954 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | 955 | usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); |
955 | V4L2_CAP_STREAMING | | ||
956 | V4L2_CAP_AUDIO | | ||
957 | V4L2_CAP_READWRITE; | ||
958 | |||
959 | if (dev->tuner_type != TUNER_ABSENT) | 956 | if (dev->tuner_type != TUNER_ABSENT) |
960 | cap->capabilities |= V4L2_CAP_TUNER; | 957 | cap->device_caps |= V4L2_CAP_TUNER; |
958 | if (vdev->vfl_type == VFL_TYPE_GRABBER) | ||
959 | cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE | | ||
960 | V4L2_CAP_STREAMING | | ||
961 | V4L2_CAP_READWRITE; | ||
962 | else | ||
963 | cap->device_caps |= V4L2_CAP_RADIO; | ||
964 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | | ||
965 | V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
961 | 966 | ||
962 | return 0; | 967 | return 0; |
963 | } | 968 | } |
@@ -965,7 +970,7 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
965 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | 970 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, |
966 | struct v4l2_fmtdesc *f) | 971 | struct v4l2_fmtdesc *f) |
967 | { | 972 | { |
968 | if (unlikely(f->index >= ARRAY_SIZE(format))) | 973 | if (f->index >= ARRAY_SIZE(format)) |
969 | return -EINVAL; | 974 | return -EINVAL; |
970 | 975 | ||
971 | strlcpy(f->description, format[f->index].name, sizeof(f->description)); | 976 | strlcpy(f->description, format[f->index].name, sizeof(f->description)); |
@@ -1301,14 +1306,14 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
1301 | struct tm6000_fh *fh = priv; | 1306 | struct tm6000_fh *fh = priv; |
1302 | struct tm6000_core *dev = fh->dev; | 1307 | struct tm6000_core *dev = fh->dev; |
1303 | 1308 | ||
1304 | if (unlikely(UNSET == dev->tuner_type)) | 1309 | if (UNSET == dev->tuner_type) |
1305 | return -EINVAL; | 1310 | return -ENOTTY; |
1306 | if (0 != t->index) | 1311 | if (0 != t->index) |
1307 | return -EINVAL; | 1312 | return -EINVAL; |
1308 | 1313 | ||
1309 | strcpy(t->name, "Television"); | 1314 | strcpy(t->name, "Television"); |
1310 | t->type = V4L2_TUNER_ANALOG_TV; | 1315 | t->type = V4L2_TUNER_ANALOG_TV; |
1311 | t->capability = V4L2_TUNER_CAP_NORM; | 1316 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; |
1312 | t->rangehigh = 0xffffffffUL; | 1317 | t->rangehigh = 0xffffffffUL; |
1313 | t->rxsubchans = V4L2_TUNER_SUB_STEREO; | 1318 | t->rxsubchans = V4L2_TUNER_SUB_STEREO; |
1314 | 1319 | ||
@@ -1326,11 +1331,14 @@ static int vidioc_s_tuner(struct file *file, void *priv, | |||
1326 | struct tm6000_core *dev = fh->dev; | 1331 | struct tm6000_core *dev = fh->dev; |
1327 | 1332 | ||
1328 | if (UNSET == dev->tuner_type) | 1333 | if (UNSET == dev->tuner_type) |
1329 | return -EINVAL; | 1334 | return -ENOTTY; |
1330 | if (0 != t->index) | 1335 | if (0 != t->index) |
1331 | return -EINVAL; | 1336 | return -EINVAL; |
1332 | 1337 | ||
1333 | dev->amode = t->audmode; | 1338 | if (t->audmode > V4L2_TUNER_MODE_STEREO) |
1339 | dev->amode = V4L2_TUNER_MODE_STEREO; | ||
1340 | else | ||
1341 | dev->amode = t->audmode; | ||
1334 | dprintk(dev, 3, "audio mode: %x\n", t->audmode); | 1342 | dprintk(dev, 3, "audio mode: %x\n", t->audmode); |
1335 | 1343 | ||
1336 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); | 1344 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); |
@@ -1344,10 +1352,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
1344 | struct tm6000_fh *fh = priv; | 1352 | struct tm6000_fh *fh = priv; |
1345 | struct tm6000_core *dev = fh->dev; | 1353 | struct tm6000_core *dev = fh->dev; |
1346 | 1354 | ||
1347 | if (unlikely(UNSET == dev->tuner_type)) | 1355 | if (UNSET == dev->tuner_type) |
1356 | return -ENOTTY; | ||
1357 | if (f->tuner) | ||
1348 | return -EINVAL; | 1358 | return -EINVAL; |
1349 | 1359 | ||
1350 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1351 | f->frequency = dev->freq; | 1360 | f->frequency = dev->freq; |
1352 | 1361 | ||
1353 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); | 1362 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); |
@@ -1361,13 +1370,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
1361 | struct tm6000_fh *fh = priv; | 1370 | struct tm6000_fh *fh = priv; |
1362 | struct tm6000_core *dev = fh->dev; | 1371 | struct tm6000_core *dev = fh->dev; |
1363 | 1372 | ||
1364 | if (unlikely(UNSET == dev->tuner_type)) | 1373 | if (UNSET == dev->tuner_type) |
1365 | return -EINVAL; | 1374 | return -ENOTTY; |
1366 | if (unlikely(f->tuner != 0)) | 1375 | if (f->tuner != 0) |
1367 | return -EINVAL; | ||
1368 | if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) | ||
1369 | return -EINVAL; | ||
1370 | if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) | ||
1371 | return -EINVAL; | 1376 | return -EINVAL; |
1372 | 1377 | ||
1373 | dev->freq = f->frequency; | 1378 | dev->freq = f->frequency; |
@@ -1376,27 +1381,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
1376 | return 0; | 1381 | return 0; |
1377 | } | 1382 | } |
1378 | 1383 | ||
1379 | static int radio_querycap(struct file *file, void *priv, | ||
1380 | struct v4l2_capability *cap) | ||
1381 | { | ||
1382 | struct tm6000_fh *fh = file->private_data; | ||
1383 | struct tm6000_core *dev = fh->dev; | ||
1384 | |||
1385 | strcpy(cap->driver, "tm6000"); | ||
1386 | strlcpy(cap->card, dev->name, sizeof(dev->name)); | ||
1387 | sprintf(cap->bus_info, "USB%04x:%04x", | ||
1388 | le16_to_cpu(dev->udev->descriptor.idVendor), | ||
1389 | le16_to_cpu(dev->udev->descriptor.idProduct)); | ||
1390 | cap->version = dev->dev_type; | ||
1391 | cap->capabilities = V4L2_CAP_TUNER | | ||
1392 | V4L2_CAP_AUDIO | | ||
1393 | V4L2_CAP_RADIO | | ||
1394 | V4L2_CAP_READWRITE | | ||
1395 | V4L2_CAP_STREAMING; | ||
1396 | |||
1397 | return 0; | ||
1398 | } | ||
1399 | |||
1400 | static int radio_g_tuner(struct file *file, void *priv, | 1384 | static int radio_g_tuner(struct file *file, void *priv, |
1401 | struct v4l2_tuner *t) | 1385 | struct v4l2_tuner *t) |
1402 | { | 1386 | { |
@@ -1409,7 +1393,9 @@ static int radio_g_tuner(struct file *file, void *priv, | |||
1409 | memset(t, 0, sizeof(*t)); | 1393 | memset(t, 0, sizeof(*t)); |
1410 | strcpy(t->name, "Radio"); | 1394 | strcpy(t->name, "Radio"); |
1411 | t->type = V4L2_TUNER_RADIO; | 1395 | t->type = V4L2_TUNER_RADIO; |
1396 | t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
1412 | t->rxsubchans = V4L2_TUNER_SUB_STEREO; | 1397 | t->rxsubchans = V4L2_TUNER_SUB_STEREO; |
1398 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
1413 | 1399 | ||
1414 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); | 1400 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); |
1415 | 1401 | ||
@@ -1424,78 +1410,14 @@ static int radio_s_tuner(struct file *file, void *priv, | |||
1424 | 1410 | ||
1425 | if (0 != t->index) | 1411 | if (0 != t->index) |
1426 | return -EINVAL; | 1412 | return -EINVAL; |
1413 | if (t->audmode > V4L2_TUNER_MODE_STEREO) | ||
1414 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
1427 | 1415 | ||
1428 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); | 1416 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); |
1429 | 1417 | ||
1430 | return 0; | 1418 | return 0; |
1431 | } | 1419 | } |
1432 | 1420 | ||
1433 | static int radio_enum_input(struct file *file, void *priv, | ||
1434 | struct v4l2_input *i) | ||
1435 | { | ||
1436 | struct tm6000_fh *fh = priv; | ||
1437 | struct tm6000_core *dev = fh->dev; | ||
1438 | |||
1439 | if (i->index != 0) | ||
1440 | return -EINVAL; | ||
1441 | |||
1442 | if (!dev->rinput.type) | ||
1443 | return -EINVAL; | ||
1444 | |||
1445 | strcpy(i->name, "Radio"); | ||
1446 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1447 | |||
1448 | return 0; | ||
1449 | } | ||
1450 | |||
1451 | static int radio_g_input(struct file *filp, void *priv, unsigned int *i) | ||
1452 | { | ||
1453 | struct tm6000_fh *fh = priv; | ||
1454 | struct tm6000_core *dev = fh->dev; | ||
1455 | |||
1456 | if (dev->input != 5) | ||
1457 | return -EINVAL; | ||
1458 | |||
1459 | *i = dev->input - 5; | ||
1460 | |||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | static int radio_g_audio(struct file *file, void *priv, | ||
1465 | struct v4l2_audio *a) | ||
1466 | { | ||
1467 | memset(a, 0, sizeof(*a)); | ||
1468 | strcpy(a->name, "Radio"); | ||
1469 | return 0; | ||
1470 | } | ||
1471 | |||
1472 | static int radio_s_audio(struct file *file, void *priv, | ||
1473 | const struct v4l2_audio *a) | ||
1474 | { | ||
1475 | return 0; | ||
1476 | } | ||
1477 | |||
1478 | static int radio_s_input(struct file *filp, void *priv, unsigned int i) | ||
1479 | { | ||
1480 | struct tm6000_fh *fh = priv; | ||
1481 | struct tm6000_core *dev = fh->dev; | ||
1482 | |||
1483 | if (i) | ||
1484 | return -EINVAL; | ||
1485 | |||
1486 | if (!dev->rinput.type) | ||
1487 | return -EINVAL; | ||
1488 | |||
1489 | dev->input = i + 5; | ||
1490 | |||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) | ||
1495 | { | ||
1496 | return 0; | ||
1497 | } | ||
1498 | |||
1499 | static int radio_queryctrl(struct file *file, void *priv, | 1421 | static int radio_queryctrl(struct file *file, void *priv, |
1500 | struct v4l2_queryctrl *c) | 1422 | struct v4l2_queryctrl *c) |
1501 | { | 1423 | { |
@@ -1599,7 +1521,6 @@ static int __tm6000_open(struct file *file) | |||
1599 | sizeof(struct tm6000_buffer), fh, &dev->lock); | 1521 | sizeof(struct tm6000_buffer), fh, &dev->lock); |
1600 | } else { | 1522 | } else { |
1601 | dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); | 1523 | dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); |
1602 | dev->input = 5; | ||
1603 | tm6000_set_audio_rinput(dev); | 1524 | tm6000_set_audio_rinput(dev); |
1604 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); | 1525 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); |
1605 | tm6000_prepare_isoc(dev); | 1526 | tm6000_prepare_isoc(dev); |
@@ -1789,16 +1710,10 @@ static const struct v4l2_file_operations radio_fops = { | |||
1789 | }; | 1710 | }; |
1790 | 1711 | ||
1791 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { | 1712 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { |
1792 | .vidioc_querycap = radio_querycap, | 1713 | .vidioc_querycap = vidioc_querycap, |
1793 | .vidioc_g_tuner = radio_g_tuner, | 1714 | .vidioc_g_tuner = radio_g_tuner, |
1794 | .vidioc_enum_input = radio_enum_input, | ||
1795 | .vidioc_g_audio = radio_g_audio, | ||
1796 | .vidioc_s_tuner = radio_s_tuner, | 1715 | .vidioc_s_tuner = radio_s_tuner, |
1797 | .vidioc_s_audio = radio_s_audio, | ||
1798 | .vidioc_s_input = radio_s_input, | ||
1799 | .vidioc_s_std = radio_s_std, | ||
1800 | .vidioc_queryctrl = radio_queryctrl, | 1716 | .vidioc_queryctrl = radio_queryctrl, |
1801 | .vidioc_g_input = radio_g_input, | ||
1802 | .vidioc_g_ctrl = vidioc_g_ctrl, | 1717 | .vidioc_g_ctrl = vidioc_g_ctrl, |
1803 | .vidioc_s_ctrl = vidioc_s_ctrl, | 1718 | .vidioc_s_ctrl = vidioc_s_ctrl, |
1804 | .vidioc_g_frequency = vidioc_g_frequency, | 1719 | .vidioc_g_frequency = vidioc_g_frequency, |