由于作者水平有限,错误之出,欢迎指正。
2.1 video_device
(1)用于创建和管理 v4l2 设备节点。首要任务:在 /dev/ 下创建设备文件。
(2).fops: 指向video 设备的struct v4l2_file_operations 结构体的指针
(3)sysfs 相关成员:
1).dev:video 设备的struct device 结构体
2).cdev:指向代表字符设备的 struct cdev 结构的指针
(4)
1).v4l2_dev:指向struct v4l2_device 结构的父设备的指针
2).dev_parent:指向struct device 父设备的指针
3).ctrl_handler:指向这个设备节点关联的控制处理程序的指针
4).queue:指向这个设备节点关联的struct vb2_queue 结构的指针
5).prio:指向含有设备优先级状态的struct v4l2_prio_state 结构的指针
(4).release:video 设备release() callback
(5).ioctl_ops:指向含有 ioctl callback 的struct v4l2_ioctl_ops 结构的指针
2.1.1 创建及销毁
(1)静态分配:嵌入到其他结构体中
一般不用释放空间,为release指定空函数video_device_release_empty()
(2)动态分配:video_device_alloc()
必须为video_device 指定release函数,该函数在video_device 的最后一个用户退出后被调用,释放所申请的空间。
2.1.2 初始化
(1)必须要初始化的成员:
1).v4l2_dev
2).name
3).fops
4).ioctl_ops
5).lock
6).prio:优先级,用来实现VIDIOC_G/S_PRIORITY。若为NULL,会使用v4l2_device的优先级。
(2)互斥锁 :lock
当lock不为NULL时,V4L2框架会使用此mutex确保操作的互斥性。
(3)优先级:prio
1)struc v4l2_prio_state 结构体,其实现为含有4个atomic_t 类型元素的数组prios。
3)在enum v4l2_priority 中以枚举的方式定义3个优先级
1> V4L2_PRIORITY_BACKGROUND:最低优先级,主要用于后台处理。
2> V4L2_PRIORITY_INTERACTIVE : 默认优先级。
3> V4L2_PRIORITY_RECORD :最高优先级。
4)如何操作v4l2_prio_stat结构体中的4个atomic_t变量,实现优先级管理?
1> 若这四个变量中的任何一个不为零,则表示该变量所对应的优先级有效。比如若prios[V4L2_PRIORITY_BACKGROUND]不为零,则程序处于V4L2_PRIORITY_BACKGROUND优先级。
2> 优先级的确定过程:从数组(atomic_t prios[4])末尾依次查询,返回第一个不为零的变量的位置。此位置即为程序的优先级。
5)优先级相关函数:
1> v4l2_prio_init 清零所有的优先级变量
2> v4l2_prio_change 设置指定的优先级(new)变量的值为1,并将以前的优先级(local)变量设置为0.
3> v4l2_prio_open 设置程序的优先级为V4L2_PRIORITY_DEFAULT
4> v4l2_prio_close 设置当前优先级变量的值为0
5> v4l2_prio_max 查询程序的优先级
6> v4l2_prio_check 查询以确定程序是否能在指定的优先级下工作
对于ioctl类的函数,读取操作一般不需要调用v4l2_prio_check检查优先级;但是写操作(更改设备状态的操作)则必须检查优先级。
(4)ioctl_ops 和 fops 成员
实现将用户的操作(函数调用)映射到实际的驱动代码中。
1)如何实现映射的?
1> 首先,使用fops将用户的ioctl操作映射到V4L2自己的__video_do_ioctl函数中,
2> 然后,通过ioctl_ops将具体的cmd传递给驱动中的相关函数。
v4l2在注册字符设备时,将该字符设备的file_operations赋值为v4l2_fops。vdev->cdev->ops 指向v4l2_fops,v4l2_fops的 .unlocked_ioctl 成员实现为v4l2_ioctl。
v4l2_ioctl的中:
1> 检查vdev->fops->unlocked_ioctl 是否初始化。
2> 已初始化(非NULL),调用v4l2_ioctl_get_lock()获得lock变量,并调用mutex_lock_interruptible()上锁,
3> 调用 video_is_registered() 检查video是否被注册; 如果已被注册,调用vdev->fops->unlocked_ioctl。
4> 释放互斥锁,mutex_unlock()
vdev->fops 指向soc_camera_fops对象,soc_camera_fops的unlocked_ioctl 成员实现为 video_ioctl2. video_ioctl2函数中仅仅调用video_usercopy()函数,video_usercopy函数会对用户传递过来的参数检查,将用户空间的数据拷贝到内核空间,调用指定的__video_do_ioctl函数,并将内核空间的数据拷贝到用户空间。
video_usercopy(file, cmd, arg, __video_do_ioctl);
__video_do_ioctl 是关键函数:
处理 IOCTL //待补充。。
struct v4l2_ioctl_info ??
2.1.3 注册
//这几个结构体是如何注册进去的?注册顺序?//待补充
(1)video_device 是如何被注册的?
在哪里调用?硬件相关具体驱动实现调用?
调用video_register_device 函数,这个函数直接调用__video_register_device。
在__video_register_device中会对 video_device 结构进行初始化,然后:
1)vdev 添加到 video_device 数组中次设备号对应的下标位置。
video_device 数组是static struct video_device * 类型的数组,定义在v4l2-dev.c文件中,数组大小为256。注册时没一个video_device struct 对象的指针都保存在这个数组中。
2)向系统中添加一个字符设备vdev->cdev
3)注册设备vdev->dev到sysfs系统中
4)注册实体vdev
最后会激活这个次设备,字符设备就能被使用了。
video_device 数组作用,获得struct video_device * 的指针:
在字符设备的ops 接口中,v4l2_open 等接口的实现,首先通过调用video_devdata()函数,得到对应的video_device 设备指针,进而进行针对v4l2设备相关的操作。
内存中每个file对象的f_inode字段指向的inode struct 的i_rdev成员是对应设备号,MINOR宏取其低20位即次设备号
(2)注册本质做了什么?为什么注册的接口是video core层来提供?
1)cdev_add
2)device_register
只调用两个函数: device_initialize 和 device_add
3)video_register_media_controller
2.2 v4l2 文件句柄
(1)file handle: 便于存储和管理文件相关的数据结构
1)比如,v4l2的event事件依托在v4l2 file handle上。
2)实现文件的多次打开。每个应用打开文件时,v4l2都会创建一个新file handle,并将文件相关的数据保存到其中,可以隔离不同的应用程序。
(2)struct v4l2_fh
1)每次通过 open 函数打开文件时,都会分配一个文件句柄。这个句柄的private_data 指向v4l2_fh结构体。
2)video_device 保存一个v4l2_fh的列表。
(3)驱动如何使用这个结构体?
//待补充
2.3 v4l2_device
(1)每一个 v4l2 device 必须创建一个 v4l2_device stuct , 可以是独立的或者是嵌入到一个更大的struct 中。
(2)注意:
1)该结构中的dev->driver_data 指向该结构
2)如果没有父设备,dev 可以是NULL
(3)v4l2 设备注册
v4l2_device_register()
2.4 v4l2子设备
2.5 v4l2 control handler 机制
2.6 v4l2 event机制
******************
references:
分析基于 linux kernel v4.9