我们先看具体sensor slave怎么注册到v4l2的:
static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = {//ioctl与对应的序号联系在一起,在v4l2层将被转换成固定的名字
{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_g_needs_reset_num,
(v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
{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_try_fmt_cap_num,
(v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},
/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_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_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */
{vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *)ioctl_g_ctrl},
{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl},
};
static struct v4l2_int_slave ov5642_slave = {//slave
.ioctls = ov5642_ioctl_desc,
.num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc),
};
static struct v4l2_int_device ov5642_int_device = {
.module = THIS_MODULE,
.name = "ov5642",
.type = v4l2_int_type_slave,
.u = {
.slave = &ov5642_slave,
},
};
v4l2_int_device_register(&ov5642_int_device);//注册v4l2_int_device:
int v4l2_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);//无论是slave还是master都会添加到int_list中
v4l2_int_device_try_attach_all();//都会做匹配动作
mutex_unlock(&mutex);
return 0;
}
我们看下v4l2匹配函数v4l2_int_device_try_attach_all():
void v4l2_int_device_try_attach_all(void)
{
struct v4l2_int_device *m, *s;
list_for_each_entry(m, &int_list, head) {//对int_list中每个master
if (m->type != v4l2_int_type_master)
continue;
list_for_each_entry(s, &int_list, head) {//对int_list中的每个salve
if (s->type != v4l2_int_type_slave)
continue;
/* Slave is connected? */
if (s->u.slave->master)//slave中master已经被赋值说明已经连接起来
continue;
/* Slave wants to attach to master? */
if (s->u.slave->attach_to[0] != 0
&& strncmp(m->name, s->u.slave->attach_to,
V4L2NAMESIZE))
continue;
if (!try_module_get(m->module))
continue;
s->u.slave->master = m;//说明slave找到了master
if (m->u.master->attach(s)) {//执行master的匹配函数
s->u.slave->master = NULL;
module_put(m->module);
continue;
}
}
}
}
上面即是slave注册到v4l2的过程,也许你会比较的奇怪,开始那些ioctl哪去呢?系统怎么访问呢?下面我们就分析这个过程。
我们在v4l2-int-device.h中有这样的定义:
/* IOCTL command numbers. */
enum v4l2_int_ioctl_num {
/*
*
* "Proper" V4L ioctls, as in struct video_device.
*
*/
vidioc_int_enum_fmt_cap_num = 1,
vidioc_int_g_fmt_cap_num,
vidioc_int_s_fmt_cap_num,
vidioc_int_try_fmt_cap_num,
vidioc_int_queryctrl_num,
vidioc_int_g_ctrl_num,
vidioc_int_s_ctrl_num,
vidioc_int_cropcap_num,
vidioc_int_g_crop_num,
vidioc_int_s_crop_num,
vidioc_int_g_parm_num,
vidioc_int_s_parm_num,
vidioc_int_querystd_num,
vidioc_int_s_std_num,
vidioc_int_s_video_routing_num,
......
};
V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
我们看下V4L2_INT_WRAPPER_1这个宏定义:
#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \
static inline int vidioc_int_##name(struct v4l2_int_device *d, \
arg_type asterisk arg) \
{ \
return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \
(void *)(unsigned long)arg); \
} \
\
static inline struct v4l2_int_ioctl_desc \
vidioc_int_##name##_cb(int (*func) \
(struct v4l2_int_device *, \
arg_type asterisk)) \
{ \
struct v4l2_int_ioctl_desc desc; \
\
desc.num = vidioc_int_##name##_num; \
desc.func = (v4l2_int_ioctl_func *)func; \
\
return desc; \
}
我们举例来说,V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *),那也就是有了这样的定义:
static inline int vidioc_int_s_ctrl(struct v4l2_int_device *d,
arg_type asterisk arg)
{
return v4l2_int_ioctl_1(d, vidioc_int_s_ctrl_num,
(void *)(unsigned long)arg);
}
static inline struct v4l2_int_ioctl_desc
vidioc_int_s_ctrl_cb(int (*func)
(struct v4l2_int_device *,
arg_type asterisk))
{
struct v4l2_int_ioctl_desc desc;
desc.num = vidioc_int_s_ctrl_num;
desc.func = (v4l2_int_ioctl_func *)func;
return desc;
static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = {//ioctl与对应的序号联系在一起,在v4l2层将被转换成固定的名字
{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_g_needs_reset_num,
(v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
{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_try_fmt_cap_num,
(v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},
/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_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_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */
{vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *)ioctl_g_ctrl},
{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl},
};
static struct v4l2_int_slave ov5642_slave = {//slave
.ioctls = ov5642_ioctl_desc,
.num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc),
};
static struct v4l2_int_device ov5642_int_device = {
.module = THIS_MODULE,
.name = "ov5642",
.type = v4l2_int_type_slave,
.u = {
.slave = &ov5642_slave,
},
};
v4l2_int_device_register(&ov5642_int_device);//注册v4l2_int_device:
int v4l2_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);//无论是slave还是master都会添加到int_list中
v4l2_int_device_try_attach_all();//都会做匹配动作
mutex_unlock(&mutex);
return 0;
}
我们看下v4l2匹配函数v4l2_int_device_try_attach_all():
void v4l2_int_device_try_attach_all(void)
{
struct v4l2_int_device *m, *s;
list_for_each_entry(m, &int_list, head) {//对int_list中每个master
if (m->type != v4l2_int_type_master)
continue;
list_for_each_entry(s, &int_list, head) {//对int_list中的每个salve
if (s->type != v4l2_int_type_slave)
continue;
/* Slave is connected? */
if (s->u.slave->master)//slave中master已经被赋值说明已经连接起来
continue;
/* Slave wants to attach to master? */
if (s->u.slave->attach_to[0] != 0
&& strncmp(m->name, s->u.slave->attach_to,
V4L2NAMESIZE))
continue;
if (!try_module_get(m->module))
continue;
s->u.slave->master = m;//说明slave找到了master
if (m->u.master->attach(s)) {//执行master的匹配函数
s->u.slave->master = NULL;
module_put(m->module);
continue;
}
}
}
}
上面即是slave注册到v4l2的过程,也许你会比较的奇怪,开始那些ioctl哪去呢?系统怎么访问呢?下面我们就分析这个过程。
我们在v4l2-int-device.h中有这样的定义:
/* IOCTL command numbers. */
enum v4l2_int_ioctl_num {
/*
*
* "Proper" V4L ioctls, as in struct video_device.
*
*/
vidioc_int_enum_fmt_cap_num = 1,
vidioc_int_g_fmt_cap_num,
vidioc_int_s_fmt_cap_num,
vidioc_int_try_fmt_cap_num,
vidioc_int_queryctrl_num,
vidioc_int_g_ctrl_num,
vidioc_int_s_ctrl_num,
vidioc_int_cropcap_num,
vidioc_int_g_crop_num,
vidioc_int_s_crop_num,
vidioc_int_g_parm_num,
vidioc_int_s_parm_num,
vidioc_int_querystd_num,
vidioc_int_s_std_num,
vidioc_int_s_video_routing_num,
......
};
V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
我们看下V4L2_INT_WRAPPER_1这个宏定义:
#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \
static inline int vidioc_int_##name(struct v4l2_int_device *d, \
arg_type asterisk arg) \
{ \
return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \
(void *)(unsigned long)arg); \
} \
\
static inline struct v4l2_int_ioctl_desc \
vidioc_int_##name##_cb(int (*func) \
(struct v4l2_int_device *, \
arg_type asterisk)) \
{ \
struct v4l2_int_ioctl_desc desc; \
\
desc.num = vidioc_int_##name##_num; \
desc.func = (v4l2_int_ioctl_func *)func; \
\
return desc; \
}
我们举例来说,V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *),那也就是有了这样的定义:
static inline int vidioc_int_s_ctrl(struct v4l2_int_device *d,
arg_type asterisk arg)
{
return v4l2_int_ioctl_1(d, vidioc_int_s_ctrl_num,
(void *)(unsigned long)arg);
}
static inline struct v4l2_int_ioctl_desc
vidioc_int_s_ctrl_cb(int (*func)
(struct v4l2_int_device *,
arg_type asterisk))
{
struct v4l2_int_ioctl_desc desc;
desc.num = vidioc_int_s_ctrl_num;
desc.func = (v4l2_int_ioctl_func *)func;
return desc;