本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email:gzzaigcn2012@gmail.com
前沿:2014年的博文就从这篇文章开始吧,又一次回到linux,过去的一年从dm3730再到dm6437,这次来到了全志的A31 4核处理器,每一次都是全新的事物,但是偶然间还是可以感受到对新事物的消化能力更强了,学习的速度也更快了。也许这正是所谓的经验,所谓的软实力吧。
linux下的视频v4l2在很久之前的博文DM6446的视频前端VPFE的驱动大框架解析等几篇中介绍了整个基于应用层的视频采集流程解析。由于最近再次看了3.3的内核版本后,有了更进一步的收获,和大家在这里分享。
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),相关内容可以看博文Linux下DM644x设备驱动I2C之总线驱动(一)详解。
比如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: A31 linux内核视频采集驱动架构