在上节中我们介绍V4L2的概念、v4l2的设备以及上层点击APP时的调用过程;这节我们详细分底层驱动的注册以及API的调用过程。
参考链接:https://blog.youkuaiyun.com/jack_a8/article/details/43113103向这位老师傅致敬,写的非常好!
言归正传,在这节中slave设备是ti940_mipi.c,master设备就不说了。先来看看流程图:
这张图基本上能说明了各个调用过程,接下里我们分析代码:
Dvr设备是通过I2C进行通信的,既然是I2C设备,那么肯定也有主从分别,现在看下slave设备注册,以ti940为例:
staticstruct v4l2_int_ioctl_desc ti_ub940_ioctl_desc[] = {
{ vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init },
{vidioc_int_dev_exit_num, ioctl_dev_exit },
{ vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power },
{ vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm },
{ vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init },
{ vidioc_int_enum_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_enum_fmt_cap },
{vidioc_int_enum_frameintervals_num,(v4l2_int_ioctl_func*) ioctl_enum_frameintervals},
{ vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap },
{ vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm },
{ vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm },
{ vidioc_int_enum_framesizes_num,(v4l2_int_ioctl_func*)ioctl_enum_framesizes },
{ vidioc_int_g_chip_ident_num, (v4l2_int_ioctl_func*)ioctl_g_chip_ident },
{ vidioc_int_reset_num, (v4l2_int_ioctl_func*)ioctl_reset },
};
staticstruct v4l2_int_slave ti_ub940_slave = {
.ioctls =ti_ub940_ioctl_desc,
.num_ioctls = ARRAY_SIZE(ti_ub940_ioctl_desc),
};
staticstruct v4l2_int_device ti_ub940_int_device = {
.module =THIS_MODULE,
.name ="ti_ub940",
.type =v4l2_int_type_slave,
.u =
{
.slave = &ti_ub940_slave,
},
};
在probe函数中用 v4l2_int_device_register(&ti_ub940_int_device);注册v4l2_int_device
intv4l2_int_device_register(struct v4l2_int_device *d)
{
if (d->type == v4l2_int_type_slave)
sort(d->u.slave->ioctls,d->u.slave->num_ioctls, //依次排序存储
sizeof(struct v4l2_int_ioctl_desc),
&ioctl_sort_cmp, NULL);
mutex_lock(&mutex);
list_add(&d->head, &int_list); //主从设备都会加到int_list链表中
v4l2_int_device_try_attach_all(); //调用此函数进行适配
mutex_unlock(&mutex);
return 0;
}
voidv4l2_int_device_try_attach_all(void)
{
struct v4l2_int_device *m, *s;
list_for_each_entry(m, &int_list,head) { //对链表中的每一个master进行适配
if (m->type !=v4l2_int_type_master)
continue;
list_for_each_entry(s,&int_list, head) { //对链表中每一个slave进行适配
if (s->type !=v4l2_int_type_slave)
continue;
/* Slave is connected? */
if(s->u.slave->master) //slave有master了就继续
continue;
/* Slave wants to attach tomaster? */
if(s->u.slave->attach_to[0] != 0
&& strncmp(m->name,s->u.slave->attach_to,
V4L2NAMESIZE))
&nbs