1.1 从字符设备说起
熟悉v4l2用户空间编程的都知道, v4l2编程主要是调用一系列的ioctl函数去对v4l2设备进行打开, 关闭, 查询, 设置等操作. v4l2设备是一个字符设备, 而且其驱动的主要工作就是实现各种各样的ioctl.
v4l2的整体框架如下图所示
V4L2的整体框架图
上图中, 淡绿色背景为用户空间, 淡蓝色背景为内核空间. 椭圆表示相关的结构体, 子系统或实例. 方框表示相关的接口. 蓝色的椭圆表示这部分属于v4l2-core的内容. 从图中可以看出用户空间通过file_operations接口与内核空间进行交互, 因此驱动必须实现file_operations中的相关的内容, 其中比较重要的几个函数是open
, release
, ioctl
, mmap
, poll
. read
和write
是可以不需要实现的. 因为为了效率v4l2基本都是使用流io的方式来进行数据传输的. 在v4l2的核心中对这个file_operations
的实现如下:
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
这个v4l2_fops函数最终绑定在一个cdev上, 并注册到系统中. 之后对该v4l2设备的调用都是通过这个cdev的设备节点进行调用的. 这个cdev的指针被一个video_device结构体引用, 从而将cdev封装到了v4l2的框架中.
1.2 v4l2_fops的封装
这里以这个fops的mmap为例:
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{