赞
踩
video_device是指向v4l2具体的设备,名字同样有些不够准确,事实上,根据注册时传入type(本例中使用的是VFL_TYPE_GRABBER,也就是视频输入设备 -- Camera)的不同,可以分为视频输入,视频输出,VBI,Radio等。
第一步先是在驱动的probe函数中添加video_device的初始化并注册:
- struct skeleton {
- struct pci_dev *pdev;
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct mutex lock;
- };
- static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- {
- ...
- mutex_init(&skel->lock);
- vdev = &skel->vdev;
- strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
- vdev->release = video_device_release_empty; //第一组
- vdev->fops = &skel_fops, //第二组
- vdev->ioctl_ops = &skel_ioctl_ops, //第三组
- vdev->lock = &skel->lock; //驱动锁,不设置的话所有同步都需要驱动开发者自己来维护,相当痛苦
- vdev->v4l2_dev = &skel->v4l2_dev; //指向root
- /* Supported SDTV standards, if any */
- vdev->tvnorms = V4L2_STD_ALL; //支持所有的视频格式
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
- video_set_drvdata(vdev, skel); //设置驱动数据
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); // VFL_TYPE_GRABBER就是视频输入设备
- if (ret)
- goto v4l2_dev_unreg;
- dev_info(&pdev->dev, "V4L2 PCI Skeleton Driver loaded\n");
- return 0;
- ...
- }
第一组只有一个,就是release,这个回调函数会在最后一个video_device的用户退出时被调用,将video_device嵌入大结构体的情况下必须实现这个回调函数,主要是释放响应的资源。
第二组是v4l2相关的文件操作函数,包括open/release/read/write等,这个release和上面的不同,只是某个用户关闭文件节点时会被调用,read/write未必要实现。
第三组是v4l2相关的ioctl操作函数,由于视频设备本身的复杂性,接口不断地增加,内核开发者发现ioctl是一个最好扩展API的方式;不过好在驱动开发者不需要实现所有的ioctl回调函数,事实上大部分都不需要。
第二步,实现相应的回调函数,这里省略了第一组release:
- static int skeleton_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
- {
- struct skeleton *skel = video_drvdata(file);
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, "V4L2 PCI Skeleton", sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
- pci_name(skel->pdev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
- }
- static const struct v4l2_ioctl_ops skel_ioctl_ops = {
- .vidioc_querycap = skeleton_querycap, //首先要实现的就是查询能力值这个回调函数
- };
- static const struct v4l2_file_operations skel_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = v4l2_fh_release,
- .unlocked_ioctl = video_ioctl2,
- };
最后,总结一下video_deivce:
●可以表示video / radio / vbi / v4l2_subdev节点。
●通常也表示DMA引擎:指向vb2_queue的指针。
●指向ioctl操作的v4l2_ioctl_ops的指针。
●指向文件操作的v4l2_file_operations的指针。
●核心锁支持:lock mutex,vb2_queue.lock:
-如果lock == NULL,则驱动程序自行完成所有同步锁定,(译注:这会是很痛苦的一件事情,尽量别给自己挖坑)。
-如果lock!= NULL,但vb2_queue.lock == NULL,则所有ioctl通过该核心锁进行同步保护,包括流ioctl。
-如果vb2_queue.lock也是!= NULL,那么该锁用于所有流ioctl:如果其他ioctl会持核心锁很长时间(典型的USB驱动程序)的情况下非常有用。
-驱动程序始终对非ioctl文件操作执行所有锁定。
●我个人的建议:使用核心锁。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。