Video4Linux框架简介(3) - video_device

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;
...
} 

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

第一组只有一个,就是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 mutexvb2_queue.lock

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

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

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

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

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


你可能感兴趣的:(Linux,Kernel,V4L2,Camera,Camera,linux,kernel,V4L2)