基于RV1126 Video分析-----图像处理模块所代表的V4L2设备注册
工作:
以设备通知器为线索,从顶向下,依次找到下一级设备,添加到V4L2设备种,循环处理。将全部的子设备整理到 V4L2设备中,这样可以通过V4L2设备直接管理所包含的各个子设备。
即这样
所有设备注册是按照这个图来的。前面分析的是 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_lvdsstruct 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_devicedev_set_drvdata(dev, cif_dev);cif_dev->dev = dev;/*参数1 struct rkcif_device参数2 设备对应的设备树节点信息 rkcif_mipi_lvdsstruct platform_devicestruct 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_devicestruct device *dev;参数2 struct rkcif_devicestruct v4l2_device v4l2_dev;
动作1工作 struct rkcif_devicestruct 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_devicestruct 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: endpointstruct 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_devicestruct v4l2_device v4l2_dev;参2struct rkcif_devicestruct v4l2_async_notifier notifier;*/ret = v4l2_async_notifier_register(&cif_dev->v4l2_dev, ntf);return ret;
}kernel\drivers\media\v4l2-core\v4l2-async.cint 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_devicestruct v4l2_device v4l2_dev;//V4L2设备-------+struct v4l2_async_notifier notifier; | struct v4l2_device *v4l2_dev;-------------+*/notifier->v4l2_dev = v4l2_dev;//参数:rkcif_device->v4l2_async_notifierret = __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_devicestruct 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: endpointstruct 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);}/*这里是一个循环探索的过程,执行四轮第一轮:传入参数:struct rkcif_devicestruct v4l2_async_notifier notifierrkcif_device 设备1 遍历全局链表 subdev_list ,搜索到当前异步通知器是waiting链表中的子设备信息,即mipi csi设备。说明探索到已挂在的子设备2 将mipi csi设备 添加到 V4L2 子设备链表中 !!3 执行 rkcif_device设备的 notifier->ops->bound()函数4 绑定 mipi csi设备 通知器struct rkcif_device struct v4l2_async_notifier notifier ----------+|struct csi2_dev |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+第二轮:传入参数:struct csi2_dev struct v4l2_async_notifier notifiermipi cis 设备1 遍历全局链表 subdev_list ,搜索到当前异步通知器是waiting链表中的子设备信息,即 mipi csi dphy 设备。说明探索到已挂在的子设备2 将 mipi csi dphy 设备 添加到 V4L2 子设备链表中 !!3 执行 mipi cis 设备的 notifier->ops->bound()函数4 绑定 mipi csi dphy 设备 通知器struct rkcif_device struct v4l2_async_notifier notifier ----------+|struct csi2_dev |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+|struct mipidphy_priv |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+第三轮: 传入参数 struct mipidphy_priv struct v4l2_async_notifier notifiermipi csi dphy 设备1 遍历全局链表 subdev_list ,搜索到当前异步通知器是waiting链表中的子设备信息,即 sensor 设备。说明探索到已挂在的子设备2 将 sensor 设备 添加到 V4L2 子设备链表中 !!3 执行 mipi csi dphy 设备的 notifier->ops->bound()函数4 绑定 sensor 设备 通知器struct rkcif_device struct v4l2_async_notifier notifier ----------+|struct csi2_dev |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+|struct mipidphy_priv |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+|struct techpoint |struct v4l2_async_notifier notifier-----------+struct v4l2_async_notifier *parent;-------+第四轮:传入参数:struct techpointstruct v4l2_async_notifier notifiersensor 设备由于sensort 已经是最后一级模块,他没有子设备。直接返回 !!!*/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;
}
截止到v4l2_async_notifier_try_all_subdevs()之前 ,目前所作的工作 :
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
结合之前的分析 四个部分就有了这样的关系:
sensorLIST_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 的通知器 公用一个公共V4L2通知器。所以后续 mipi csi,mipi csi phy,2855 依次执行v4l2_async_notifier_try_all_subdevs()。共享公共的V4L2通知器。*/struct v4l2_device *v4l2_dev = v4l2_async_notifier_find_v4l2_dev(notifier);struct v4l2_subdev *sd;//如果 排除 2855,mipi csi phy, mipi csiif (!v4l2_dev)return 0;again:/* 遍历 v4l2_subdev全局链表 subdev_list,此时 subdev_list链表上有3个subdev,* 分别是 2855的, mipi csi phy的及 mipi csi 的这里会被2855终结跳出,因为他没有子设备。*/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_devicestruct 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_devicestruct v4l2_async_notifier notifier; struct list_head waiting;//等待通知链表从 waiting 中删除 子设备信息*/list_del(&asd->list);sd->asd = asd;/*绑定 notifier,即使用同一个 V4L2 的通知器struct rkcif_devicestruct 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->donestruct rkcif_devicestruct 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_devstruct v4l2_subdev sd 得到 struct csi2_devstruct 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_devicestruct 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);
}
基于RV1126 Video分析-----图像处理模块所代表的V4L2设备注册相关推荐
- 基于RV1126 Video分析-----sensor模块所代表的subdev子设备注册
工作: static LIST_HEAD(notifier_list); //异步通知链表 static LIST_HEAD(subdev_list);//v4l2_subdev 链表LIST_HEA ...
- 基于RV1126 Video分析-----驱动各模块总览
一 通用理论 硬件链接: 一般情况下,Camera和SOC有两个接口进行连接,分为为MIPI接口和I2C接口,其中MIPI接口用来传输图像的数据,数据传输路径为从Sensor传输到SOC.另一个接口为 ...
- 基于RV1126 Video分析-----mipi dphy模块所代表的subdev子设备注册
工作: LIST_HEAD(notifier_list)----+ LIST_HEAD(subdev_list)----+ | || || 挂载 | 挂载| | struct techpoint | ...
- 基于RV1126 Video分析-----mipi协议解析模块所代表的subdev子设备注册
工作: sensorLIST_HEAD(notifier_list)----+ LIST_HEAD(subdev_list)----+ | || || 挂载 | 挂载| | struct techpo ...
- 基于RV1126 Video分析-----sensor 的 media模块注册
工作 kernel\drivers\media\i2c\techpoint\techpoint_v4l2.c static int techpoint_probe(struct i2c_client ...
- 基于matlab 论文知网,基于MATLAB的校园图像处理与分析
内容介绍 原文档由会员 jiji888 发布 基于MATLAB的校园图像处理与分析 2.13万字 我自己原创的毕业设计,今年最新的,仅在本站独家提交,大家放心使用 摘要 随着计算机科学技术的不断发展以 ...
- PLUS模型有两大模块,一是基于土地扩张分析策略的规则挖掘框架,二是基于多类型随机补丁种子的CA模型,此外该模型还内嵌了Markov chain,以便于对土地利用数量需要作出预测。
工业革命以来,社会生产力迅速提高,人类活动频繁,此外人口与日俱增对土地的需求与改造更加强烈,人-地关系日益紧张.此外,土地资源的不合理开发利用更是造成了水土流失.植被退化.水资源短缺.区域气候变化.生 ...
- 基于Ti Omap3x 分析v4l2架构
1 概述 本文将基于Ti Omap3x这个典型的实例来分析v4l2在具体media场景中的应用.通过分析app层的行为以及driver层的实现来对整个多媒体框架有一个大概的认识.内容主要包括主要包括v ...
- 基于MATLAB的数字图像处理的设计与实现 转
基于MAT [摘要]数字图像处理是一门新兴技术,随着计算机硬件的发展,数字图像的实时处理已经成为可能,由于数字图像处理的各种算法的出现,使得其处理速度越来越快,能更好的为人们服务.数字图像处理是一种通 ...
最新文章
- 单点登录系统实现基于SpringBoot
- win10 编译姿态估计AlphaPose
- 主c++ 辅lua luabind protobuf
- SAP CRM Appointment应用里Date profile的配置
- 谁去过顽皮,谁去过尼斯? 圣诞老人为您提供Java 11建议!
- NYOJ2括号配对问题
- Flutter的滚动以及sliver约束
- 项目成功的关键是在投资最少的时候找出错误
- S5PV210 Uboot开发与移植02:Uboot配置与编译
- 压缩感知(Compressed sensing)from wiki
- 如何查看并杀死僵尸进程?
- 蓝牙打印 设置打印样式_双编辑模式 打印自由更轻松!——海鸟贴纸打印机蓝牙按键版体验...
- 双层优化模型【简述】
- Java、对字符串中的字符排序
- 知其然知其所以然 itoa实现 整型转字符串
- 台式计算机cpu品牌,台式电脑CPU天梯图2018年9月最新版 桌面CPU性能排名
- 教程二:windows api(c mfc vs2017)实现U盘插拔检测,获取U盘容量,U盘内容移动,开启和关闭U盘以及获取盘符等
- 每天叫醒的不是闹钟而是励志文章梦想
- hey 安装_如何使用“ Hey Siri”在Mac上启动Siri
- 论文投稿必看,审稿人意见互相矛盾,作者该怎么办?