platformd device、driver注册过程

本文以smsc911x驱动为例

platform_device注册过程

该设备被定义在dts里面了

参考文章设备树节点转换为设备节点device_node、和平台设备资源platform_device_设备树节点转换成平台设备-CSDN博客

dts里面的节点会被转换为device_node和platform_device(并不是所有节点都会被转换为platform_device)

    ethernet@3,02000000 {compatible = "smsc,lan9118", "smsc,lan9115";reg = <3 0x02000000 0x10000>;interrupts = <15>;phy-mode = "mii";reg-io-width = <4>;smsc,irq-active-high;smsc,irq-push-pull;vdd33a-supply = <&v2m_fixed_3v3>;vddvario-supply = <&v2m_fixed_3v3>;};

 内核初始化时,回去解析dts文件,然后去注册各个设备,大致的流程如下图

 (我也忘了哪里听到了这个说法,不知道对不对。platform总线,设备和驱动。设备往platform总线上注册,注册的时候回去probe,匹配驱动。同样注册驱动的时候,也会去匹配设备)

下图是之间调用platform_device_register注册设备的过程 

 在下列函数中加入了打印,看看究竟有哪些device_node

int of_platform_populate(struct device_node *root,const struct of_device_id *matches,const struct of_dev_auxdata *lookup,struct device *parent)
{
......................printk("\r\n %s,%d, device_node %s, parnet %s\n", __FUNCTION__, root->name, parent ? parent->init_name : "null");for_each_child_of_node(root, child) {printk("\r\n%s,%d child %s\n", __FUNCTION__, __LINE__, child->name);rc = of_platform_bus_create(child, matches, lookup, parent, true);if (rc)break;}
....................
}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)
{
.........................for_each_child_of_node(bus, child) {printk("   create child: %s\n", child->full_name);rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
................}return rc;
}

 打印结构如下图。比较奇怪的是virtio_mmio dts里面没有,不知道是从哪里出来的

dts文件名vexpress-v2p-ca9.dts和vexpress-v2m.dtsi

最后根据dts或者是打印信息可以看到device_node的关系如下图。

 跟节点上挂了chosen...smb(simple bus),然后vexpress-v2m.dtsi里面的所有节点有全部挂到了smb下面。

这些节点是为什么会挂到smb下面呢?怀疑是smb节点包含了该头文件导致

/{

        chosen { };

..........................

        smb {
                compatible = "simple-bus";

        ..................................................

                /include/ "vexpress-v2m.dtsi"

        };

};

b. 并非所有的device_node都会转换为platform_device只有以下的device_node会转换:

  • 该节点必须含有compatible属性
  • 根节点的子节点(节点必须含有compatible属性)
  • 含有特殊compatible属性的节点的子节点(子节点必须含有compatible属性)这些特殊的compatilbe属性为: “simple-bus”,“simple-  mfd”,“isa”,"arm,amba-bus "
  • 根节点是例外的,生成platfrom_device时,即使有compatible属性也不会处理

注意:i2c, spi等总线节点会转换为platform_device,但是,spi、i2c下的子节点无论compatilbe是否为: “simple-bus”,“simple-  mfd”,“isa”,"arm,amba-bus "都应该交给对应的总线驱动程序来处理而不会被转换为platform_device

device_node并不等同于platform_device,感觉转换规则就是这个函数里面确定的

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 */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);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;}/* 怀疑上面的代码就是引用里面说的转换规则 */dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);if (!dev || !of_match_node(matches, bus))return 0;if (g_v2m == 1)printk("platform_device: %s, device node: %s\n", dev->name, bus->full_name);for_each_child_of_node(bus, child) {//if (g_v2m == 1)//printk("   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;
}

可以看到这么多device_node最后转换为platform_device的节点只有这三个 。compatible属性也满足条件

platform_device: smb, device node: /smb
platform_device: smb:motherboard, device node: /smb/motherboard
platform_device: smb:motherboard:iofpga@7,00000000, device node: /smb/motherboard/iofpga@7,00000000

    motherboard {
        model = "V2M-P1";
        arm,hbi = <0x190>;
        arm,vexpress,site = <0>;
        compatible = "arm,vexpress,v2m-p1", "simple-bus";
        #address-cells = <2>; /* SMB chipselect number and offset */
        #size-cells = <1>;
        #interrupt-cells = <1>;
        ranges;

那其他的节点如果不转换为platform_device,那是如何与platform_driver匹配的呢?比如Ethernet节点 

更正一下上面的说法,后面经过加打印,确认Ethernet节点其实是被转换为了platform_device了的

b. 并非所有的device_node都会转换为platform_device只有以下的device_node会转换:

那这句话还是对的吗?后面研究研究 

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)
{
........................if (g_v2m == 1)printk("%s,%d device node: %s\n", __FUNCTION__, __LINE__, bus->full_name);
........................dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);if (!dev || !of_match_node(matches, bus)){if (g_v2m == 1)printk("fail create platform_device ??, dev %p, device node: %s\n",dev, bus->full_name);return 0;}if (g_v2m == 1)printk("%s,%d platform_device: %s, device node: %s\n", __FUNCTION__, __LINE__, dev->name, bus->full_name);for_each_child_of_node(bus, child) {if (g_v2m == 1)printk("   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;
}

打印信息如下。暂时不知道of_match_node没有满足是什么意思。但是看样子device是创建成功了的。

 platform driver注册

关于platform_driver是在驱动代码里面通过module init,在初始化阶段通过do init call调用注册函数

大致流程如下 ​​​​​​

1 设备向内核注册platform_device(platform_device_register、或者是通过dts)​​​​​​,把设备挂在虚拟的platform bus下

2 驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev()。对每个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device()->drv->bus->match()==platform_match(),有几种匹配规则,如果相符就调用platform_drv_probe()->driver->probe(),如果probe(本例中则是smsc911x_drv_probe)成功则绑定该设备到该驱动

本例是通过驱动代码里面的of_match_table进行匹配。名字要和dts里面的相同

感觉1和2没有先后顺序,看代码不论是设备注册或者是驱动注册的时候都会去调用driver probe device尝试发现对方

dts中尝试新增设备

1 dts中新增节点

 

2、重新编译dtb文件。这样加载dts的时候就会注册该设备

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-

make dtbs

3、添加驱动代码,注册platform_driver

static int my_drv_probe(struct platform_device *pdev)
{printk("%s,%d platform_device name: %s, device_node full name %s\n", \__FUNCTION__, __LINE__, pdev->name, pdev->dev.of_node->full_name);return 0;	
}
static int my_drv_remove(struct platform_device *pdev)
{printk("%s,%d platform_device name: %s, device_node full name %s\n", \__FUNCTION__, __LINE__, pdev->name, pdev->dev.of_node->full_name);return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id new_node_test[] = {{ .compatible = "arm,newnodetest", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, new_node_test);
#endif#define MY_DRV_NAME		"newnodetest"
static struct platform_driver my_driver = {.probe = my_drv_probe,.remove = my_drv_remove,.driver = {.name	= MY_DRV_NAME,.owner	= THIS_MODULE,.pm	= NULL,.of_match_table = of_match_ptr(new_node_test),},
};/* Entry point for loading the module */
static int __init my_init_module(void)
{dump_stack();SMSC_INITIALIZE();return platform_driver_register(&my_driver);
}/* entry point for unloading the module */
static void __exit my_cleanup_module(void)
{platform_driver_unregister(&my_driver);
}module_init(my_init_module);
module_exit(my_cleanup_module);

运行信息打印

解析device node能看到有新增的节点

通过module init注册的初始化函数,也调用了,从而注册了platform_drive,最后也走到了我们写的probe函数

dts语法规则不清楚,后面看一下dts语法 

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

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

相关文章

vi编辑器使用

说明&#xff1a;本文介绍vi编辑器使用&#xff1b; 介绍&基础使用 vi编辑器是linux操作系统中最常用的编辑器&#xff0c;使用vi或vim命令启动。vim是vi编辑器的增强版&#xff0c;大多数情况使用vi命令也会打开vim编辑器&#xff0c;为了方便介绍&#xff0c;以下均称v…

【Web】2024XYCTF题解(全)

目录 ezhttp ezmd5 warm up ezMake ez?Make εZ?мKε? 我是一个复读机 牢牢记住&#xff0c;逝者为大 ezRCE ezPOP ezSerialize ezClass pharme 连连看到底是连连什么看 ezLFI login give me flag baby_unserialize ezhttp 访问./robots.txt 继…

从阿里云崩溃看IT系统非功能能力验证

昨天下午6点左右学员群里有人说阿里云又出问题了&#xff0c;并且还挺长时间没有恢复了。 我也登录了一下&#xff0c;结果登录直接不停地302。如下所示&#xff1a; 做为阿里云重要的基础设施&#xff0c;这一故障影响了。如官方通告的处理时间线&#xff1a; 17:44起&#…

【JavaEE初阶系列】——理解tomcat 带你实现最简单的Servlet的hello world程序(七大步骤)

目录 &#x1f6a9;认识Tomcat &#x1f6a9;运用Tomcat &#x1f6a9;Servlet &#x1f393;完成简单的Servlet的hello world程序 &#x1f388;创建项目Maven &#x1f388;引入依赖 &#x1f388;创建目录 &#x1f388;编写代码 &#x1f388;打包程序 &#x1…

Go 语言基础(一)【基本用法】

前言 最近心情格外不舒畅&#xff0c;不仅仅是对前途的迷茫&#xff0c;这种迷茫倒是我自己的问题还好&#xff0c;关键它是我们这种普通吗喽抗衡不了的。 那就换个脑子&#xff0c;学点新东西吧&#xff0c;比如 Go&#xff1f; 1、Go 语言入门 介绍就没必要多说了&#xff0…

求矩阵对角线元素之和(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int sum 0;int a[3][3] { 0 };//获取数组a的值&#xff1b;printf(&qu…

『大模型笔记』Code Example: Function Calling with ChatGPT

Code Example: Function Calling with ChatGPT 文章目录 一. Code Example: Function Calling with ChatGPT二. 参考文献一. Code Example: Function Calling with ChatGPT from openai import OpenAI from dotenv import load_dotenv import json# --------------------------…

标准汽车试验铁地板的技术要求

在现代科技化发展的工作中&#xff0c;试验平台被广泛使用。铸铁试验平台&#xff08;试验铁地板&#xff09;又叫试验工作平台&#xff0c;听名字大家也不难想象出来这是一款带有箱式体的台面&#xff0c;这是一种有长方形或者圆形又或者正方形的试验工作台。 铸铁试验平台&a…

调用WinPE给现有的Windows做一个备份

前言 前段时间有小伙伴问我&#xff1a;如何让给电脑备份系统。 小白直接告诉他&#xff1a;为啥要备份系统呢&#xff1f;直接给电脑创建一个还原点就好了。 Windows还原点创建教程&#xff08;点我跳转&#xff09; 没想到小伙伴的格局比小白大得多&#xff0c;他说&…

2024年第二十一届 五一杯 (C题)大学生数学建模挑战赛 | 多目标优化问题,深度学习分析 | 数学建模完整代码解析

DeepVisionary 每日深度学习前沿科技推送&顶会论文&数学建模与科技信息前沿资讯分享&#xff0c;与你一起了解前沿科技知识&#xff01; 本次DeepVisionary带来的是五一杯的详细解读&#xff1a; 完整内容可以在文章末尾全文免费领取&阅读&#xff01; 首先&…

编码方式导致的csv文件错误

写入csv文件时&#xff0c;假如出现了csv文件是乱码的情况&#xff0c;那么说明编码方式有问题&#xff0c;需要修改一下编码方式为utf-8-sig。 把编码方式修改一下为encodingutf-8-sig &#xff0c;再次运行就不会是乱码了&#xff0c;可见再读写csv文件时&#xff0c;假如使用…

【报错处理】ib_write_bw执行遇到Found Incompatibility issue with GID types.原因与解决办法

文章目录 拓扑现象根因解决办法解决后效果 拓扑 #mermaid-svg-zheSkw17IeCpjnVA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zheSkw17IeCpjnVA .error-icon{fill:#552222;}#mermaid-svg-zheSkw17IeCpjnVA .error…

Python语言零基础入门——模块

目录 一、模块的导入与使用 1.模块的导入 2.模块的使用 二、包的使用 1.包 2.包的使用 三、常见的标准库 1.random的运用举例 2.random小游戏 &#xff08;1&#xff09;石头剪刀布 &#xff08;2&#xff09;猜大小 3.re 4.time库的使用 5.turtle库的使用 6.so…

手把手实现一个简约酷美美的版权声明模块

1. 导语 版权声明在很多网站都有用到&#xff0c;出场率还是很高的。所以今天就实现一个属于自己分风格的版权声明模块&#xff0c;技术上采用原生的前端三剑客: HTMLCSSJavaScript(可能会用到) 比如CSDN的版权声明是这样的 2. 需求分析 先看看成品吧&#xff0c;这篇文字结…

Access to image at ... from origin ... has been blocked

Access to image at ‘http://127.0.0.1:3000/api/getImg?url/uploads/file/20240421/file-1713715007811-logo.png’ from origin ‘http://ggbol.gnway.cc’ has been blocked by CORS policy: The request client is not a secure context and the resource is in more-pri…

【C++】---模板进阶

【C】---模板进阶 一、模版参数1、类型参数2、非类型参数 二、模板的特化1、函数模板的特化2、类模板特化&#xff08;1&#xff09;全特化&#xff08;2&#xff09;偏特化 三、模板分离编译1、模板支持分离编译吗&#xff1f;2、为什么模板不支持分离编译&#xff1f;3、如何…

google search API 获取

登录谷歌云启动服务 首先登录谷歌云Google Cloud: https://console.cloud.google.com/&#xff0c;登录后创建一个项目。 选择创建的项目&#xff0c;进入API库。搜索Google Search。 选择custom Search API并启用。 此外&#xff0c;有个非常具有类似的API-- Google Search …

3D建模在游戏行业的演变和影响

多年来&#xff0c;游戏行业经历了显着的转变&#xff0c;这主要是由技术进步推动的。 深刻影响现代游戏的关键创新之一是 3D 建模领域。 从像素化精灵时代到我们今天探索的错综复杂的游戏世界&#xff0c;3D 建模已成为游戏开发不可或缺的基石。 本文讨论 3D 建模在游戏行业中…

PyVista 3D数据可视化 Python 库 一行代码实现裁剪 含源码

简介&#xff1a; Pyvista是一个用于科学可视化和分析的Python库,使3D数据可视化变得更加简单和易用&#xff1b; 只增加一行代码就可以实现裁剪&#xff1b; 1.效果&#xff1a; 2.代码如下&#xff1a; 加载模型数据&#xff1a; 代码实现&#xff1a; import pyvista a…

查找算法之二分查找

一、算法介绍 二分查找&#xff0c;也称为折半查找&#xff0c;是一种在有序数组中查找特定元素的高效算法。对于包含 n 个元素的有序数组&#xff0c;二分查找的步骤如下&#xff1a; 确定搜索范围&#xff1a;首先&#xff0c;将要查找的元素与数组中间的元素进行比较。如果…