论dts中的of_platform_populate如何选择性加载device node为platform device

论dts中的of_platform_populate如何选择性加载device node为platform device论dts中的of_platform_populate如何选择性加载devicenode为platformdevice2016-01-2114:26909人阅读评论(0)收藏举报本文章已收录于:分类:android源码(66)作者同类文章Xlinux(60)作者同类文章X

大家好,又见面了,我是你们的朋友全栈君。

1.  在比较新的linux内核中,设备树dts已经取代了传统的machine board device description,dts在内核中以各种device node的形式存在,而这些device node对于大部分的内核驱动模块platform_driver来说,最终需要有对应的platform device来与他匹配才可以完成一次device和driver的probe过程。

所有有必要将dts中需要加载为device的device node转为platform device,而这个过程是交给of_platform_populate来完成的(dts相关的device node tree是在start_kernel的setup_arch->unflatten_device_tree来加载dtb并解析)。

    of_platform_populate的入口一般是处于init_machine中,对于arm架构而言位于board.c中的DT_MACHINE_START()的init_machine中定义,而init_machine的调用是以一个module的形式而存在的,该module被加载后的目的,就是做device的create,在以前旧的board中,会将board.c中定义的相关device info转换为对应的device,以便后面的driver加载时可以match到相应的device。在基于dts的设备管理中,这个功能由of_platform_populate来实现

  1. static int __init customize_machine(void)  
  2. {  
  3.     /* customizes platform devices, or adds new ones */  
  4.     if (machine_desc->init_machine)  
  5.         machine_desc->init_machine();  
  6.     return 0;  
  7. }  
  8. arch_initcall(customize_machine);  
论dts中的of_platform_populate如何选择性加载device node为platform device

static int __init customize_machine(void)
{
	/* customizes platform devices, or adds new ones */
	if (machine_desc->init_machine)
		machine_desc->init_machine();
	return 0;
}
arch_initcall(customize_machine);

该module的initcall等级相比内核核心的core module来说是较低的,但一般比device module来的高,所以内核中是先存着device然后再当不同的driver被call加载后,完成一次驱动和设备的probe交互。在dts下这种过程典型的是platform device和driver的形式而存在。

2. of_platform_populate函数做了哪些事情

  1. int of_platform_populate(struct device_node *root,  
  2.             const struct of_device_id *matches,  
  3.             const struct of_dev_auxdata *lookup,  
  4.             struct device *parent)//NULL/NULL  
  5. {  
  6.     struct device_node *child;  
  7.     int rc = 0;  
  8.   
  9.     root = root ? of_node_get(root) : of_find_node_by_path(“/”);//根节点,可以从非根节点/开始加载  
  10.     if (!root)  
  11.         return -EINVAL;  
  12.   
  13.     for_each_child_of_node(root, child) {  
  14.         rc = of_platform_bus_create(child, matches, lookup, parent, true);  
  15.         if (rc)  
  16.             break;  
  17.     }  
  18.   
  19.     of_node_put(root);  
  20.     return rc;  
  21. }  
论dts中的of_platform_populate如何选择性加载device node为platform device

int of_platform_populate(struct device_node *root,
			const struct of_device_id *matches,
			const struct of_dev_auxdata *lookup,
			struct device *parent)//NULL/NULL
{
	struct device_node *child;
	int rc = 0;

	root = root ? of_node_get(root) : of_find_node_by_path("/");//根节点,可以从非根节点/开始加载
	if (!root)
		return -EINVAL;

	for_each_child_of_node(root, child) {
		rc = of_platform_bus_create(child, matches, lookup, parent, true);
		if (rc)
			break;
	}

	of_node_put(root);
	return rc;
}

该该函数的功能主要可以总结如下:

a.根据所选择的device node根节点,来递归式的遍历从root node开始以下的所有device node

b.将device node转变为一个platform_device并将其作为device 通过device_add到内核

c.可以判断哪些device node是需要转为device到内核的。

d. 如果传入的root=NULL,则表明从dts的\节点开始逐一的递归处理,否则根据所选择的device node作为root,做递归处理。

e. struct of_device_id *matches,该match table重点是后续节点递归处理时,需要和该table mach后才可以继续递归处理。

需要说明的是dts中定义的各种device node,往往只是用来辅助核心的device node而存在的,也就是说这些node存在并不需要加载为platform device,那么哪些device node是不会在of_platform_populate中被解析为device的呢,具体可以从以下几个方面展开:

  1. static int of_platform_bus_cof_platform_populatereate(struct device_node *bus,  
  2.                   const struct of_device_id *matches,  
  3.                   const struct of_dev_auxdata *lookup,  
  4.                   struct device *parent, bool strict)  
  5. {  
  6.     const struct of_dev_auxdata *auxdata;  
  7.     struct device_node *child;  
  8.     struct platform_device *dev;  
  9.     const char *bus_id = NULL;  
  10.     void *platform_data = NULL;  
  11.     int rc = 0;  
  12.   
  13.     /* Make sure it has a compatible property */  
  14.     if (strict && (!of_get_property(bus, “compatible”, NULL))) {  
  15.         pr_debug(“%s() – skipping %s, no compatible prop\n”,  
  16.              __func__, bus->full_name);  
  17.         return 0;  
  18.     }  
  19.   
  20.     auxdata = of_dev_lookup(lookup, bus);//初始设备树解析时lookup为Null  
  21.     if (auxdata) {  
  22.         bus_id = auxdata>name;  
  23.         platform_data = auxdata>platform_data;  
  24.     }  
  25.   
  26.     if (of_device_is_compatible(bus, “arm,primecell”)) {  
  27.         of_amba_device_create(bus, bus_id, platform_data, parent);  
  28.         return 0;  
  29.     }  
  30.   
  31.     dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);//创建platform device  
  32.     if (!dev || !of_match_node(matches, bus))//看该bus即父节点是否属于要继续加载子节点  
  33.         return 0;//matches需要用户的驱动支持of_platform_populate  
  34.   
  35.     for_each_child_of_node(bus, child) {//子设备的解析处理  
  36.         pr_debug(”   create child: %s\n”, child->full_name);  
  37.         rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);//父节点下的子设备节点创建  
  38.         if (rc) {  
  39.             of_node_put(child);  
  40.             break;  
  41.         }  
  42.     }  
  43.     return rc;  
  44. }  
论dts中的of_platform_populate如何选择性加载device node为platform device

static int of_platform_bus_cof_platform_populatereate(struct device_node *bus,
				  const struct of_device_id *matches,
				  const struct of_dev_auxdata *lookup,
				  struct device *parent, bool strict)
{
	const struct of_dev_auxdata *auxdata;
	struct device_node *child;
	struct platform_device *dev;
	const char *bus_id = NULL;
	void *platform_data = NULL;
	int rc = 0;

	/* Make sure it has a compatible property */
	if (strict && (!of_get_property(bus, "compatible", NULL))) {
		pr_debug("%s() - skipping %s, no compatible prop\n",
			 __func__, bus->full_name);
		return 0;
	}

	auxdata = of_dev_lookup(lookup, bus);//初始设备树解析时lookup为Null
	if (auxdata) {
		bus_id = auxdata->name;
		platform_data = auxdata->platform_data;
	}

	if (of_device_is_compatible(bus, "arm,primecell")) {
		of_amba_device_create(bus, bus_id, platform_data, parent);
		return 0;
	}

	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);//创建platform device
	if (!dev || !of_match_node(matches, bus))//看该bus即父节点是否属于要继续加载子节点
		return 0;//matches需要用户的驱动支持of_platform_populate

	for_each_child_of_node(bus, child) {//子设备的解析处理
		pr_debug("   create child: %s\n", child->full_name);
		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);//父节点下的子设备节点创建
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	return rc;
}

可以看到是有一个类似bus的root device node下来逐步展开的,而这个root node可以不是函数重点关注的是:

a. of_get_property(“compatible”),如果这个节点root device属性不存在,则表明其不需要生成为platform device

b. 随着root device node由函数of_platform_device_create_pdata创建为platform device后,需要检查当前节点的compatible是否和match table中定义的table list相互匹配:

  1. const struct of_device_id *of_match_node(const struct of_device_id *matches,  
  2.                      const struct device_node *node)  
  3. {  
  4.     if (!matches)  
  5.         return NULL;  
  6.   
  7.     while (matches->name[0] || matches->type[0] || matches->compatible[0]) {  
  8.         int match = 1;  
  9.         if (matches->name[0])  
  10.             match &= node->name  
  11.                 && !strcmp(matches->name, node->name);  
  12.         if (matches->type[0])  
  13.             match &= node->type  
  14.                 && !strcmp(matches->type, node->type);  
  15.         if (matches->compatible[0])  
  16.             match &= of_device_is_compatible(node,  
  17.                         matches->compatible);  
  18.         if (match)  
  19.             return matches;  
  20.         matches++;  
  21.     }  
  22.     return NULL;  
  23. }  
论dts中的of_platform_populate如何选择性加载device node为platform device

const struct of_device_id *of_match_node(const struct of_device_id *matches,
					 const struct device_node *node)
{
	if (!matches)
		return NULL;

	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
		int match = 1;
		if (matches->name[0])
			match &= node->name
				&& !strcmp(matches->name, node->name);
		if (matches->type[0])
			match &= node->type
				&& !strcmp(matches->type, node->type);
		if (matches->compatible[0])
			match &= of_device_is_compatible(node,
						matches->compatible);
		if (match)
			return matches;
		matches++;
	}
	return NULL;
}

如果当该device node在被创建为platform device后,就不在和match table相匹配时,其对应的child node就不会再被创建platform device,即无论child node是否定义了”compatible”,其对应的platform device均不会被生成。

c.对于dts中定义的device node,只有其所属的parent node所属的compatible属性和调用of_platform_populate时传入的of_device_id相互匹配,则说明如果当前的device node只要包含有compatible属性就会被创建为platform device。

以一个简单的dts为例:

  1. /{  
  2.   soc0{  
  3.   compatible = “my, soc0”;  
  4.   node1{  
  5.   compatible = “my, node1”;                      
  6.   node1_1{  
  7.   compatible = “my, node1_1”;  
  8.   node1_1_1{  
  9.   compatible = “my, node1_1_1”;  
  10. }  
  11. }  
  12. }  
  13.   node2{ }  
  14. }  
  15.   soc1{ compatible = “my, soc1”; }  
  16. }  
论dts中的of_platform_populate如何选择性加载device node为platform device

/{
  soc0{
  compatible = "my, soc0";
  node1{
  compatible = "my, node1";                    
  node1_1{
  compatible = "my, node1_1";
  node1_1_1{
  compatible = "my, node1_1_1";
}
}
}
  node2{ }
}
  soc1{ compatible = "my, soc1"; }
}

a.假设现在在init_machine中调用of_platform_populate()时传入的root node为NULL,且mach id为”my, soc0″,”my,node1″

则最终soc0会被首先作为/ root node的child node被加载为platform device,然后依次是node1,由于其相应的compatible和match id匹配,则其对应的child node允许被继续调用of_platform_bus_create,并且对含有compatible的device node生成为platform device,如本例中的node1。同理对于node1而言会加载node1_1节点,但当node1_1生成为device后,由于无法匹配match id,则其无法再递归的处理其下的子节点,从而使得node1_1_1不会被生成为platform device。而这需要说明的是,这个device虽然不会被自动加载为platform device但在node1_1的device driver实现时,可以将node1_1_1形成一种特定的device,如i2c_client等,只是不会生成platform device。从而解释了为何该device node只是以一个device 的形式存在于内核而不是即是i2c_client和platform device。

而soc0下的node2由于不存在compatible属性,同样不会被生成device,以及其child node下的各级device node也都不会被加载。

b,假设传入的root node为soc1,且mach id为”my,node1″时

这个过程会加载node1,然后是node1_1,同样的node1_1_1不会被生成为platform_device.

3.总结

对于of_platform_populate如何选择性的加载device node为platform device在系统启动阶段,可以只关注该device node所属的parent node的compatible属于match id。

一旦自身包含compatible,则会自动调用of_platform_device_create_pdata生成一个platform device。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163803.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 目标检测(Object Detection)

    目标检测(Object Detection)文章目录目标检测(ObjectDetection)一、基本概念1.什么是目标检测2.目标检测的核心问题3.目标检测算法分类1)TowStage2)OneStage4.目标检测应用1)人脸检测2)行人检测3)车辆检测4)遥感检测二、目标检测原理1.候选区域产生1)滑动窗口2)选择性搜索①什么是选择性搜索②选择搜索流程③选择搜索优点2.数据表示3.效果评估4.非极大值抑制三、目标检测模型1.R-CNN系列1)R-CNN①定义②流程③效果④缺点2)FastR-CNN①定义

  • 在java中println什么意思_java printf与println

    在java中println什么意思_java printf与println在java中,System.out.println()是我们经常会用到的一个语法,它的作用是将值输出显示在console窗口中,这样程序员就可以在console窗口中看到代码运行的结果。而除了System.out.println()之外,还有其他的打印结果的方法。比如说System.out.print(),这个方法与System.out.println()很像,区别就在于,System.out….

  • 2、工厂方法模式

    2、工厂方法模式

  • jsonobject返回map_jsonobject转map对象

    jsonobject返回map_jsonobject转map对象原标题:jsonobject转map对象我们在开发嵌套数据的时候,有时会返回jsonobject数据,这是因为进行的是url访问,但是这个过程可能会出现异常,因此我们需要将jsonobject转map对象使用。本文将向大家介绍jsonobject转map对象的实现方法。1、依赖于jar包,使用json-lib包进行转换。相关jar包jakartacommons-lang2.5jakarta…

  • 怎么将sql文件导入数据库_mysql导入sql文件命令

    怎么将sql文件导入数据库_mysql导入sql文件命令打开命令提示符行输入以下命令进入本地数据库2.创建数据库新建一个新数据库用来导入.sql数据3.导入.sql文件在导入.sql文件之前,设置一下编码模式,防止出现中文乱码的情况(第一次导入就出现了中文乱码,所以中添加一步防止出现乱码情况)。以上就是将.sql文件导入数据库的全部操作,这是打开新建的数据库就能看到导入进去的表内容。…

  • 神经网络轴承故障诊断_一维卷积神经网络详解

    神经网络轴承故障诊断_一维卷积神经网络详解基于一维卷积神经网络的滚动轴承故障识别提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录基于一维卷积神经网络的滚动轴承故障识别一、数据预处理二、模型搭建三、使用步骤1.引入库2.读入数据总结一、数据预处理采用美国凯斯西储大学(CWRU)的开放轴承数据库的样本进行实验分析,轴承故障产生的实验台如下图所示。使用电火花加工技术分别在轴承的内圈、外圈和滚动体上引入单点缺陷,故障尺寸分别为7、14和21in,以48kHz采样频率采集不同负载下的故障轴承振动数据用于实验分析。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号