device_node转换成platform_device

news2024/12/24 8:32:59

device_node转换成platform_device


文章目录

  • device_node转换成platform_device
  • 转换规则
  • 主要核心函数
    • of_default_bus_match_table
    • arm
    • arm64
    • of_platform_register_reconfig_notifier
  • Linux内核是如何将device_node转换成platform_device
    • of_platform_populate函数
    • 处理根节点下的子节点(匹配规则2)


设备树替换了平台总线模型当中对硬件资源描述的device部分。所以设备树也是对硬件资源进行描述的文件。
在这里插入图片描述

在平台总线模型中,device部分是用platform_device结构体来描述硬件资源的。所以内核最终会将内核认识的device_node树转换platform_device。
但是并不是所有的节点都会被转换成platform_device,只有满足要求的才会转换成platform_device,
转换成platformdevice的节点可以在/sys/bus/platform/devices下查看。

在这里插入图片描述
在这里插入图片描述

节点要满足什么要求才会被转换成platform_device呢?

转换规则

1.根节点下包含compatible属性的子节点。
2.节点中compatible属性包含simple-bus,simple-mfd,isa其中之一的节点下包含compatible属性的子节。
3.如果节点的compatible属性包含arm,primecell值,则对应的节点会被转换成不会被转换成amba设各。不会被转换成platform_device。

主要核心函数

of_default_bus_match_table

const struct of_device_id of_default_bus_match_table[] = {
    { .compatible = "simple-bus", },
    { .compatible = "simple-mfd", },
#ifdef CONFIG_ARM_AMBA
    { .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
    {} /* Empty terminated list */
};

arm

static int __init customize_machine(void)
{
    /*
     * customizes platform devices, or adds new ones
     * On DT based machines, we fall back to populating the
     * machine from the device tree, if no callback is provided,
     * otherwise we would always need an init_machine callback.
     */
    of_iommu_init();
    if (machine_desc->init_machine)
        machine_desc->init_machine();
#ifdef CONFIG_OF
    else
        of_platform_populate(NULL, of_default_bus_match_table,
                    NULL, NULL);
#endif
    return 0;
}
arch_initcall(customize_machine);

在这里插入图片描述

arm64

在内核启动的时候会执行of_platform_default_populate_init函数,这个函数是用arch_initcall_sync来修饰的。

arch_initcall_sync(of_platform_default_populate_init);

所以系统启动的时候会调用of_platform_default_populate_init函数,然后调用一系列函数进行转换,转换流程如下,
在这里插入图片描述

arch/arm64/kernel/setup.c

static int __init arm64_device_init(void)
{
of_iommu_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
arch_initcall_sync(arm64_device_init);

of_platform_register_reconfig_notifier

int __init platform_bus_init(void)
{
    int error;

    early_platform_cleanup();

    error = device_register(&platform_bus);
    if (error)
        return error;
    error =  bus_register(&platform_bus_type);
    if (error)
        device_unregister(&platform_bus);
    of_platform_register_reconfig_notifier();
    return error;
}

of_platform_notify函数是Linux内核中的一个通知机制,主要作用是把动态加载的设备树的节点解析出来,以便在驱动模型的基础上构建实际的设备驱动。在platform总线上的控制器模块都是挂在这条总线上,而of_platform_notify函数则是把这些控制器模块挂载到内核中。
在这个函数中,当动态加载一个设备树节点时,会先检查其父节点是否为一个总线,如果不是则返回NOTIFY_OK;如果已经被挂载,则返回NOTIFY_OK;否则会创建一个platform_device并将其挂载到内核中。当卸载一个设备树节点时,会先检查其是否已经被卸载,如果没有则会找到该设备并将其从内核中卸载。

static int of_platform_notify(struct notifier_block *nb,
                unsigned long action, void *arg)
{
    struct of_reconfig_data *rd = arg;
    struct platform_device *pdev_parent, *pdev;
    bool children_left;

    switch (of_reconfig_get_state_change(action, rd)) {
    case OF_RECONFIG_CHANGE_ADD:
        /* verify that the parent is a bus */
        if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS))
            return NOTIFY_OK;    /* not for us */

        /* already populated? (driver using of_populate manually) */
        if (of_node_check_flag(rd->dn, OF_POPULATED))
            return NOTIFY_OK;

        /* pdev_parent may be NULL when no bus platform device */
        pdev_parent = of_find_device_by_node(rd->dn->parent);
        pdev = of_platform_device_create(rd->dn, NULL,
                pdev_parent ? &pdev_parent->dev : NULL);
        of_dev_put(pdev_parent);

        if (pdev == NULL) {
            pr_err("%s: failed to create for '%s'\n",
                    __func__, rd->dn->full_name);
            /* of_platform_device_create tosses the error code */
            return notifier_from_errno(-EINVAL);
        }
        break;

    case OF_RECONFIG_CHANGE_REMOVE:

        /* already depopulated? */
        if (!of_node_check_flag(rd->dn, OF_POPULATED))
            return NOTIFY_OK;

        /* find our device by node */
        pdev = of_find_device_by_node(rd->dn);
        if (pdev == NULL)
            return NOTIFY_OK;    /* no? not meant for us */

        /* unregister takes one ref away */
        of_platform_device_destroy(&pdev->dev, &children_left);

        /* and put the reference of the find */
        of_dev_put(pdev);
        break;
    }

    return NOTIFY_OK;
}

static struct notifier_block platform_of_notifier = {
    .notifier_call = of_platform_notify,
};

void of_platform_register_reconfig_notifier(void)
{
    WARN_ON(of_reconfig_notifier_register(&platform_of_notifier));
}
#endif /* CONFIG_OF_DYNAMIC */

#endif /* CONFIG_OF_ADDRESS */

Linux内核是如何将device_node转换成platform_device

of_platform_populate函数

该函数主要调用了of_platform_populate函数
drivers/of/platform.c
of_platform_populate函数是Linux内核中的一个函数,主要作用是将设备树中的device node创建成platform device,为后续和各类驱动的platform driver匹配做准备。在Linux内核启动时,内核通过of_platform_populate函数,将dts中的device node创建成platform device。
of_platform_populate函数定义如下所示:

int of_platform_populate(struct device_node *root,
                const struct of_device_id *matches,
                const struct of_dev_auxdata *lookup,
                struct device *parent)

其中,root是第一级要探测的父节点或NULL表示树的根;matches是匹配表,NULL表示使用默认值;lookup是用于匹配id和platform_data与设备节点的auxdata表;parent是要挂载设备的父节点,NULL表示顶层。详细内容如下:

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;

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

    of_node_put(root);
    return rc;
}

of_platform_populate
of_platform_bus_create
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;

    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;
        }
    }
    of_node_set_flag(bus, OF_POPULATED_BUS);
    return rc;
}

转换规则1

if (strict && (!of_get_property(bus, “compatible”, NULL))) {
pr_debug(“%s() - skipping %s, no compatible prop\n”,
func, bus->full_name);
return 0;
}

转换规则3

  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;
    }

处理根节点下的子节点(匹配规则2)

dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;

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;
}
}
of_node_set_flag(bus, OF_POPULATED_BUS);

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;

    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;
        }
    }
    of_node_set_flag(bus, OF_POPULATED_BUS);
    return rc;
}

设备树转换成paltform_device以后就和平台总线模型一样啦。所以驱动和设备也会根据名字来匹配。匹配成功以后会执行驱动中的probe函数。
匹配优先级:name<id_table<of_match_table

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

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

相关文章

在ubuntu连接Xlight FTP Server

一 在windows上搭建服务器 http://www.xlightftpd.com/download.htm 使用英文版&#xff0c;使防止在ubuntu中登录中文版时&#xff0c;显示乱码 新建用户和用户对应的服务器目录 如下所示&#xff0c;默认只有读权限 全都勾选 勾选完毕后的效果 在目录中放一个文件&#…

10款常用的原型设计工具,包含一键生成原型工具

原型图是产品设计师日常工作的“常客”&#xff0c;原型图软件也扮演着产品设计师的“武器”角色。 许多新产品设计师不知道如何选择原型图软件。本文盘点了10个优秀的原型图软件&#xff0c;让我们来看看。 1.即时设计 即时设计是一款免费的在线 UI 设计工具&#xff0c;无…

【Java数据结构】排序

排序 插入排序希尔排序选择排序堆排序冒泡排序快速排序序列的分割Hoare法挖坑法快慢指针法 优化1 - 三数取中优化2- 数据规模小时的插入 归并排序 插入排序 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插…

Jetson Orin环境安装Opencv+Cuda以及vscode环境配置

文章目录 一&#xff1a;Opencv Cuda源码的下载、编译1.卸载jetson上自带的无cuda加速Opencv2.安装Opencv依赖库3.下载 OpenCV 和 opencv_contrib 源码4.编译安装 OpenCV、opencv_contrib 二&#xff1a;Opencv 的环境配置三&#xff1a;Vscode 中的Opencv环境配置四&#xff…

系统分析师---系统建模相关高频考试知识点

系统规划---成本效益分析 评价信息系统经济效益常用的方法主要有成本效益分析法,投入产出分析法和价值工程方法。盈亏平衡法常用于销售定价; 可行性分析 系统规划是信息系统生命周期的第一个阶段,其任务是对企业的环境、目标以及现有系统的状况进行初步调查,根据企业目标…

张正友相机标定原理

相机标定 记录1.1 张正友相机标定相关 参考 记录 最小二乘法&#xff1a;A^T A x 0 奇异值分解的办法求解最小二乘法 因为可以假设标定板平面在世界坐标系Z0的平面上&#xff0c; 1.1 张正友相机标定相关 单目相机标定实现–张正友标定法(包含具体的实现以及C代码&#xff0…

《花雕学AI》ChatGPT Shortcut Chrome 扩展:让生产力和创造力加倍的 ChatGPT 快捷指令库

你是否想要与一个智能的对话伙伴聊天&#xff0c;或者让它帮你完成各种任务&#xff0c;如写作、编程、摘要、翻译等&#xff1f;如果是的话&#xff0c;你可能会对 ChatGPT 感兴趣。ChatGPT 是一个基于 GPT-3.5 的对话式人工智能&#xff0c;可以与用户进行自然、流畅、有趣的…

文件看不见了,内存还占着容量的找回教程

U盘文件突然不见了但还占用内存空间的解决方法 如果文件看不见了但内存占用仍然存在&#xff0c;可能是因为以下原因&#xff1a; 文件被隐藏。某些操作系统允许隐藏文件&#xff0c;这些文件只能在文件浏览器中被找到。 文件被损坏。如果文件损坏&#xff0c;它可能不会显示在…

Python图形化编程开源项目拼码狮PinMaShi

开源仓库 #项目地址 https://github.com/supercoderlee/pinmashi https://gitee.com/supercoderlee/pinmashiPinMaShi采用electron开发&#xff0c;图形化拖拽式编程有效降低编程难度&#xff0c;对Python编程的初学者非常友好&#xff1b;积木式编程加快Python程序的开发&…

黑马Redis笔记-高级篇

黑马Redis笔记-高级篇 1、Redis持久化&#xff08;解决数据丢失&#xff09;1.1 RDB持久化1.1.1 定义1.1.2 异步持久化bgsave原理 1.2 AOF持久化1.3 RDB和AOF比较 2、Redis主从&#xff08;解决并发问题&#xff09;2.1 搭建主从架构2.2 主从数据同步原理2.2.1 全量同步2.2.2 增…

基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法 -附代码

基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法 文章目录 基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法1.KELM理论基础2.分类问题3.基于哈里斯鹰算法优化的KELM4.测试结果5.Matlab代码 摘要&#xff1a;本文利用哈里斯鹰算法对核极限学习机(KELM)进行优化&#xff0c…

【小梦C嘎嘎——启航篇】基本语法格式:namespace ?

基本语法格式&#xff1a;namespace &#xff1f;&#x1f60e; 前言&#x1f64c;namespace 是什么&#xff1f;namespace 的意义何在&#xff1f; 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&…

springboot + vue 部署 阿里云云服务器 ECS

安装所需文件 安装mysql5.7 下载MySQL的yum源配置 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装MySQL的yum源 yum -y install mysql57-community-release-el7-11.noarch.rpm使用yum方式安装MySQL5.7&#xff08;下载需要点时间&#xf…

【 断电延时继电器 电源监视 导轨安装 JOSEF约瑟 HJZS-E202 AC220V】

品牌&#xff1a;JOSEF约瑟型号&#xff1a;HJZS-E202名称&#xff1a;断电延时继电器额定电压&#xff1a;110、220VDC/AC&#xff1b;100VAC触点容量&#xff1a;250V/5A功率消耗&#xff1a;≤4.2W返回系数&#xff1a;10%额定电压 系列型号&#xff1a; HJZS-E202断电延时…

4.4 栈实现及其应用

目录 栈 顺序栈 创建栈: 清空栈: 判断栈是否空 &#xff1a; 进栈 : 出栈 : 取栈顶元素: 栈 栈是限制在一端进行插入操作和删除操作的线性表&#xff08;俗称堆栈&#xff09; 允许进行操作的一端称为“栈顶” 另一固定端称为“栈底” 当栈中没有元素时称为“空栈”…

Robbin负载均衡详解及实践---SpringCloud组件(三)

Robbin负载均衡详解及实践 一 为什么使用Robbin&#xff1f;二 Robbin概念三 负载均衡实践1.启动eureka客户端2.启动多个provider服务&#xff0c;注册到eureka3.在consumer端配置负载均衡参数 四 Robbin源码剖析 一 为什么使用Robbin&#xff1f; 在Eureka详解及实践—Spring…

SAS初识

1、SAS常用工作窗口 “结果”&#xff08;Result&#xff09;窗口——管理SAS程序的输出结果&#xff1b; “日志”&#xff08;Log&#xff09;窗口——记录程序的运行情况&#xff1b; “SAS资源管理器”&#xff08;Explore&#xff09;窗口&#xff1b; “输出”&#xff0…

详解vue中的Object.defineProperty

如果想要age遍历的话 就设置属性 打印出来 发现有可以枚举的属性age 参考课程&#xff1a; 011_尚硅谷Vue技术_Object.defineProperty_哔哩哔哩_bilibili // 1.Vue中的数据代理&#xff1a; // 通过Vm对象来代理data对象中属性的操作&#xff08;读/写&#xff09; // 2…

STL容器 —— list 了解、接口使用,以及模拟实现list(部分常用接口)

注意 &#xff1a; 以下所有文档都来源此网站 &#xff1a; http://cplusplus.com/ 一、vector的介绍及使用 list文档的介绍&#xff1a;https://cplusplus.com/reference/list/list/ 1. vector 的介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&…

python自动化测试工具selenium使用指南 ,绝对能帮到你

目录 概述 pythonselenium环境安装 使用selenium启动浏览器 selenium页面加载等待和检测 使用time.sleep()等待 使用implicitly_wait设置最长等待时间 使用WebDriverWait设置等待条件 检测document是否加载完成 selenium元素定位和读取 查找元素 dom元素交互 查找元…