Device Tree (四) - device_node -> platform_device

一,调用到of_platform_populate的流程

kernel V5.10:
start_kernel(void)
----setup_arch(&command_line);
--------setup_machine_fdt(__fdt_pointer); /* D:\work\source_code\msm-kernel\msm_kernel\arch\arm64\kernel\setup.c */
--------unflatten_device_tree(); /* D:\work\source_code\msm-kernel\msm_kernel\drivers\of\fdt.c */
----arch_call_rest_init();
--------rest_init();
------------kernel_thread(kernel_init, NULL, CLONE_FS);
----------------kernel_init_freeable();
--------------------do_basic_setup();
------------------------driver_init();
----------------------------firmware_init(); /* D:\work\source_code\msm-kernel\msm_kernel\drivers\base\firmware.c */
--------------------------------firmware_kobj = kobject_create_and_add("firmware", NULL);
----------------------------of_core_init();
--------------------------------of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
--------------------------------__of_attach_node_sysfs(np);
--------------------------------proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
----------------------------platform_bus_init();
------------------------do_initcalls();
--------------------------------do_initcall_level(level, command_line);
--------------------------------arch_initcall_sync(of_platform_default_populate_init);
------------------------------------of_platform_populate(root, of_default_bus_match_table, lookup, parent); /* D:\work\source_code\msm-kernel\msm_kernel\drivers\of\platform.c */

二,Device_Tree与sysfs

在of_core_init()函数中在/sys/firmware/devicetree/base目录下面为设备树展开成sysfs的目录和二进制属性文件,所有的node节点就是一个目录,所有的property属性就是一个二进制属性文件。

1, 创建/sys/firmware 目录

int __init firmware_init(void)
{firmware_kobj = kobject_create_and_add("firmware", NULL);if (!firmware_kobj)return -ENOMEM;return 0;
}

2, of_core_init

void __init of_core_init(void)
{struct device_node *np;/* Create the kset, and register existing nodes */mutex_lock(&of_mutex);//创建/sys/firmware/devicetree目录of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);if (!of_kset) {mutex_unlock(&of_mutex);pr_err("failed to register existing nodes\n");return;}for_each_of_allnodes(np) {//为设备树展开成sysfs的目录和二进制属性文件__of_attach_node_sysfs(np);if (np->phandle && !phandle_cache[of_phandle_cache_hash(np->phandle)])phandle_cache[of_phandle_cache_hash(np->phandle)] = np;}mutex_unlock(&of_mutex);/* Symlink in /proc as required by userspace ABI */if (of_root)//创建软链接 /proc/device-tree -> /sys/firmware/devicetree/baseproc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
}

3, __of_attach_node_sysfs

int __of_attach_node_sysfs(struct device_node *np)
{const char *name;struct kobject *parent;struct property *pp;int rc;if (!IS_ENABLED(CONFIG_SYSFS) || !of_kset)return 0;// kobj.ksetnp->kobj.kset = of_kset;if (!np->parent) {/* Nodes without parents are new top level trees *///如果device_node的parent为空,这个device_node作为根节点,根的名字为basename = safe_name(&of_kset->kobj, "base");parent = NULL;} else {//非根节点的名字name = safe_name(&np->parent->kobj, kbasename(np->full_name));parent = &np->parent->kobj;}if (!name)return -ENOMEM;//在父亲节点的目录下,为node创建目录rc = kobject_add(&np->kobj, parent, "%s", name);kfree(name);if (rc)return rc;//为property创建二进制属性文件for_each_property_of_node(np, pp)__of_add_property_sysfs(np, pp);of_node_get(np);return 0;
}

4,__of_add_property_sysfs

int __of_add_property_sysfs(struct device_node *np, struct property *pp)
{int rc;/* Important: Don't leak passwords */bool secure = strncmp(pp->name, "security-", 9) == 0;if (!IS_ENABLED(CONFIG_SYSFS))return 0;//判断node已经被绑定 node->kobj.state_in_sysfsif (!of_kset || !of_node_is_attached(np))return 0;sysfs_bin_attr_init(&pp->attr);pp->attr.attr.name = safe_name(&np->kobj, pp->name);pp->attr.attr.mode = secure ? 0400 : 0444;pp->attr.size = secure ? 0 : pp->length;pp->attr.read = of_node_property_read;//在所属节点的目录中,为property创建二进制属性文件rc = sysfs_create_bin_file(&np->kobj, &pp->attr);WARN(rc, "error adding attribute %s to node %pOF\n", pp->name, np);return rc;
}

三,of_platform_populate执行流程

1, 整体流程

D:\work\source_code\msm-kernel\msm_kernel\drivers\of\platform.cof_platform_default_populate_init()|of_platform_default_populate();|of_platform_populate();|of_platform_bus_create()_____________________|_________________|                                      |of_platform_device_create_pdata()       of_platform_bus_create()_________________|____________________|                                      |
of_device_alloc()                        of_device_add()       

2, 关键代码分析

2.1,of_platform_default_populate
int of_platform_default_populate(struct device_node *root,const struct of_dev_auxdata *lookup,struct device *parent)
{return of_platform_populate(root, of_default_bus_match_table, lookup,parent);
}
EXPORT_SYMBOL_GPL(of_platform_default_populate);
2.2, of_platform_populate
/**
* of_platform_populate() - Populate platform_devices from device tree data
* @root: parent of the first level to probe or NULL for the root of the tree
* @matches: match table, NULL to use the default
* @lookup: auxdata table for matching id and platform_data with device nodes
* @parent: parent to hook devices from, NULL for toplevel
*
* Similar to of_platform_bus_probe(), this function walks the device tree
* and creates devices from nodes.  It differs in that it follows the modern
* convention of requiring all device nodes to have a 'compatible' property,
* and it is suitable for creating devices which are children of the root
* node (of_platform_bus_probe will only create children of the root which
* are selected by the @matches argument).
*
* New board support should be using this function instead of
* of_platform_bus_probe().
*
* Returns 0 on success, < 0 on failure.
*/
int of_platform_populate(struct device_node *root,const struct of_device_id *matches,const struct of_dev_auxdata *lookup,struct device *parent)
{struct device_node *child;int rc = 0;//获取根节点root = root ? of_node_get(root) : of_find_node_by_path("/");if (!root)return -EINVAL;pr_debug("%s()\n", __func__);pr_debug(" starting at: %pOF\n", root);//遍历根节点下的子节点device_links_supplier_sync_state_pause();for_each_child_of_node(root, child) {//将device_node转化为platform_devicerc = of_platform_bus_create(child, matches, lookup, parent, true);if (rc) {of_node_put(child);break;}}device_links_supplier_sync_state_resume();//设置已经被转化的flagof_node_set_flag(root, OF_POPULATED_BUS);of_node_put(root);return rc;
}
EXPORT_SYMBOL_GPL(of_platform_populate);
2.3, of_platform_bus_create
/**
* of_platform_bus_create() - Create a device for a node and its children.
* @bus: device node of the bus to instantiate
* @matches: match table for bus nodes
* @lookup: auxdata table for matching id and platform_data with device nodes
* @parent: parent for new device, or NULL for top level.
* @strict: require compatible property
*
* Creates a platform_device for the provided device_node, and optionally
* recursively create devices for all the child nodes.
*/
static int of_platform_bus_create(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 *///节点中必须有compatible属性if (strict && (!of_get_property(bus, "compatible", NULL))) {pr_debug("%s() - skipping %pOF, no compatible prop\n",__func__, bus);return 0;}/* Skip nodes for which we don't want to create devices *///在of_skipped_node_table中的节点不会被转化if (unlikely(of_match_node(of_skipped_node_table, bus))) {pr_debug("%s() - skipping %pOF node\n", __func__, bus);return 0;}//判断节点是否已经被转化if (of_node_check_flag(bus, OF_POPULATED_BUS)) {pr_debug("%s() - skipping %pOF, already populated\n",__func__, bus);return 0;}auxdata = of_dev_lookup(lookup, bus);if (auxdata) {bus_id = auxdata->name;platform_data = auxdata->platform_data;}if (of_device_is_compatible(bus, "arm,primecell")) {/** Don't return an error here to keep compatibility with older* device tree files.*/of_amba_device_create(bus, bus_id, platform_data, parent);return 0;}//创建,初始化,注册一个devicedev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);//当某个根子节点的compatible属性为"simple-bus"、"simple-mfd"、"isa"、"arm,amba-bus"时,当前节点中的子节点将会被转换成platform_device节点if (!dev || !of_match_node(matches, bus))return 0;//转化当前节点中的子节点for_each_child_of_node(bus, child) {pr_debug("   create child: %pOF\n", child);rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);if (rc) {of_node_put(child);break;}}//设置node已经被转化的flagof_node_set_flag(bus, OF_POPULATED_BUS);return rc;
}
2.4,of_platform_device_create_pdata
/**
* of_platform_device_create_pdata - Alloc, initialize and register an of_device
* @np: pointer to node to create device for
* @bus_id: name to assign device
* @platform_data: pointer to populate platform_data pointer with
* @parent: Linux device model parent device.
*
* Returns pointer to created platform device, or NULL if a device was not
* registered.  Unavailable devices will not get registered.
*/
static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,void *platform_data,struct device *parent)
{struct platform_device *dev;//判断设备是否可用 status = okay,并且没有被转化过if (!of_device_is_available(np) ||of_node_test_and_set_flag(np, OF_POPULATED))return NULL;//创建并初始化一个platform_devicedev = of_device_alloc(np, bus_id, parent);if (!dev)goto err_clear_flag;dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);if (!dev->dev.dma_mask)dev->dev.dma_mask = &dev->dev.coherent_dma_mask;//device的bus_typedev->dev.bus = &platform_bus_type;//device的platform_datadev->dev.platform_data = platform_data;of_msi_configure(&dev->dev, dev->dev.of_node);//会调用到device_add(&ofdev->dev),将新转化来的设备添加到设备层次结构中if (of_device_add(dev) != 0) {platform_device_put(dev);goto err_clear_flag;}return dev;err_clear_flag:of_node_clear_flag(np, OF_POPULATED);return NULL;
}
2.5,of_device_alloc
/**
* of_device_alloc - Allocate and initialize an of_device
* @np: device node to assign to device
* @bus_id: Name to assign to the device.  May be null to use default name.
* @parent: Parent device.
*/
struct platform_device *of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)
{struct platform_device *dev;int rc, i, num_reg = 0, num_irq;struct resource *res, temp_res;dev = platform_device_alloc("", PLATFORM_DEVID_NONE);if (!dev)return NULL;/* count the io and irq resources *///统计reg属性的数量while (of_address_to_resource(np, num_reg, &temp_res) == 0)num_reg++;//统计中断irq属性的数量num_irq = of_irq_count(np);/* Populate the resource table *///根据num_irq和num_reg的数量申请相应struct resource内存空间if (num_irq || num_reg) {res = kcalloc(num_irq + num_reg, sizeof(*res), GFP_KERNEL);if (!res) {platform_device_put(dev);return NULL;}//设置platform_device中num_resources成员dev->num_resources = num_reg + num_irq;//设置platfrom_device中的resource成员dev->resource = res;//将device_node中的reg属性转换成platform_device中的struct resource成员for (i = 0; i < num_reg; i++, res++) {rc = of_address_to_resource(np, i, res);WARN_ON(rc);}//将device_node中的irq属性转换成platform_device中的struct resource成员if (of_irq_to_resource_table(np, res, num_irq) != num_irq)pr_debug("not all legacy IRQ resources mapped for %pOFn\n",np);}//将platform_device的dev.of_node成员指针指向device_nodedev->dev.of_node = of_node_get(np);//将platform_device的dev.fwnode成员指针指向device_node的fwnode成员dev->dev.fwnode = &np->fwnode;//设备parent为platform_bus, struct device platform_busdev->dev.parent = parent ? : &platform_bus;//构造platform device ->device 的名字if (bus_id)dev_set_name(&dev->dev, "%s", bus_id);elseof_device_make_bus_id(&dev->dev);return dev;
}
EXPORT_SYMBOL(of_device_alloc);

首先,函数先统计设备树中reg属性和中断irq属性的个数,然后分别为它们申请内存空间,链入到platform_device中的struct resources成员中。除了设备树中"reg"和"interrupt"属性之外,还有可选的"reg-names"和"interrupt-names"这些io中断资源相关的设备树节点属性也在这里被转换。

将相应的设备树节点生成的device_node节点链入到platform_device的dev.of_node中。

四,什么样的device_node会被解析成platform_device

首先,对于所有的device_node,如果要转换成platform_device,必须满足以下条件:

  •  一般情况下,只对设备树中根的子节点进行转换,也就是子节点的子节点并不处理。但是存在一种特殊情况,就是当某个根子节点的compatible属性为"simple-bus"、"simple-mfd"、"isa"、"arm,amba-bus"时,当前节点中的子节点将会被转换成platform_device节点。
  • 节点中必须有compatible属性。
const struct of_device_id of_default_bus_match_table[] = {{ .compatible = "simple-bus", },{ .compatible = "simple-mfd", },{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */{} /* Empty terminated list */
};

五,DeviceTree Kernel API

kernel中获取dts的资源可以参考如下链接提供的API函数:

DeviceTree Kernel API — The Linux Kernel documentation

参考链接:

https://www.cnblogs.com/downey-blog/p/10486568.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/753146.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jasypt 配置文件加密的用法

Jasypt 是一个用于配置文件加密的 Java 库。它可以用来加密和解密配置文件中的敏感信息&#xff0c;如数据库密码、API 密钥等。 使用 Jasypt 加密配置文件的步骤如下&#xff1a; 引入 Jasypt 依赖 首先&#xff0c;在你的项目的构建文件中添加 Jasypt 依赖。如果使用 Maven&…

AI系统性学习04—文本嵌入模型

文本嵌入&#xff08;text embedding&#xff09;是自然语言中的一项重要技术&#xff0c;是将文本转换了固定长度的低密度集向量的表示。 文章目录 1、文本嵌入介绍1.1 介绍1.2 文本嵌入与文本向量1.3 应用场景1.4 常用的文本嵌入模型 2、M3E文本嵌入模型2.1 模型介绍2.2 模型…

Games101笔记-模型、视图、投影

在旋转点&#xff0c;旋转矩阵的逆等于矩阵的转置 视图变换和投影变换 三维变换 左边3*3是线性变换&#xff0c;右边一列是仿射变换(平移) 先线性再平移 缩放、旋转、平移 x叉乘y得到z&#xff0c;y叉乘z得到x&#xff0c; xyz给任何两个可以得到另一个 (循环对称) z叉乘x得…

sqllab第十一关通关笔记

知识点&#xff1a; 发现登录框就可以尝试注入登录框一般都是字符型注入通过注入可以获取其他表的信息绕过手段 单引号闭合联合注入也可以进行错误注入 首先看界面是一个登录框&#xff1b;通过admin admin登录进去&#xff0c;发现页面会把用户名和密码的登录信息打印出来&am…

美区PayPal绑visa卡注意事项

很多小伙伴都有绑定paypal的需求&#xff0c;但是如果你是绑定美区的paypal这里有几点建议&#xff1a; 1、建议使用US的网络环境注册 2、使用美区的账号 3、使用美区的visa卡 三者统一才可以绑定成功&#xff0c;点击获取可以绑定美区paypal的visa卡&#xff0c;办理简单

【超细完整版】C# 获取WebService所有方法并调用 【调用篇】

注意&#xff1a;该文章涉及到的调用方法若找不到 请移步第一部分内容查找 C# 生成wsdl和dll教程请移步 【超细完整版】C# WebService 通过URL生成WSDL文件和DLL文件> 【生成篇】 开始 首先实现一个类&#xff0c;用于实现对URL的验证等 public class InputFormatVerifica…

【vue elementUI】修改el-dropdown样式

实现效果如下&#xff1a; 代码如下&#xff1a; <el-dropdown trigger"click" command"handleCommand" active-text-color"#606266"><span class"product-card">{{getCategoryName(categoryId)}}</span><el-dro…

docker安装华为opengauss高斯数据库

opengauss高斯数据库 openGauss是一款企业级开源关系型数据库&#xff0c;由华为公司推出。它深度融合了华为多年的数据库领域经验&#xff0c;充分结合企业级场景需求&#xff0c;基于openGauss自研生态而打造。 在架构上&#xff0c;openGauss着重于传统数据库的企业级能力和…

Monorepo 解决方案 — 基于 Bazel 的 Xcode 性能优化实践

背景介绍 书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》&#xff0c;在头条工程切换至 Bazel 构建系统后&#xff0c;为了支持用户使用 Xcode 开发的习惯&#xff0c;我们使用了开源项目 Tulsi 作为生成工具&#xff0c;用于将 Bazel 工程转换为 Xcode 工程。但是…

sqllab第二十七关通关笔记

知识点&#xff1a; union select 关键字过滤 通过<> /**/进行截断处理 un<>ion sel<>ect 没效果uni/**/on sel/**/ect 被过滤了双写绕过 这关对select进行了多重过滤&#xff0c;无法进行双写绕过 大小写绕过 UNion SElect (这关可以用&am…

亚马逊优惠券新规颁布,卖家应该如何应对?

最近亚马逊优惠券新规引发了很多跨境卖家的热议&#xff0c;内容显示&#xff0c;亚马逊于2024年3月12日实施新的优惠券规则&#xff0c;在这之后卖家提报优惠券需要遵守新的定价要求。到底发生了哪些变化和调整呢&#xff1f;今天就跟大家分析亚马逊优惠券新规政策的调整以及卖…

OpenvSwitch 配置 Trunk 端口实验

OpenvSwitch 配置 Trunk 端口实验 Open vSwitch(OVS)作为一款领先的软件交换机&#xff0c;为构建灵活、可扩展的虚拟网络架构提供了强大的支持。其中Trunk口(Trunk Port)功能就是OVS中一个非常实用的特性。 Trunk口允许在同一个物理端口上传输多个VLAN的数据流量。通过配置T…

蓝桥杯每日一题(BFS)

1562 微博转发 开始思路错误点&#xff1a;在用拉链法保存关注信息的时候&#xff0c;因为要看一个用户发的有多少转发的&#xff0c;所以要以用户为坑位&#xff0c;所有关注这个坑位的用户为链表。&#xff08;开始弄反了&#xff09; e数组存某个用户的idx&#xff0c;ne是…

西门子上位机软件WINCC的项目改造及其多元化报警功能实践:巨控GRM560智能远程控制终端

标签: #西门子WINCC #OPC通讯 #短信报警系统 #项目改造 #智能报警 西门子上位机软件WINCC的项目改造及其多元化报警功能实践 在工业自动化领域&#xff0c;有效的监控和及时的异常响应是保障生产安全和效率的关键。西门子的WINCC上位机软件升级&#xff0c;整合了巨控的OPC560…

Python 计算1~100 求和

result0 for i in range(101):print(i)result result i print(result)

Redis 内存是如何划分的?

查询内存命令 info memory 查询Redis自身使用内存的统计数据。通过这个命令&#xff0c;可以了解 Redis 实例的内存分配情况、内存碎片、键空间使用情况等 内存分配情况&#xff1a; used_memory&#xff1a;Redis 实例当前使用的内存总量&#xff08;以字节为单位&#xff0…

LeetCode 面试经典150题 45.跳跃游戏II

题目&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到…

【初学者】Visual Studio 2019没有 C 项目,只有C++怎么办? 怎么创建第一个项目教程。

起因&#xff1a; 想要在 Visual Studio 上创建一个 C 项目&#xff0c;发现只有 C 的。 解决&#xff1a; C 是 C 的超集。只要创建 C 的项目就行了&#xff0c;将新增的 .cpp 文件改后缀为 .c 即可。不会有问题的。 C 的语法更加严格&#xff0c;而 C 的项目更宽松。虽然…

【云呐】固定资产管理系统的功能有哪些?管理工具

为了提高经营效率&#xff0c;降低企业成本&#xff0c;许多企业选择固定资产管理系统。那么&#xff0c;固定资产管理系统有什么作用呢&#xff1f; 资产登记&#xff1a;  固定资产管理系统可以方便地登记公司的固定资产&#xff0c;包括资产名称、规格型号、购买日期、使…

3dmax渲染卡光子、灯光缓存的处理方法

1、在vray全局开关勾选最大射线强度 2、将场景材质转换为vray类型 3、关闭置换 4、清理空物体等场景垃圾 可以试一下优化场景的工具&#xff0c;清理空物体、空代理、适当塌陷精简场景、清理场景垃圾等 有3dmax效果图渲染需求可以使用渲染100&#xff08;注册填邀请码‘7788…