Linux v4l2架构学习总链接

int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,struct v4l2_async_notifier *notifier)
{int ret;/** 有条件限制* 1. subdev不能为空* 2. v4l2_dev值为NULL* 任意一个满足都不可以* 这里的v4l2_dev,只有注册video节点的时候才会被赋值*/if (WARN_ON(!sd || notifier->v4l2_dev))return -EINVAL;notifier->sd = sd;ret = __v4l2_async_notifier_register(notifier);if (ret)notifier->sd = 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;if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)return -EINVAL;INIT_LIST_HEAD(&notifier->waiting);INIT_LIST_HEAD(&notifier->done);mutex_lock(&list_lock);/** 对于notifier->subdevs中有数据的情况*/for (i = 0; i < notifier->num_subdevs; i++) {asd = notifier->subdevs[i];switch (asd->match_type) {case V4L2_ASYNC_MATCH_CUSTOM:case V4L2_ASYNC_MATCH_DEVNAME:case V4L2_ASYNC_MATCH_I2C:break;/** 重点分析 V4L2_ASYNC_MATCH_FWNODE*/case V4L2_ASYNC_MATCH_FWNODE:if (v4l2_async_notifier_fwnode_has_async_subdev(notifier, asd->match.fwnode, i)) {dev_err(dev,"fwnode has already been registered or in notifier's subdev list\n");ret = -EEXIST;goto err_unlock;}break;default:dev_err(dev, "Invalid match type %u on %p\n",asd->match_type, asd);ret = -EINVAL;goto err_unlock;}/** asd挂载到notifier->waiting上* 这里的notifier是mipi csi phy的,不是imx291的* asd对应的是imx291的dts节点*/list_add_tail(&asd->list, &notifier->waiting);}/** 这里暂时认为v4l2_dev = NULL* 所以不执行*/ret = v4l2_async_notifier_try_all_subdevs(notifier);if (ret < 0)goto err_unbind;/** 这里暂时认为notifier->waiting不为空* 所以不执行*/ret = v4l2_async_notifier_try_complete(notifier);if (ret < 0)goto err_unbind;/* Keep also completed notifiers on the list */list_add(&notifier->list, &notifier_list);mutex_unlock(&list_lock);return 0;
}

v4l2_async_subdev_notifier_register

-> __v4l2_async_notifier_register

-> v4l2_async_notifier_fwnode_has_async_subdev


这里代入情景分析

请看下面的2篇文章,都是注册的subdev,这里不考虑注册video,不考虑不考虑不考虑。。。

2.2 -- 基于RV1126平台imx291分析 --- imx291注册

2.3 -- 基于RV1126平台imx291分析 --- mipi-csi-phy注册

注册了imx291,现在在注册mipi-csi-phy,调用到了这个函数

现在的情况是

notifier->num_subdevs = 1

asd->match.fwnode 指向imx291 dts的节点

notifier_list链表上只有imx291的notifier

static bool v4l2_async_notifier_fwnode_has_async_subdev(struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,unsigned int this_index)
{unsigned int j;lockdep_assert_held(&list_lock);/** 这里的for循环只是为了检测subdevs是不是重复*//* Check that an fwnode is not being added more than once. */for (j = 0; j < this_index; j++) {struct v4l2_async_subdev *asd = notifier->subdevs[this_index];struct v4l2_async_subdev *other_asd = notifier->subdevs[j];if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&asd->match.fwnode ==other_asd->match.fwnode)return true;}/** 根据情景代入可以知道* notifier_list上只有一个imx291的notifier*//* Check than an fwnode did not exist in other notifiers. */list_for_each_entry(notifier, &notifier_list, list)if (__v4l2_async_notifier_fwnode_has_async_subdev(notifier, fwnode))return true;return false;
}static bool __v4l2_async_notifier_fwnode_has_async_subdev(struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
{struct v4l2_async_subdev *asd;struct v4l2_subdev *sd;/** 判断notifier->waiting链表上的asd 和当前的fwnode值是否相等* 正常来说这里不会出现,除非注册了2次*/list_for_each_entry(asd, &notifier->waiting, list) {if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)continue;if (asd->match.fwnode == fwnode)return true;}/** 判断notifier->done链表上的subdev和当前的fwnode值是否相等*/list_for_each_entry(sd, &notifier->done, async_list) {if (WARN_ON(!sd->asd))continue;if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)continue;if (sd->asd->match.fwnode == fwnode)return true;}return false;
}

v4l2_async_subdev_notifier_register

-> __v4l2_async_notifier_register

-> v4l2_async_notifier_fwnode_has_async_subdev

-> v4l2_async_notifier_try_all_subdevs


注意看到下面的文章后再开始看下面的分析

2.6 -- 基于RV1126平台imx291分析 -- rkcif_mipi注册

目前为止

notifier_list链表上有3个notifier,分别是imx291的, mipi csi phy的及 mipi csi 的

subdev_list链表上有3个subdev,分别是imx291的, mipi csi phy的及 mipi csi 的

mipi csi phy的notifier->waitng上有个asd,asd指向imx291 dts的节点

mipi csi 的notifier->waiting上有个asd,asd指向mipi csi phy dts的节点

rkcif_mipi 的notifier->waiting上有个asd,asd指向mipi csi dts的节点

当前的notifier是rkcif_mipi的,其v4l2_dev不为空

static int v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
{struct v4l2_device *v4l2_dev =v4l2_async_notifier_find_v4l2_dev(notifier);struct v4l2_subdev *sd;if (!v4l2_dev)return 0;again:/** subdev_list链表上有3个subdev,* 分别是imx291的, mipi csi phy的及 mipi csi 的*/list_for_each_entry(sd, &subdev_list, async_list) {struct v4l2_async_subdev *asd;int ret;/** v4l2_async_find_match这个比较简单* 首先从notifier->waiting上取下每一个asd* 对于当前的rkcif_mipi来说其nontifier->waiting上的asd只有一个* 这个asd指向mipi csi dts的节点* 于是 subdev_list上取出mipi csi 的subdev时* 这个这个asd就和mipi csi 匹配上了*/asd = v4l2_async_find_match(notifier, sd);if (!asd)continue;/** sd为mipi csi 的subdev* asd指向mipi csi dts的节点* notifier是rkcif_mipi的*/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;
}

v4l2_async_subdev_notifier_register

-> __v4l2_async_notifier_register

-> v4l2_async_notifier_fwnode_has_async_subdev

-> v4l2_async_notifier_try_all_subdevs

-> v4l2_async_match_notify


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;/** 这里主要做2件事情* 1. 调用sd->internal_ops->registered(sd) 有的话* 2. sd从nitifier->waiting上移除挂载到v4l2_dev->subdevs上面*    这个很重要,这是保证subdev能被注册的关键*/ret = v4l2_device_register_subdev(v4l2_dev, sd);if (ret < 0)return ret;/** 调用notifier->ops->bound*/ret = v4l2_async_notifier_call_bound(notifier, sd, asd);if (ret < 0) {v4l2_device_unregister_subdev(sd);return ret;}/* Remove from the waiting list */list_del(&asd->list);sd->asd = asd;/** 对于subdev之前注册的时候* 其subdev的notifier都是保存在* sd->subdev_notifier中* 现在这个notifier用于保存管理者的notifier,* 管理者就是上一级的notifier*/sd->notifier = notifier;/** 之前sd通过async_list挂载到subdev_list* 现在将其从subdev_list移除* 挂载到notifier->done* 主意notifier是管理者的notifier*//* Move from the global subdevice list to notifier's done */list_move(&sd->async_list, &notifier->done);/** See if the sub-device has a notifier. If not, return here.*//** 这句很关键* 之前忽略了这句导致一直没有理解其他的subdev是怎么注册的* 这里补贴代码,只说一下原理* 根据上面的分析,知道sd是mipi csi dts的节点* 于是就遍历notifier_list找到一个notifier* 满足notifier->sd == sd* 哪个notifier满足?* 肯定是mipi csi 的notifier满足* 这样就找到了下一级的notifier*/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.*//** 建立一个父子关系*/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上找到imx291的subdev* 将imx291 的subdev挂载到v4l2_dev->subdevs上* 将imx291 的sd从subdev_list上移除挂载到mipi csi phy的notifier->done上* * 接着找到imx291的notifer* 由于notifier->waiting上没有设备,所以就不会找的subdev* 于是就退出嵌套*/return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
}

v4l2_async_subdev_notifier_register

-> __v4l2_async_notifier_register

-> v4l2_async_notifier_fwnode_has_async_subdev

-> v4l2_async_notifier_try_all_subdevs

-> v4l2_async_notifier_try_complete


static int v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
{/* Quick check whether there are still more sub-devices here. *//** sd从notifier->waiting上移除* 是在v4l2_device_register_subdev中执行的*/if (!list_empty(&notifier->waiting))return 0;/* Check the entire notifier tree; find the root notifier first. *//** 找到最高级管理者的notifier* 也就是v4l2_dev的notifier* 对于我们分析的情景来说* imx291 的 notifier parent是 mipi csi phy的notifier* mipi csi phy 的 notifier parent是 mipi csi的notifier* mipi csi 的 notifier parent是 rkcif_mipi的notifier* rkcif_mipi 的 notifier parent为空*/while (notifier->parent)notifier = notifier->parent;/* This is root if it has v4l2_dev. */if (!notifier->v4l2_dev)return 0;/* Is everything ready? *//** 看下面分析*/if (!v4l2_async_notifier_can_complete(notifier))return 0;/** 当所有的notifier->waiting都为空的时候,说明准备好了* 可以开始注册了*//** 这里会调用管理者的notifier的* ops->complete* 这里会把所有的subdev都注册*/return v4l2_async_notifier_call_complete(notifier);
}

v4l2_async_subdev_notifier_register

-> __v4l2_async_notifier_register

-> v4l2_async_notifier_fwnode_has_async_subdev

-> v4l2_async_notifier_try_all_subdevs

-> v4l2_async_notifier_try_complete

-> v4l2_async_notifier_can_complete


static bool v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
{struct v4l2_subdev *sd;if (!list_empty(&notifier->waiting))return false;/** 从管理者的notifier->done上找到下一级的sd* 根据下一级的sd找从notifier_list上找到其对应的notifier* 然后再找下一级...* 通过确认所有的notifier->waiting为空* 说明sb都挂载到了v4l2_dev->subdevs上了* 就知道可以注册subdev了* 退出的条件是* 找到最后一个notifer,由于已经是最低级的notifier* 所以最后一个notifier->done上是空的*/list_for_each_entry(sd, &notifier->done, async_list) {struct v4l2_async_notifier *subdev_notifier =v4l2_async_find_subdev_notifier(sd);if (subdev_notifier &&!v4l2_async_notifier_can_complete(subdev_notifier))return false;}return true;
}

v4l2_async_subdev_notifier_register 分析相关推荐

  1. Linux v4l2架构学习

    写在开始之前. 网上有很多文章讲v4l2架构,讲的都很好,但是很多都是讲讲主要的结构体已经注册接口这些,个人觉得入门还是要深入的去看代码,至少把整个流程粗略的看一遍,才能真正的了解架构是什么样的,调用 ...

  2. 基于RV1126 Video分析-----mipi dphy模块所代表的subdev子设备注册

    工作: LIST_HEAD(notifier_list)----+ LIST_HEAD(subdev_list)----+ | || || 挂载 | 挂载| | struct techpoint | ...

  3. 基于RV1126 Video分析-----sensor模块所代表的subdev子设备注册

    工作: static LIST_HEAD(notifier_list); //异步通知链表 static LIST_HEAD(subdev_list);//v4l2_subdev 链表LIST_HEA ...

  4. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  5. 2022-2028年中国自动驾驶系统行业现状调研分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国自动驾驶系统行业市场行业相关概述.中国自 ...

  6. 2022-2028年中国阻尼涂料市场研究及前瞻分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国阻尼涂料行业市场行业相关概述.中国阻尼涂 ...

  7. 2021-2028年中国阻燃装饰行业市场需求与投资规划分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国阻燃装饰行业市场行业相关概述.中国阻燃装 ...

  8. 2022-2028年全球与中国漂白吸水棉市场研究及前瞻分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了全球与中国漂白吸水棉行业市场行业相关概述.全 ...

  9. 2022-2028年全球与中国青苔清洗剂市场研究及前瞻分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了全球与中国青苔清洗剂行业市场行业相关概述.全 ...

最新文章

  1. Ansible02-实施playbook
  2. [PHP] 遗传算法求函数最大值一般实现
  3. web ch6 表单基础(部分选学)
  4. c++电费管理系统_能耗管理系统
  5. Python爬虫教程:requests模拟登陆github
  6. statspack报告
  7. 归并算法(分割与合并)
  8. SQLite语法与Android数据库操作
  9. 前端纯css 图片的模糊处理
  10. OpenCore引导配置说明第十二版-基于OpenCore-0.6.5正式版
  11. H5 的直播协议和视频监控方案
  12. CF-GYM 103119 L. Random Permutation
  13. 74HC165基础篇(一)
  14. R语言实战应用精讲50篇(十二)-正态分布与方差齐性的检验方法与SPSS操作
  15. 无情的事实--人类曾经被彻底毁灭过
  16. JEDEC发布用于高性能计算应用的DDR5 SDRAM标准更新
  17. esp8266 AP模式控制继电器开关
  18. NISP一级学习笔记(1~9章知识点集合大全)
  19. C++难学吗?为什么难学?如何去学?
  20. 2022中国中医药产业展,山东医药保健展,济南药交会9月举办

热门文章

  1. 【2015NOIP模拟】【Ocd】【Mancity】【Captcha】10.31总结
  2. 网络正常,浏览器显示代理服务器没有响应怎么办?
  3. python编程学习笔记(三)
  4. 电子凸轮追剪曲线生成算法 理解后可转成其他品牌PLC或任何一种编程语言
  5. 使用maya.cmds加载和卸载插件
  6. SEO搜索引擎优化步骤建议
  7. 自定义Xshell颜色主题Color Schemes
  8. html标签的message,Message 消息提示
  9. 用css伪元素制作箭头图标
  10. 打印日志文件并将其上传存到HDFS中