当前位置:   article > 正文

Video4Linux框架简介(3) - video_device

video_device

video_device是指向v4l2具体的设备,名字同样有些不够准确,事实上,根据注册时传入type(本例中使用的是VFL_TYPE_GRABBER,也就是视频输入设备 -- Camera)的不同,可以分为视频输入,视频输出,VBI,Radio等。

第一步先是在驱动的probe函数中添加video_device的初始化并注册:

  1. struct skeleton {
  2. struct pci_dev *pdev;
  3. struct v4l2_device v4l2_dev;
  4. struct video_device vdev;
  5. struct mutex lock;
  6. };
  7. static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  8. {
  9. ...
  10. mutex_init(&skel->lock);
  11. vdev = &skel->vdev;
  12. strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
  13. vdev->release = video_device_release_empty; //第一组
  14. vdev->fops = &skel_fops, //第二组
  15. vdev->ioctl_ops = &skel_ioctl_ops, //第三组
  16. vdev->lock = &skel->lock; //驱动锁,不设置的话所有同步都需要驱动开发者自己来维护,相当痛苦
  17. vdev->v4l2_dev = &skel->v4l2_dev; //指向root
  18. /* Supported SDTV standards, if any */
  19. vdev->tvnorms = V4L2_STD_ALL; //支持所有的视频格式
  20. set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
  21. video_set_drvdata(vdev, skel); //设置驱动数据
  22. ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); // VFL_TYPE_GRABBER就是视频输入设备
  23. if (ret)
  24. goto v4l2_dev_unreg;
  25. dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
  26. return 0;
  27. ...
  28. }

(译注)video_device一共有三组文件操作函数:

第一组只有一个,就是release,这个回调函数会在最后一个video_device的用户退出时被调用,将video_device嵌入大结构体的情况下必须实现这个回调函数,主要是释放响应的资源。

第二组是v4l2相关的文件操作函数,包括open/release/read/write等,这个release和上面的不同,只是某个用户关闭文件节点时会被调用,read/write未必要实现。

第三组是v4l2相关的ioctl操作函数,由于视频设备本身的复杂性,接口不断地增加,内核开发者发现ioctl是一个最好扩展API的方式;不过好在驱动开发者不需要实现所有的ioctl回调函数,事实上大部分都不需要。


第二步,实现相应的回调函数,这里省略了第一组release:

  1. static int skeleton_querycap(struct file *file, void *priv,
  2. struct v4l2_capability *cap)
  3. {
  4. struct skeleton *skel = video_drvdata(file);
  5. strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
  6. strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card));
  7. snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
  8. pci_name(skel->pdev));
  9. cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
  10. V4L2_CAP_STREAMING;
  11. cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
  12. return 0;
  13. }
  14. static const struct v4l2_ioctl_ops skel_ioctl_ops = {
  15. .vidioc_querycap = skeleton_querycap, //首先要实现的就是查询能力值这个回调函数
  16. };
  17. static const struct v4l2_file_operations skel_fops = {
  18. .owner = THIS_MODULE,
  19. .open = v4l2_fh_open,
  20. .release = v4l2_fh_release,
  21. .unlocked_ioctl = video_ioctl2,
  22. };


最后,总结一下video_deivce:

●可以表示video / radio / vbi / v4l2_subdev节点。

通常也表示DMA引擎:指向vb2_queue的指针。

指向ioctl操作的v4l2_ioctl_ops的指针。

指向文件操作的v4l2_file_operations的指针。

核心锁支持:lock mutexvb2_queue.lock

-如果lock == NULL,则驱动程序自行完成所有同步锁定,(译注:这会是很痛苦的一件事情,尽量别给自己挖坑)。

-如果lock= NULL,但vb2_queue.lock == NULL,则所有ioctl通过该核心锁进行同步保护,包括流ioctl

-如果vb2_queue.lock也是!= NULL,那么该锁用于所有流ioctl:如果其他ioctl会持核心锁很长时间(典型的USB驱动程序)的情况下非常有用。

-驱动程序始终对非ioctl文件操作执行所有锁定。

我个人的建议:使用核心锁。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/263141
推荐阅读
相关标签
  

闽ICP备14008679号