工作:
static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表
LIST_HEAD(subdev_list)----+ LIST_HEAD(notifier_list)----+
| |
|挂载 | 挂载
| |
struct techpoint | +->struct v4l2_async_notifier----+
struct v4l2_subdev subdev; ----------+----------------|----->struct v4l2_subdev *sd;
const struct v4l2_subdev_ops *ops |
struct v4l2_device *v4l2_dev; |
struct v4l2_async_notifier *subdev_notifier; ------+
&i2c1 {
/delete-node/ ar0230@10;
/delete-node/ ov4689@36;
/delete-node/ os04a10@36;
tp2855_1: tp2855_1@44 {
compatible = "techpoint,tp2855";
reg = <0x44>; //i2c地址
...
port {
ucam_out0: endpoint {
remote-endpoint = <&csi_dphy0_input>; //Sensor连接到mipi
data-lanes = <1 2 3 4>;
};
};
};
tp2855_2: tp2855_2@45 {
compatible = "techpoint,tp2855";
reg = <0x45>; //i2c地址
...
port {
ucam_out1: endpoint {
remote-endpoint = <&csi_dphy1_input>; //Sensor连接到mipi csi_dphy1_input
data-lanes = <1 2 3 4>;
};
};
};
};
kernel\drivers\media\i2c\techpoint\techpoint_v4l2.c
static const struct v4l2_subdev_pad_ops techpoint_subdev_pad_ops = {
.enum_mbus_code = techpoint_enum_mbus_code,
.enum_frame_size = techpoint_enum_frame_sizes,
.get_fmt = techpoint_get_fmt,
.set_fmt = techpoint_set_fmt,
};
static const struct v4l2_subdev_video_ops techpoint_video_ops = {
.s_stream = techpoint_stream,
.g_mbus_config = techpoint_g_mbus_config,
.g_frame_interval = techpoint_g_frame_interval,
.querystd = techpoint_querystd,
};
static const struct v4l2_subdev_core_ops techpoint_core_ops = {
.s_power = techpoint_power,
.ioctl = techpoint_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = techpoint_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_ops techpoint_subdev_ops = {
.core = &techpoint_core_ops,
.video = &techpoint_video_ops,
.pad = &techpoint_subdev_pad_ops,
};
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops techpoint_internal_ops = {
.open = techpoint_open,
};
#endif
/*
1 填充了subdev的相关成员信息 struct v4l2_subdev *sd;
sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
sd->ops = &imx291_subdev_ops;
sd->v4l2_dev = NULL;
sd->flags = V4L2_SUBDEV_FL_IS_I2C
2 记录 v4l2_subdev 到 异步通知notifier notifier->sd = sd
并将notifier挂载到全局链表notifier_list上
3 subdev 挂载到 全局链表subdev_list上
*/
static int techpoint_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct techpoint *techpoint;
struct v4l2_subdev *sd;
techpoint = devm_kzalloc(dev, sizeof(*techpoint), GFP_KERNEL);
if (!techpoint)
return -ENOMEM;
techpoint->client = client;
techpoint->supplies = NULL;
...
//注册
/*
sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
sd->ops = &imx291_subdev_ops;
sd->v4l2_dev = NULL;
sd->flags = V4L2_SUBDEV_FL_IS_I2C
*/
sd = &techpoint->subdev;
v4l2_i2c_subdev_init(sd, client, &techpoint_subdev_ops);
...
/*
1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
2 subdev挂载到 全局链表subdev_list上
*/
ret = v4l2_async_register_subdev_sensor_common(sd);
}
static const struct of_device_id techpoint_of_match[] = {
{ .compatible = "techpoint,tp2855" },
{ .compatible = "techpoint,tp2815" },
{ .compatible = "techpoint,tp9930" },
{},
};
static const struct i2c_device_id techpoint_match_id[] = {
{ "techpoint", 0 },
{ },
};
static struct i2c_driver techpoint_i2c_driver = {
.driver = {
.name = TECHPOINT_NAME,
.pm = &techpoint_pm_ops,
.of_match_table = of_match_ptr(techpoint_of_match),
},
.probe = &techpoint_probe,
.remove = &techpoint_remove,
.id_table = techpoint_match_id,
};
static int __init sensor_mod_init(void)
{
return i2c_add_driver(&techpoint_i2c_driver);
}
static void __exit sensor_mod_exit(void)
{
i2c_del_driver(&techpoint_i2c_driver);
}
kernel\drivers\media\v4l2-core\v4l2-fwnode.c
/*
1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
2 subdev挂载到 全局链表subdev_list上
*/
int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *notifier;
int ret;
if (WARN_ON(!sd->dev))
return -ENODEV;
//初始化为空
notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
if (!notifier)
return -ENOMEM;
...
/* 主要就是将异步通知notifier挂载到 全局notifier_list链表上
1 记录v4l2_subdev 到 异步通知notifier notifier->sd = sd
2 将异步通知notifier挂载到 全局notifier_list链表上
v4l2_subdev
v4l2_async_notifier
*/
ret = v4l2_async_subdev_notifier_register(sd, notifier);
if (ret < 0)
goto out_cleanup;
//将当前subdev挂载到 全局链表subdev_list上
ret = v4l2_async_register_subdev(sd);
if (ret < 0)
goto out_unregister;
/* subdev和notifier你中有我,我中有你 */
sd->subdev_notifier = notifier;
return 0;
out_unregister:
v4l2_async_notifier_unregister(notifier);
out_cleanup:
v4l2_async_notifier_cleanup(notifier);
kfree(notifier);
return ret;
}
kernel\drivers\media\v4l2-core\v4l2-async.c
static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表
/*
参数1 struct mipidphy_priv -> v4l2_subdev
参数2 struct mipidphy_priv -> v4l2_async_notifier
*/
int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
struct v4l2_async_notifier *notifier)
{
int ret;
if (WARN_ON(!sd || notifier->v4l2_dev))
return -EINVAL;
/*
* 记录subdev
*/
notifier->sd = sd;
/*
参数 struct mipidphy_priv -> v4l2_async_notifier
异步通知注册 主要就是操作notifier
*/
ret = __v4l2_async_notifier_register(notifier);
if (ret)
notifier->sd = NULL;
return ret;
}
/*
参数 struct mipidphy_priv -> v4l2_async_notifier
*/
static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
struct device *dev =
notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
struct v4l2_async_subdev *asd;
int ret;
int i;
//不满足条件 跳出
if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
return -EINVAL;
mutex_lock(&list_lock);
//对于 sensor驱动 无,跳过
for (i = 0; i < notifier->num_subdevs; i++) {
...
}
/*
该函数只能从V4L2顶层设备:rkcif_mipi设备 开始执行。因为其他三个subdev设备自己刚开始是没有初始化 自己的 父通知器 以及 自己的通知器所管理的 v4l2_device设备的
所以这里 sensor 不执行
*/
ret = v4l2_async_notifier_try_all_subdevs(notifier);
/* 参数1 当前设备异步通知器
* 条件不满足,暂时不进入分析,不满足原因如下
* 1. notifier->parent == NULL
* 2. notifier->v4l2_dev == NULL
所以其他三个subdev设备 独自初始化时 不满足该函数运行条件
只有 rkcif_mipi 能执行该函数
*/
ret = v4l2_async_notifier_try_complete(notifier);
/*
* 以上2个函数可以看出来,v4l2_dev为空时都不会执行
* 将这个notifer挂载到链表notifier_list上
*/
list_add(¬ifier->list, ¬ifier_list);
}
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_async_notifier *notifier;
int ret;
if (!sd->fwnode && sd->dev)
sd->fwnode = dev_fwnode(sd->dev);
mutex_lock(&list_lock);
INIT_LIST_HEAD(&sd->async_list);
...
/*
* 没有匹配到相关的信息
* 将当前subdev挂载到 全局链表subdev_list上
*/
list_add(&sd->async_list, &subdev_list);
...
return ret;
}