前言
__V412术语的意思是:video for linux version2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口.凡是内核中的子系统都有抽象底层硬件的差异,为上层提供统一的接口和提取出公共代码避免代码冗余等好处.,我们的摄像头驱动程序是属于字符设备驱动程序,对于复杂的字符设备驱动程序它引入了分层的概念,在我们之前写过的LCD驱动文章就是利用这种分层的概念,如下图所示,上一层的fbmem.c构造了一个fops结构体,里面有打开,读写函数,注册该结构体,这一层内核文件已经帮我们做好了,我们需要做的是硬件相关的一层,分配设置一个fb_info结构体然后注册告诉fbmem.c,当我们的app调用open,read,write函数时就会根据注册的fb_info结构体中的属性来操作硬件了,可以看出这样写的好处就是我们只需要专注于我们硬件层相关的东西即可,而且使得app使用统一的open,read,write函数调用,简单来说就是使得app层可以通过统一的接口就能访问各种设备
v4l2驱动架构如图所示,图中芯片模块对应Soc的各个子模块,video_device结构体主要用来控制Soc的video模块,v4l2_device会包含多个v4l2_subdev,每个v4l2_subdev 用来控制各自的子模块,某些驱动不需要v4l2_subdev,依靠video模块就能实现功能
V4L2支持三类设备:视频输入输出设备,VBI设备和radio设备(其实还支持更多类型的设备,暂不讨论),分别会在/dev目录下产生videoX,radioX和vbiX设备节点,我们常见的视频输入设备主要是摄像头,下图是V4L2在linux系统中的最简要的结构图
如上图所示,V4L2系统主要由4部分组成
字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间
V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数,是底层向上层注册的核心
平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev
具体的sensor驱动:主要上电,提供工作时钟,视频图像裁剪,流IO开启等,实现各种设备控制方法供上层调用并注v4l2_subdev.
从上图V4L2框架是一个标准的树形结构,v4l2_device充当了父设备,通过链表把所有注册到其下的子设备管理起来,这些设备可以是GRABBER,VBI或RADIO.V4l2_subdev是子设备,v4l2_subdev结构体包含了对设备操作的ops和ctrls,这部分代码和硬件相关,需要驱动工程师根据硬件实现,像摄像头设备需要实现控制上下电,读取ID,饱和度,对比度和视频数据流打开关闭的接口函数.Video_device用于创建子设备节点,把操作设备的接口暴露给用户空间.V4l2_fh是每个子设备的文件句柄,在打开设备节点文件时设置,方便上层索引到v4l2_ctrl_handler,v4l2_ctrl_handler管理设备的ctrls,这些ctrls(摄像头设备)包括调节饱和度,对比度和白平衡等。
虚拟视频驱动vivi.c分析:
vivi_init
vivi_create_instance
v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数
video_device_alloc
//设置
1.vfd:
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2.
vfd->v4l2_dev = &dev->v4l2_dev;//辅助作用,用于提供自旋锁,引用计数
3. 设置"ctrl属性"(用于APP的ioctl):
v4l2_ctrl_handler_init(hdl, 11);//初始化一个v4l2_ctrl_handler
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);//设置音量
dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1,