文章目录
- 一、V4L2简介
- 二、v4l2驱动关键组件
- (一)video_device结构体
- v4l2操作方法结构体
- v4l2的ioctl操作方法结构体
- (二)v4l2_device结构体
一、V4L2简介
V4L2,即Video for Linux two,是Linux内核中用于视频设备驱动的框架。
它提供了一套统一的接口规范给用户空间的应用程序,使其能够访问和控制视频设备。
v4l2设备本质是字符设备驱动,当调用cdev的fops时,就会回调到v4l2的操作方法结构体,即v4l2_file_operations。
当调用ioctl函数时,会回调到v4l2的操作方法结构体,然后再回调到ioctl操作方法结构体,即v4l2_ioctl_ops。
首先,需要分配并初始化video_device结构体,
然后,设置其成员变量,如设备名、文件操作函数集、ioctl操作函数集等,注意必须填充v4l2_dev->name成员
最后,调用video_register_device函数将video_device结构体注册到系统中,创建一个对应的设备文件(如/dev/videoX)。
二、v4l2驱动关键组件
video_device:表示一个字符设备,包含cdev和v4l2_device等成员
v4l2_device:表示一个v4l2设备实例,内部通过链表管理从属所有子设备。
(一)video_device结构体
V4L2驱动框架中表示视频设备的核心结构体。
它包含了设备的各种属性和操作函数,如字符设备名、操作函数集以及ioctl操作函数集。
//该结构体用于创建和管理v4l2设备节点
struct video_device
{
const struct v4l2_file_operations *fops; //v4l2_file_operations操作方法结构体
struct device dev; //视频设备结构体device
struct cdev *cdev; //字符设备
struct v4l2_device *v4l2_dev; //v4l2_device父类
struct device *dev_parent; //device结构体的父类
/* 设备信息 */
char name[32]; //视频设备名
enum vfl_devnode_type vfl_type; //v4l设备类型
int minor; //次设备号
u16 num; //视频设备节点号
unsigned long flags; //视频设备标志位
/* 回调函数 */
void (*release)(struct video_device *vdev); //视频设备注销的回调函数
const struct v4l2_ioctl_ops *ioctl_ops; //v4l2的ioctl回调函数
struct mutex *lock; //序列化操作锁
};
v4l2操作方法结构体
struct v4l2_file_operations {
struct module *owner;
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
__poll_t (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
unsigned long (*get_unmapped_area) (struct file *, unsigned long,unsigned long, unsigned long, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct file *);
int (*release) (struct file *);
};
v4l2的ioctl操作方法结构体
struct v4l2_ioctl_ops {
//查询是否是摄像头设备
int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
//列举摄像头支持的数据格式
int (*vidioc_enum_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_fmtdesc *f);
//获取当前设置的数据格式
int (*vidioc_g_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f);
//尝试设置数据格式到摄像头
int (*vidioc_try_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f);
//设置数据格式给摄像头
int (*vidioc_s_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f);
//申请内存
int (*vidioc_reqbufs)(struct file *file, void *fh, struct v4l2_requestbuffers *b);
//查询内存
int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
//将申请的内存放入到队列尾
int (*vidioc_qbuf)(struct file *file, void *fh, struct v4l2_buffer *b);
//将内存从队列头取出
int (*vidioc_dqbuf)(struct file *file, void *fh, struct v4l2_buffer *b);
//开启摄像头
int (*vidioc_streamon)(struct file *file, void *fh, enum v4l2_buf_type i);
//关闭摄像头
int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
(二)v4l2_device结构体
表示一个V4L2设备,通常作为管理所有子设备的根节点。
它包含了指向子设备的指针数组,以及用于管理子设备的各种函数。
通过v4l2_device_register函数,可以将v4l2_device结构体注册到系统中。
v4l2_dev继承于device,描述摄像头设备,所有的子设备由链表连接
//v4l2设备驱动的主结构体
struct v4l2_device {
struct device *dev; //指向struct device的指针
struct media_device *mdev; //指向struct media_device的指针,可能为NULL
struct list_head subdevs; //已注册的子设备,以链表形式管理
spinlock_t lock; //自旋锁
char name[V4L2_DEVICE_NAME_SIZE]; //v4l2的设备名
void (*release)(struct v4l2_device *v4l2_dev); //当引用计数降为0时调用的释放函数
};
--------------------
//以链表形式保存每一个v4l2设备的子设备
struct list_head {
struct list_head *next, *prev;
};