V4l2驱动架构
驱动架构图
所有的驱动程序有以下结构:
1) 每个设备包含设备状态的实例结构。
2) 子设备的初始化和命令方式(如果有).
3) 创建V4L2的设备节点 (/dev/videoX, /dev/vbiX and /dev/radioX)和跟踪设备节点的具体数据。
4)文件句柄特定的结构,包含每个文件句柄数据;
5) 视频缓冲处理。
驱动源码分析
vivi.c 虚拟视频驱动程序
----- 此代码模拟一个真正的视频设备V4L2 API (位于drivers/media/video目录下)
入口:+int __init vivi_init(void)
+ vivi_create_instance(i) /*创建设备*//**/。
+ 分配一个vivi_dev的结构体 /*它嵌套这结构体v4l2_device 和video_device*/
+ v4l2_device_register(NULL, &dev->v4l2_dev);/*注册vivi_dev中的V4l2_device*/
+ 初始化视频的DMA队列
+ 初始化锁
+ video_device_alloc(); 动态分配video_device结构体
+ 构建一个video_device结构体 vivi_template 并赋给上面分配的video_device
static struct video_device vivi_template = {
. name = "vivi",
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.minor = -1,
.release = video_device_release,
.tvnorms = V4L2_STD_525_60,
.current_norm = V4L2_STD_NTSC_M,
};
+ video_set_drvdata(vfd, dev);设置驱动程序专有数据
+ 所有控件设置为其默认值
+ list_add_tail(&dev->vivi_devlist, &vivi_devlist);添加到设备列表
+ 构建 v4l2_file_operations 结构体vivi_fops 并实现.open .release .read .poll .mmap函数
----- .ioctl 用标准的v4l2控制处理程序
+ 构建 v4l2_ioctl_ops结构体 vivi_ioctl_ops
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
};
+ int vivi_open(struct file *file)
+ vivi_dev *dev = video_drvdata(file); 访问驱动程序专用数据
+ 分配+初始化句柄(vivi_fh)数据
+ 重置帧计数器
+ videobuf_queue_vmalloc_init(); 初始化视频缓冲队列
+ 开启一个新线程用于开始和暂停
+ 实现自定义的v4l2_ioctl_ops 函数