工作:
即这样
所有设备注册是按照这个图来的。前面分析的是 tp2855_1@44 --> mipi csi phy --> csi2_dev 。这3个都是subdev,只有rkcif_mipi是video
sensor 模块 mipi物理层 mipi协议解析 VICAP模块
sensor-------->csi2_dcphy0 ------> mipi0_csi2 -----> rkcif_mipi_lvds
&rkcif_mipi_lvds {
status = "okay";
rockchip,cif-monitor = <3 2 25 1000 5>;
port {
/* MIPI CSI-2 endpoint */
cif_mipi_in: endpoint {
remote-endpoint = <&mipi_csi2_output>;
data-lanes = <1 2 3 4>;
};
};
};
kernel\drivers\media\platform\rockchip\cif\dev.c
static const struct of_device_id rkcif_plat_of_match[] = {
{
.compatible = "rockchip,rkcif-dvp",
.data = &rkcif_dvp_match_data,
},
{
.compatible = "rockchip,rkcif-mipi-lvds",
.data = &rkcif_mipi_lvds_match_data,
},
{},
};
//已经成功探测到其中一个子设备,只是把子设备 mipi csi的subdev放入cif_dev->sensors的数组中存储
/*
参数1 rkcif_device->v4l2_async_notifier
参数2 相关联的 mipi csi 的 v4l2_subdev
参数3 相关联的 mipi csi 的dts节点
*/
static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
//当前 rkcif_device 设备信息
struct rkcif_device *cif_dev = container_of(notifier,
struct rkcif_device, notifier);
struct rkcif_async_subdev *s_asd = container_of(asd,
struct rkcif_async_subdev, asd);
if (cif_dev->num_sensors == ARRAY_SIZE(cif_dev->sensors)) {
v4l2_err(&cif_dev->v4l2_dev,
"%s: the num of subdev is beyond %d\n",
__func__, cif_dev->num_sensors);
return -EBUSY;
}
//将 相关联的 mipi csi 的 v4l2_subdev 添加到 rkcif_device设备的子sensor[]数组中
cif_dev->sensors[cif_dev->num_sensors].lanes = s_asd->lanes;
cif_dev->sensors[cif_dev->num_sensors].mbus = s_asd->mbus;
cif_dev->sensors[cif_dev->num_sensors].sd = subdev;
++cif_dev->num_sensors;
v4l2_err(subdev, "Async registered subdev\n");
return 0;
}
static int rkcif_plat_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
//设备对应的设备树节点 rkcif_mipi_lvds
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct rkcif_device *cif_dev;
const struct rkcif_match_data *data;
int ret;
//分配 rkcif_device 空间
cif_dev = devm_kzalloc(dev, sizeof(*cif_dev), GFP_KERNEL);
//初始化 rkcif_device
dev_set_drvdata(dev, cif_dev);
cif_dev->dev = dev;
/*
参数1 struct rkcif_device
参数2 设备对应的设备树节点信息 rkcif_mipi_lvds
struct platform_device
struct device dev;
struct device_node *of_node;
*/
ret = rkcif_plat_init(cif_dev, node, data->inf_id);
if (ret) {
rkcif_detach_hw(cif_dev);
return ret;
}
return 0;
}
int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int inf_id)
{
struct device *dev = cif_dev->dev;
struct v4l2_device *v4l2_dev;
int ret;
...
/* 初始化 rkcif_device->v4l2_device
参数1
struct rkcif_device
struct device *dev;
参数2
struct rkcif_device
struct v4l2_device v4l2_dev;
动作1
工作
struct rkcif_device
struct device *dev;-------------+
struct v4l2_device v4l2_dev; |
struct device *dev;---------+
*/
ret = v4l2_device_register(cif_dev->dev, &cif_dev->v4l2_dev);
...
ret = rkcif_register_platform_subdevs(cif_dev);
return ret;
}
static int rkcif_register_platform_subdevs(struct rkcif_device *cif_dev)
{
int stream_num = 0, ret;
...
ret = cif_subdev_notifier(cif_dev);
...
return ret;
}
static int cif_subdev_notifier(struct rkcif_device *cif_dev)
{
struct v4l2_async_notifier *ntf = &cif_dev->notifier;
struct device *dev = cif_dev->dev;
int ret;
/*
动作2
结果:
struct rkcif_device
struct device *dev;
struct device_node *of_node; //A associated device tree node 如 节点 rkcif_mipi_lvds
struct device_node *child; //Aa 第一个子节点 如 节点 port
struct device_node *child; // Aa-1 第一个子节点 如 节点 cif_mipi_in: endpoint
struct fwnode_handle fwnode;
struct v4l2_async_notifier notifier;
const struct v4l2_async_notifier_operations *ops ;(init)
struct list_head waiting;//等待通知链表
struct v4l2_async_subdev **subdevs;//subdevs数组
|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组
|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式
|union match
struct fwnode_handle *fwnode;----------------------------->>>>>------------------------相连接的远程节点 mipi_csi2_output 的 父节点port的 fwnode
*/
ret = v4l2_async_notifier_parse_fwnode_endpoints(
dev, ntf, sizeof(struct rkcif_async_subdev), rkcif_fwnode_parse);
ntf->ops = &subdev_notifier_ops;
/*
参1
struct rkcif_device
struct v4l2_device v4l2_dev;
参2
struct rkcif_device
struct v4l2_async_notifier notifier;
*/
ret = v4l2_async_notifier_register(&cif_dev->v4l2_dev, ntf);
return ret;
}
W:\H3318C_ODM\H3318C\kernel\drivers\media\v4l2-core\v4l2-async.c
int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
struct v4l2_async_notifier *notifier)
{
int ret;
if (WARN_ON(!v4l2_dev || notifier->sd))
return -EINVAL;
//动作3
//注意这里!!
// 初始化了 通知器的根V4L2设备
/*
struct rkcif_device
struct v4l2_device v4l2_dev;//V4L2设备-------+
struct v4l2_async_notifier notifier; |
struct v4l2_device *v4l2_dev;-------------+
*/
notifier->v4l2_dev = v4l2_dev;
//参数:rkcif_device->v4l2_async_notifier
ret = __v4l2_async_notifier_register(notifier);
if (ret)
notifier->v4l2_dev = NULL;
return ret;
}
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;
/*
动作4
工作
struct rkcif_device
struct device *dev;
struct device_node *of_node; //A associated device tree node 如 节点 rkcif_mipi_lvds
struct device_node *child; //Aa 第一个子节点 如 节点 port
struct device_node *child; // Aa-1 第一个子节点 如 节点 cif_mipi_in: endpoint
struct fwnode_handle fwnode;
struct v4l2_async_notifier notifier;
const struct v4l2_async_notifier_operations *ops ;(init)
+---struct list_head waiting;//等待通知链表
| struct v4l2_async_subdev **subdevs;//subdevs数组 保存 对应的远端关联节点的父节点信息
+-------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组
|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式
|union match
struct fwnode_handle *fwnode;----------------------------->>>>>------------------------相连接的远程节点 mipi_csi2_output 的 父节点port的 fwnode
*/
for (i = 0; i < notifier->num_subdevs; i++) {
//获取 对应的远端关联节点的父节点信息
asd = notifier->subdevs[i];
//挂载 到等待队列
list_add_tail(&asd->list, ¬ifier->waiting);
}
ret = v4l2_async_notifier_try_all_subdevs(notifier);
if (ret < 0)
goto err_unbind;
/* 参数1 当前设备异步通知器
* 条件不满足,暂时不进入分析,不满足原因如下
* 1. notifier->parent == NULL
* 2. notifier->v4l2_dev == NULL
所以其他三个subdev设备 独自初始化时 不满足该函数运行条件
只有 rkcif_mipi 能执行该函数
*/
ret = v4l2_async_notifier_try_complete(notifier);
if (ret < 0)
goto err_unbind;
/*
* 以上2个函数可以看出来,v4l2_dev为空时都不会执行
* 将这个notifer挂载到链表notifier_list上
*/
/* Keep also completed notifiers on the list */
list_add(¬ifier->list, ¬ifier_list);
mutex_unlock(&list_lock);
return 0;
err_unbind:
/*
* On failure, unbind all sub-devices registered through this notifier.
*/
v4l2_async_notifier_unbind_all_subdevs(notifier);
err_unlock:
mutex_unlock(&list_lock);
return ret;
}
截止到目前所作的工作 :
struct rkcif_device
+---struct v4l2_device v4l2_dev;
| struct device *dev;------+
| |绑定
| struct device *dev; ---------+
| struct device_node *of_node; //A associated device tree node 如 节点 rkcif_mipi_lvds
| struct device_node *child; //Aa 第一个子节点 如 节点 port
| struct device_node *child; // Aa-1 第一个子节点 如 节点 cif_mipi_in: endpoint
| struct fwnode_handle fwnode;
|
| struct v4l2_async_notifier notifier;
绑定+-------struct v4l2_device v4l2_dev;//通知器的根V4L2设备
const struct v4l2_async_notifier_operations *ops ;(init)
+-------struct list_head waiting;//等待探索的子设备链表,记录设备树所描述的远程关联子设备,等待探索
挂载| struct v4l2_async_subdev **subdevs;//subdevs数组
+-----------|//subdevs[n] 将设备树所描述的远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组
|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式
|union match
struct fwnode_handle *fwnode;----------------------------关联->>>>>------------------------相连接的远程节点 mipi_csi2_output 的 父节点port的 fwnode
结合之前的分析 四个部分就有了这样的关系:
sensor
LIST_HEAD(notifier_list)----+ LIST_HEAD(subdev_list)----+
| |
| |
| 挂载 | 挂载
| |
struct techpoint | |
struct v4l2_async_notifier *subdev_notifier; -----------+ |
struct v4l2_subdev *sd; ---------+ |
| bind |
struct v4l2_subdev subdev;-----------+ ---------------------------------------------------------------+
const struct v4l2_subdev_ops *ops(init!!!)
struct v4l2_device *v4l2_dev; (NULL)
struct i2c_client *client;
struct device dev;
struct device_node *of_node; // A 如节点 tp2855_1@44
struct device_node *child; //Aa 如节点 ports
+-------struct fwnode_handle *fwnode;
| +---struct device_node *child; // Aa-1 如节点 ucam_out0
| |
| |
| |
| | mipi_csi_dphy
| |
| | LIST_HEAD(notifier_list)-----+ LIST_HEAD(subdev_list)------+
| | | |
| | |挂载 |挂载
| | struct mipidphy_priv | |
| | +-------struct v4l2_async_notifier notifier; --------------------+ |
| | | const struct v4l2_async_notifier_operations *ops; (init!!!) |
| | | +-------struct list_head waiting;//等待探索的子设备链表,记录设备树所描述的远程关联子设备,等待探索|
| | | | struct v4l2_async_subdev **subdevs;//数组 |
| | | +-----------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组 |
| | | |enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE |
| | | |union match |
+---|-------|--------------------struct fwnode_handle *fwnode; |
| | struct v4l2_subdev *sd ------------+ |
| | | |
| | struct v4l2_subdev sd;-----------------+ ------------------------------------------------------+
| | const struct v4l2_subdev_ops *ops
| | struct v4l2_device *v4l2_dev; (NULL)
| +------------struct v4l2_async_notifier *subdev_notifier;
|
| struct device *dev;
| struct device_node *of_node; //A associated device tree node 如 节点 csi_dphy0
| struct device_node *child; //Aa 第一个子节点 如 节点 ports
| struct device_node *child; // Aa-1 第一个子节点 如 节点 port@0
| struct device_node *child; //Aa-1-1 第一个子节点 如 节点 csi_dphy1_input: endpoint@1
|------------------------------------remote-endpoint = <&ucam_out0> 设备树属性
struct device_node *sibling; // Aa-2 第二个子节点 如 节点 port@1
+-----------------------------------struct fwnode_handle *fwnode;
| +---------------------------struct device_node *child; //Aa-2-1 第一个子节点 如 节点 csi_dphy1_output: endpoint@0
| | remote-endpoint = <&mipi_csi2_input> 设备树属性
| |
| |
| |
| |
| |
| | mipi_csi
| | LIST_HEAD(notifier_list)-----+ LIST_HEAD(subdev_list)----+
| | | |
| | | |
| | struct csi2_dev | |
| | struct device *dev;== platform_device *pdev->dev | |
| | +-----------struct v4l2_async_notifier notifier;-------------------------------------+ |
| | | const struct v4l2_async_notifier_operations *ops; (init !!!!) |
| | | +-------struct list_head waiting;//等待探索的子设备链表,记录设备树所描述的远程关联子设备,等待探索 |
| | | | struct v4l2_async_subdev **subdevs;//subdevs数组 |
| | | +-----------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组 |
| | | |enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式 |
| | | |union match |
+-------|---------------|-----------------------struct fwnode_handle *fwnode; |
| | struct v4l2_subdev *sd -----+ |
| | | |
| | | |
| | struct v4l2_subdev sd; --------+--------------------------------------------------------------------------+
| | const struct v4l2_subdev_ops *ops;
| | struct v4l2_device *v4l2_dev; (NULL)
| | struct device *dev;== platform_device *pdev->dev
| +---------------struct v4l2_async_notifier notifier;
|
| struct device *dev;
| struct device_node *of_node; //A associated device tree node 如 节点 mipi_csi2
| struct device_node *child; //Aa 第一个子节点 如 节点 ports
| struct device_node *child; // Aa-1 第一个子节点 如 节点 port@0
| struct device_node *child; //Aa-1-1 第一个子节点 如 节点 mipi_csi2_input: endpoint@1
+---------------------------------------------------remote-endpoint = <&csi_dphy0_output>; 设备树属性
struct device_node *sibling; // Aa-2 第二个子节点 如 节点 port@1
+-----------------------------------------------struct fwnode_handle *fwnode;
| struct device_node *child; //Aa-2-1 第一个子节点 如 节点 mipi_csi2_output: endpoint@0
| +-------------------------------------------remote-endpoint = <&csi_dphy0_output>;
| |
| |
| | rkcif_mipi
| | struct rkcif_device
| | +---struct v4l2_device v4l2_dev; //最重要的v4l2设备
| | | struct device *dev;------+
| | | |绑定
| | | struct device *dev; ---------+
| | | struct device_node *of_node; //A associated device tree node 如 节点 rkcif_mipi_lvds
| | | struct device_node *child; //Aa 第一个子节点 如 节点 port
| | | struct device_node *child; // Aa-1 第一个子节点 如 节点 cif_mipi_in: endpoint
| | | struct fwnode_handle fwnode;
| +-------------------------------------------remote-endpoint = <&mipi_csi2_output>; 设备树属性
| | struct v4l2_async_notifier notifier;
| 绑定+-------struct v4l2_device v4l2_dev;//通知器的根V4L2设备
| const struct v4l2_async_notifier_operations *ops ;(init)
| +-------struct list_head waiting;//等待探索的子设备链表,记录设备树所描述的远程关联子设备,等待探索
| 挂载| struct v4l2_async_subdev **subdevs;//subdevs数组
| +-----------|//subdevs[n] 将设备树所描述的远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组
| |enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式
| |union match
+---------------------------------------------struct fwnode_handle *fwnode;
总结前面的工作:
动作1 初始化 V4L2设备
动作2 将V4L2设备 作为通知器根V4L2设备
动作3 将设备树描述的远程子设备信息 添加到 子设备数组subdevs[] 以及 通知器等待探索的子设备链表 waiting
即将要做的:
动作4
前面已经通过设备树 拿到了关联子设备的信息,那么接下来 就要探索所关联的子设备是否存在,意思就是 探索一下自己关联的远程子设备是否已经 存在于 v4l2_subdev全局链表 subdev_list,是的话就说明子设备部分已经存在,那么就可以继续 处理两者之间的关系
首先 既然 关联子设备已经存在于 v4l2_subdev全局链表 subdev_list,那么就说明探索到了子设备部分,所以从 通知器等待探索的子设备链表 waiting 中删除 子设备。本来嘛,都已经找到了,就必要在这里排队了。并且也从v4l2_subdev全局链表 subdev_list 中删除子设备。已经找到了,不用挂在这里了。
然后建立 两者间的关系
注意执行第一轮 rkcif_device 部分的 v4l2_async_notifier_try_all_subdevs()时候,在最后面 初始化了 子设备通知器的父通知器,相当于打开了这里mipi csi的阀门同理后续都会初始化各自子设备通知器的父通知器的,分别从这里开始执行,重复动作4,建立各自的联系。
再由前面的关系图的相互绑定关系
最后得到这样的关系图:
static int v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
{
/*
这里是个阀门,只能从 rkcif_device 开始执行
在 rkcif_device 执行这里之前 2855,mipi csi phy, mipi csi 三个subdev 的通知器都没有初始化自己的 父通知器
更没有根V4L2设备,只有 rkcif_device 的通知器才有根V4L2设备
rkcif_device 从 v4l2_async_notifier_try_all_subdevs 执行一轮后,指定的了 子设备mipi csi 的通知器的父通知器,所以后续
*/
struct v4l2_device *v4l2_dev = v4l2_async_notifier_find_v4l2_dev(notifier);
struct v4l2_subdev *sd;
//如果 排除 2855,mipi csi phy, mipi csi
if (!v4l2_dev)
return 0;
again:
/* 遍历 v4l2_subdev全局链表 subdev_list,此时 subdev_list链表上有3个subdev,
* 分别是 2855的, mipi csi phy的及 mipi csi 的
*/
list_for_each_entry(sd, &subdev_list, async_list) {
struct v4l2_async_subdev *asd;
int ret;
/*
遍历全局链表 subdev_list ,搜索当前异步通知器是waiting链表中的子设备
|------------LIST_HEAD(subdev_list)----------------------|
| |
|--------------subdev-------subdev------subdev-----------|
struct rkcif_device
struct v4l2_async_notifier notifier;
+---struct list_head waiting;//等待通知链表
| struct v4l2_async_subdev **subdevs;//subdevs数组 保存 对应的远端关联节点的父节点信息
+-------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组
|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE 设备树fwnode匹配方式
|union match
struct fwnode_handle *fwnode;----------------------------->>>>>------------------------相连接的远程节点 mipi_csi2_output 的 父节点port的 fwnode
* 首先从 rkcif_device->v4l2_async_notifier->waiting 上取下每一个 asd (子设备描述v4l2_async_subdev 链表 waiting)
* 对于当前的rkcif_mipi来说其nontifier->waiting上的asd只有一个, 这个asd指向mipi csi dts的节点
* 于是 subdev_list上取出mipi csi 的subdev时
* 这个这个asd就和mipi csi 匹配上了
*/
asd = v4l2_async_find_match(notifier, sd);//获取 相关联的子设备的描述信息(mipi csi dts的节点信息)
if (!asd)
continue;
/*
参数1 rkcif_device->v4l2_async_notifier 当前设备通知管理器
参数2 rkcif_device->v4l2_dev 当前设备 V4L2驱动
参数3 相关联的子设备 mipi csi 的 v4l2_subdev 当前设备的子设备subdev
参数4 相关联的子设备 mipi csi 的dts节点 描述 当前设备的子设备描述
*/
ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
if (ret < 0)
return ret;
/*
* v4l2_async_match_notify() may lead to registering a
* new notifier and thus changing the async subdevs
* list. In order to proceed safely from here, restart
* parsing the list from the beginning.
*/
goto again;
}
return 0;
}
static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct v4l2_async_notifier *subdev_notifier;
int ret;
/*
目前已知的 工作 :
动作
struct rkcif_device
//V4L2 设备驱动
+---struct v4l2_device *v4l2_dev;
| //链表,用于跟踪已注册的子设备
| +---struct list_head subdevs;
| |
| |
| | struct csi2_dev
| | // V4L2子设备
| | struct v4l2_subdev sd;
| | //指向的所属的 V4L2 设备驱动
+---|-------------------struct v4l2_device *v4l2_dev;
| //挂载到 sub-devices子设备链表
+---------------------struct list_head list;
参数1 rkcif_device->v4l2_async_notifier->v4l2_dev
参数2 相关联的 mipi csi 的 v4l2_subdev
*/
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret < 0)
return ret;
/*
对于rkcif_mipi 只是把mipi csi的subdev放入cif_dev->sensors的数组中存储
参数1 rkcif_device->v4l2_async_notifier 当前设备通知管理器
参数2 相关联的子设备 mipi csi 的 v4l2_subdev 当前设备的子设备subdev
参数3 相关联的子设备 mipi csi 的dts节点 描述 当前设备的子设备描述
struct rkcif_device
//用于记录rkcif sensor 信息
struct rkcif_sensor_info sensors[RKCIF_MAX_SENSOR];
//V4L2子设备
struct v4l2_subdev *sd; -------------------+
|
struct csi2_dev |
// V4L2子设备 |
struct v4l2_subdev sd -------------------------+
*/
ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
if (ret < 0) {
v4l2_device_unregister_subdev(sd);
return ret;
}
/* Remove from the waiting list
将 当前设备的子设备描述 从当前设备的 异步通知 所管理的 子设备描述链表 waiting 上删除 (子设备描述v4l2_async_subdev 链表 waiting)
struct rkcif_device
struct v4l2_async_notifier notifier;
struct list_head waiting;//等待通知链表
从 waiting 中删除 子设备信息
*/
list_del(&asd->list);
sd->asd = asd;
/*
绑定 notifier,即使用同一个 V4L2 的通知器
struct rkcif_device
struct v4l2_async_notifier notifier ----------+
|
|
struct csi2_dev |
struct v4l2_subdev sd |
struct v4l2_async_notifier notifier ------+
*/
sd->notifier = notifier;
/* Move from the global subdevice list to notifier's done */
/*
之前sd通过自己的async_list挂载到全局subdev_list,现在将其从全局subdev_list移除,并且挂载到 notifier->done
注意notifier是管理者的notifier
对于 rkcif_mipi
就是 先从全局subdev_list链表中 删掉 mipi csi 子设备的 subdev。然后将他挂载到 自己的 rkcif_device->v4l2_async_notifier->done
struct rkcif_device
struct v4l2_async_notifier notifier
//已经完成探测的子设备链表
struct list_head done; -----------+
|
struct csi2_dev | 已经完成探测,加到完成链表
struct v4l2_subdev sd |
struct list_head async_list;------+
*/
list_move(&sd->async_list, ¬ifier->done);
/*
参数
struct csi2_dev
struct v4l2_subdev sd
得到
struct csi2_dev
struct v4l2_async_notifier notifier
遍历全局通知器链表notifier_list 找到 mipi csi 的通知器,这样就能找到下一级子设备
*/
subdev_notifier = v4l2_async_find_subdev_notifier(sd);
if (!subdev_notifier || subdev_notifier->parent)
return 0;
/*
* Proceed with checking for the sub-device notifier's async
* sub-devices, and return the result. The error will be handled by the
* caller.
*/
/*
struct rkcif_device
struct v4l2_async_notifier notifier ----------+
|
struct csi2_dev |
struct v4l2_async_notifier notifier |
struct v4l2_async_notifier *parent;-------+
*/
// 指定 mipi csi 的异步通知器 的父通知器 是 rkcif_mipi的异步通知器
subdev_notifier->parent = notifier;
/*
* 这是一个嵌套函数
* 脑补一下后面是怎么执行的
* 继续从subdev_list上找到mipi csi phy的subdev
* 将mipi csi phy 的subdev挂载到v4l2_dev->subdevs上
* 将mipi csi phy 的sd从subdev_list上移除挂载到mipi csi的notifier->done上
*
* 接着找到mipi csi phy的notifer
* 继续从subdev_list上找到2855的subdev
* 将2855 的subdev挂载到v4l2_dev->subdevs上
* 将2855 的sd从subdev_list上移除挂载到mipi csi phy的notifier->done上
*
* 接着找到2855的notifer
* 由于notifier->v4l2_device 上没有设备,所以就不会找的subdev
* 于是就退出嵌套
*/
/*
参数1 mipi csi 的异步通知器
*/
return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
}