Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] saa7146: fix querycap, vbi/video separation and g/s_register

The querycap ioctl returned an incorrect version number and incorrect
capabilities (mixing up vbi and video caps).

The reason for that was that video nodes could do vbi activities: that
should be separated between the vbi and video nodes.

There were also a few minor problems with dbg_g/s_register that have
been resolved. The mxb/saa7146 driver now passes the v4l2_compliance tests.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
ab49ae0f 537fa492

+92 -46
+6 -2
drivers/media/common/saa7146_fops.c
··· 478 478 v4l2_ctrl_handler_free(hdl); 479 479 return -ENOMEM; 480 480 } 481 - ext_vv->ops = saa7146_video_ioctl_ops; 481 + ext_vv->vid_ops = saa7146_video_ioctl_ops; 482 + ext_vv->vbi_ops = saa7146_vbi_ioctl_ops; 482 483 ext_vv->core_ops = &saa7146_video_ioctl_ops; 483 484 484 485 DEB_EE("dev:%p\n", dev); ··· 580 579 return -ENOMEM; 581 580 582 581 vfd->fops = &video_fops; 583 - vfd->ioctl_ops = &dev->ext_vv_data->ops; 582 + if (type == VFL_TYPE_GRABBER) 583 + vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; 584 + else 585 + vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; 584 586 vfd->release = video_device_release; 585 587 /* Locking in file operations other than ioctl should be done by 586 588 the driver, not the V4L2 core.
+31 -4
drivers/media/common/saa7146_video.c
··· 446 446 447 447 static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 448 448 { 449 + struct video_device *vdev = video_devdata(file); 449 450 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; 450 451 451 452 strcpy((char *)cap->driver, "saa7146 v4l2"); 452 453 strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); 453 454 sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); 454 - cap->version = SAA7146_VERSION_CODE; 455 455 cap->device_caps = 456 456 V4L2_CAP_VIDEO_CAPTURE | 457 457 V4L2_CAP_VIDEO_OVERLAY | 458 458 V4L2_CAP_READWRITE | 459 459 V4L2_CAP_STREAMING; 460 460 cap->device_caps |= dev->ext_vv_data->capabilities; 461 + if (vdev->vfl_type == VFL_TYPE_GRABBER) 462 + cap->device_caps &= 463 + ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); 464 + else 465 + cap->device_caps &= 466 + ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY); 461 467 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 462 468 return 0; 463 469 } ··· 996 990 997 991 chip->ident = V4L2_IDENT_NONE; 998 992 chip->revision = 0; 999 - if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) { 1000 - chip->ident = V4L2_IDENT_SAA7146; 993 + if (chip->match.type == V4L2_CHIP_MATCH_HOST) { 994 + if (v4l2_chip_match_host(&chip->match)) 995 + chip->ident = V4L2_IDENT_SAA7146; 1001 996 return 0; 1002 997 } 998 + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && 999 + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) 1000 + return -EINVAL; 1003 1001 return v4l2_device_call_until_err(&dev->v4l2_dev, 0, 1004 1002 core, g_chip_ident, chip); 1005 1003 } ··· 1018 1008 .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, 1019 1009 .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, 1020 1010 .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, 1021 - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, 1022 1011 .vidioc_g_chip_ident = vidioc_g_chip_ident, 1023 1012 1024 1013 .vidioc_overlay = vidioc_overlay, ··· 1032 1023 .vidioc_streamon = vidioc_streamon, 1033 1024 .vidioc_streamoff = vidioc_streamoff, 1034 1025 .vidioc_g_parm = vidioc_g_parm, 1026 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1027 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1028 + }; 1029 + 1030 + const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = { 1031 + .vidioc_querycap = vidioc_querycap, 1032 + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, 1033 + .vidioc_g_chip_ident = vidioc_g_chip_ident, 1034 + 1035 + .vidioc_reqbufs = vidioc_reqbufs, 1036 + .vidioc_querybuf = vidioc_querybuf, 1037 + .vidioc_qbuf = vidioc_qbuf, 1038 + .vidioc_dqbuf = vidioc_dqbuf, 1039 + .vidioc_g_std = vidioc_g_std, 1040 + .vidioc_s_std = vidioc_s_std, 1041 + .vidioc_streamon = vidioc_streamon, 1042 + .vidioc_streamoff = vidioc_streamoff, 1043 + .vidioc_g_parm = vidioc_g_parm, 1035 1044 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1036 1045 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1037 1046 };
+12 -12
drivers/media/dvb/ttpci/av7110_v4l.c
··· 802 802 ERR("cannot init capture device. skipping\n"); 803 803 return -ENODEV; 804 804 } 805 - vv_data->ops.vidioc_enum_input = vidioc_enum_input; 806 - vv_data->ops.vidioc_g_input = vidioc_g_input; 807 - vv_data->ops.vidioc_s_input = vidioc_s_input; 808 - vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; 809 - vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; 810 - vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; 811 - vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; 812 - vv_data->ops.vidioc_g_audio = vidioc_g_audio; 813 - vv_data->ops.vidioc_s_audio = vidioc_s_audio; 814 - vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; 815 - vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; 816 - vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; 805 + vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input; 806 + vv_data->vid_ops.vidioc_g_input = vidioc_g_input; 807 + vv_data->vid_ops.vidioc_s_input = vidioc_s_input; 808 + vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner; 809 + vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner; 810 + vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency; 811 + vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency; 812 + vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio; 813 + vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio; 814 + vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; 815 + vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; 816 + vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; 817 817 818 818 if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { 819 819 ERR("cannot register capture device. skipping\n");
+3 -3
drivers/media/dvb/ttpci/budget-av.c
··· 1483 1483 ERR("cannot init vv subsystem\n"); 1484 1484 return err; 1485 1485 } 1486 - vv_data.ops.vidioc_enum_input = vidioc_enum_input; 1487 - vv_data.ops.vidioc_g_input = vidioc_g_input; 1488 - vv_data.ops.vidioc_s_input = vidioc_s_input; 1486 + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; 1487 + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; 1488 + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; 1489 1489 1490 1490 if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { 1491 1491 /* fixme: proper cleanup here */
+6 -6
drivers/media/video/hexium_gemini.c
··· 399 399 hexium->cur_input = 0; 400 400 401 401 saa7146_vv_init(dev, &vv_data); 402 - vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; 403 - vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; 404 - vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; 405 - vv_data.ops.vidioc_enum_input = vidioc_enum_input; 406 - vv_data.ops.vidioc_g_input = vidioc_g_input; 407 - vv_data.ops.vidioc_s_input = vidioc_s_input; 402 + vv_data.vid_ops.vidioc_queryctrl = vidioc_queryctrl; 403 + vv_data.vid_ops.vidioc_g_ctrl = vidioc_g_ctrl; 404 + vv_data.vid_ops.vidioc_s_ctrl = vidioc_s_ctrl; 405 + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; 406 + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; 407 + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; 408 408 ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); 409 409 if (ret < 0) { 410 410 pr_err("cannot register capture v4l2 device. skipping.\n");
+3 -3
drivers/media/video/hexium_orion.c
··· 371 371 DEB_EE("\n"); 372 372 373 373 saa7146_vv_init(dev, &vv_data); 374 - vv_data.ops.vidioc_enum_input = vidioc_enum_input; 375 - vv_data.ops.vidioc_g_input = vidioc_g_input; 376 - vv_data.ops.vidioc_s_input = vidioc_s_input; 374 + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; 375 + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; 376 + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; 377 377 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { 378 378 pr_err("cannot register capture v4l2 device. skipping.\n"); 379 379 return -1;
+28 -13
drivers/media/video/mxb.c
··· 662 662 { 663 663 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; 664 664 665 - return call_all(dev, core, g_register, reg); 665 + if (!capable(CAP_SYS_ADMIN)) 666 + return -EPERM; 667 + if (v4l2_chip_match_host(&reg->match)) { 668 + reg->val = saa7146_read(dev, reg->reg); 669 + reg->size = 4; 670 + return 0; 671 + } 672 + call_all(dev, core, g_register, reg); 673 + return 0; 666 674 } 667 675 668 676 static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) 669 677 { 670 678 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; 671 679 680 + if (!capable(CAP_SYS_ADMIN)) 681 + return -EPERM; 682 + if (v4l2_chip_match_host(&reg->match)) { 683 + saa7146_write(dev, reg->reg, reg->val); 684 + reg->size = 4; 685 + return 0; 686 + } 672 687 return call_all(dev, core, s_register, reg); 673 688 } 674 689 #endif ··· 704 689 } 705 690 mxb = (struct mxb *)dev->ext_priv; 706 691 707 - vv_data.ops.vidioc_enum_input = vidioc_enum_input; 708 - vv_data.ops.vidioc_g_input = vidioc_g_input; 709 - vv_data.ops.vidioc_s_input = vidioc_s_input; 710 - vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; 711 - vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; 712 - vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; 713 - vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; 714 - vv_data.ops.vidioc_enumaudio = vidioc_enumaudio; 715 - vv_data.ops.vidioc_g_audio = vidioc_g_audio; 716 - vv_data.ops.vidioc_s_audio = vidioc_s_audio; 692 + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; 693 + vv_data.vid_ops.vidioc_g_input = vidioc_g_input; 694 + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; 695 + vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner; 696 + vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner; 697 + vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency; 698 + vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency; 699 + vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio; 700 + vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio; 701 + vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio; 717 702 #ifdef CONFIG_VIDEO_ADV_DEBUG 718 - vv_data.ops.vidioc_g_register = vidioc_g_register; 719 - vv_data.ops.vidioc_s_register = vidioc_s_register; 703 + vv_data.vid_ops.vidioc_g_register = vidioc_g_register; 704 + vv_data.vid_ops.vidioc_s_register = vidioc_s_register; 720 705 #endif 721 706 if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { 722 707 ERR("cannot register capture v4l2 device. skipping.\n");
-2
include/media/saa7146.h
··· 18 18 #include <linux/vmalloc.h> /* for vmalloc() */ 19 19 #include <linux/mm.h> /* for vmalloc_to_page() */ 20 20 21 - #define SAA7146_VERSION_CODE 0x000600 /* 0.6.0 */ 22 - 23 21 #define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr))) 24 22 #define saa7146_read(sxy,adr) readl(sxy->mem+(adr)) 25 23
+3 -1
include/media/saa7146_vv.h
··· 161 161 int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); 162 162 163 163 /* the extension can override this */ 164 - struct v4l2_ioctl_ops ops; 164 + struct v4l2_ioctl_ops vid_ops; 165 + struct v4l2_ioctl_ops vbi_ops; 165 166 /* pointer to the saa7146 core ops */ 166 167 const struct v4l2_ioctl_ops *core_ops; 167 168 ··· 201 200 202 201 /* from saa7146_video.c */ 203 202 extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops; 203 + extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops; 204 204 extern struct saa7146_use_ops saa7146_video_uops; 205 205 int saa7146_start_preview(struct saa7146_fh *fh); 206 206 int saa7146_stop_preview(struct saa7146_fh *fh);