1.V4L2 驱动中的核心结构体
v4l2_device;一个v4l2的总设备。
v4l2_sbudev:来描述camera等sensor设备,一般是指挂接在总线(i2c)上的摄像头
video_device:实际和处理器采集口相关的配置,一般该设备会完成注册以/dev/video0,video1的字符设备注册的形式暴露给应用层。
video_device的重要性在于它具备承上启下的作用,驱动实现的ioctl内容,刚好则是为用户的控制提供了内核的实现。当然内核ioctl向下又是能控制相关的vfe和sensor,如下
static struct video_device vfe_template = { .name = "vfe", .fops = &vfe_fops, //用户open的相关内容 .ioctl_ops = &vfe_ioctl_ops,//用户ioctl对应的相关内容 .release = video_device_release, };
static const struct v4l2_file_operations vfe_fops = { .owner = THIS_MODULE, .open = vfe_open, .release = vfe_close, .read = vfe_read, .poll = vfe_poll, .ioctl = video_ioctl2, //最终会调用v4l2_ioctl_ops这个实际处理器的相关处理逻辑 // //.unlocked_ioctl = .mmap = vfe_mmap, }; static const struct v4l2_ioctl_ops vfe_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_fmt_vid_cap = vidioc_g_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,//video buffer缓存申请 .vidioc_querybuf = vidioc_querybuf,//查询buffer属性,完成对用户v4l2的设置,为mmap做准备 .vidioc_qbuf = vidioc_qbuf,//入列 .vidioc_dqbuf = vidioc_dqbuf,//出列 .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_streamon = vidioc_streamon,//启动视频采集 .vidioc_streamoff = vidioc_streamoff, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif };
video_device除了实现对基本的视频端口的硬件初始化,还完成对相关的视频采集缓存区的维护,通过queue来维护采集逻辑,通过中断来触发处理。
2.视频采集的最底层部分当然是外设camera
不同的camera有不同的驱动,但是他都凌驾在i2c的控制器上。故实现camera的驱动,通常都是实现i2c_driver和i2c_client的相关内容。这里相关的i2c_adapter(和处理器自己的i2c总线特性相关,比如A31有4路i2c,故有4个 adapter)。
比如camera ov5640的驱动架构很简单,但是为了和专门的视频采集挂接在一起,他作为i2c_client的同时也是v4l2_sbudev子设备。
static const struct v4l2_subdev_ops sensor_ops = { .core = &sensor_core_ops, .video = &sensor_video_ops, };
这个结构体是作为v4l2子设备的op,会通过video device的ioctl来调用实现。
在video的驱动中,可以看到如下API:
v4l2_i2c_new_subdev_b oard():生成一个新的i2c的v4l2子设备,内部核心:是建立一个i2c_board_info(表明板级上的一个i2c client),并将其完成设备的注册,这会调用对应的camera驱动的probe函数。这里会调用函数:
v4l2_i2c_subdev_init(sd, client, &sensor_ops);//subdevice建立,与i2c client建立联系。
从上面的这个API的实现,建立了subdev和client的关系后,video这边就可以通过用户传入的ioctl命令来对subdev进行控制如:
v4l2_subdev_call内部会调用i2c_client的驱动处理即上文中的sensor_ops中的core和video过程。
到此为止,video device,subdev, sensor之间的关系基本理通,调用的顺序合理而且紧密,如下图所示。
图1: linux内核视频采集驱动架构