linux驱动学习---有些节点不会生成platform_device,怎么访问它们

这里对应韦东山linux开发手册11.7.3节内容。进行整理和对api使用方法的学习,以作备忘。如有问题,请大家提醒。
这里主要是找到节点,下一章介绍如何找到属性、获取属性的值。

有些节点不会生成platform_device,怎么访问它们

  • 内核启动时会解析 DTB,生成一棵树状结构,每个节点用 struct device_node 表示。
  • 对于有 compatible 并注册为设备的节点,内核有可能创建对应的 platform_device;但有些节点只是配置数据,不会生成 platform_device。
  • 在驱动中我们可以直接用 of_* 系列函数访问这些节点,读取它们的属性值。

以下的10个api,无论节点是否生成了 platform_device,都可以直接通过它们找到并访问该节点,因为它们是针对 设备树解析后的数据结构(struct device_node) 而不是针对设备模型(struct device / platform_device)的。

示例 DTB

假设我们的 DTS 中有一个不会创建 platform_device 的纯数据节点:

c 复制代码
/ {
    my_config {
        setting1 = <100>;
        setting2 = "hello";
        subnode {
            compatible = "myvendor,mysubnode";
            value = <42>;
        };
    };
};

编译成 DTB 后,这个 my_config 节点只有配置信息,不会有相应的驱动绑定。

主找到节点

1. of_find_node_by_path(path)

通过路径查找节点,返回节点指针。

c 复制代码
struct device_node *np;
np = of_find_node_by_path("/my_config");
if (np)
    pr_info("Found node: %s", np->name);

2. of_find_node_by_name(from, name)

从某个起始节点开始按名字查找:

c 复制代码
struct device_node *np;
np = of_find_node_by_name(NULL, "my_config"); // NULL 表示从整棵树查找

3. of_find_node_by_type(from, type)

按类型属性值查找(需要节点有 device_type 属性)。

查找规则

  • 它会从 from 节点开始(from == NULL 表示从整个设备树的第一个节点开始)
    顺序地遍历设备树中所有的节点
  • 找到第一个 device_type 属性值等于 type 的节点时 → 直接返回这个节点
  • 如果没找到符合条件的节点 → 返回 NULL
c 复制代码
np = of_find_node_by_type(NULL, "memory");

4. of_find_compatible_node(from, type, compat)

按 compatible 字符串匹配:

c 复制代码
np = of_find_compatible_node(NULL, NULL, "myvendor,mysubnode");

5. of_find_node_by_phandle(handle)

如果你有节点的 phandle,可以直接找:

设备树:

c 复制代码
clk1: clock@12340000 {
    compatible = "myvendor,myclock";
    reg = <0x12340000 0x1000>;
    phandle = <0x05>;
};

mydev: mydevice@20000000 {
    compatible = "myvendor,mydev";
    clocks = <&clk1>;  // 相当于 clocks = <0x05>;
};

驱动

c 复制代码
u32 clk_handle;
struct device_node *clk_node, *dev_node;

dev_node = of_find_node_by_path("/mydevice@20000000");
of_property_read_u32(dev_node, "clocks", &clk_handle);

clk_node = of_find_node_by_phandle(clk_handle);
pr_info("Found clock node: %s", clk_node->name);

6. of_get_parent(node)

获取父节点:

c 复制代码
struct device_node *parent;
parent = of_get_parent(np);

7. of_get_next_parent(node)

获取下一个父节点(往根节点方向逐个遍历):

c 复制代码
while ((np = of_get_next_parent(np)))
    pr_info("Parent: %s", np->name);

8. of_get_next_child(parent, prev)

遍历子节点:

c 复制代码
struct device_node *child = NULL;
while ((child = of_get_next_child(np, child)))
    pr_info("Child: %s", child->name);

9. of_get_next_available_child(parent, prev)

只获取状态为 okay 或无状态属性的子节点:

设备树的 status 属性

  • 在设备树里,节点可能有一个 status 属性,用来告诉内核这个设备是否启用。
  • 常见取值:
    • "okay" → 节点启用
    • "disabled" → 节点禁用
    • "reserved" → 节点保留(不启用)
  • 如果没有 status 属性,内核默认当成启用(相当于 "okay")。
c 复制代码
struct device_node *child = NULL;
while ((child = of_get_next_available_child(np, child)))
    pr_info("Available child: %s", child->name);

10. of_get_child_by_name(parent, name)

从父节点根据名字精确查找子节点:

c 复制代码
struct device_node *sub;
sub = of_get_child_by_name(np, "subnode");

整体的代码

c 复制代码
#include <linux/module.h>
#include <linux/of.h>
#include <linux/init.h>

static int __init mydrv_init(void)
{
    struct device_node *np, *child;
    const char *str;
    u32 val;

    // 找到 /my_config 节点
    np = of_find_node_by_path("/my_config");
    if (!np) {
        pr_err("my_config node not found!\n");
        return -ENODEV;
    }

    // 读取字符串属性 setting2
    if (!of_property_read_string(np, "setting2", &str))
        pr_info("setting2 = %s", str);

    // 读取整数属性 setting1
    if (!of_property_read_u32(np, "setting1", &val))
        pr_info("setting1 = %u", val);

    // 获取子节点 subnode
    child = of_get_child_by_name(np, "subnode");
    if (child) {
        if (!of_property_read_u32(child, "value", &val))
            pr_info("subnode value = %u", val);
    }

    return 0;
}

static void __exit mydrv_exit(void)
{
    pr_info("mydrv exit");
}

module_init(mydrv_init);
module_exit(mydrv_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DTB node access example");
相关推荐
HLC++16 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室17 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy20 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕20 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫1 天前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生1 天前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.111 天前
linux基础IO
linux·运维·服务器
BelongPanda1 天前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯1 天前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_777998341 天前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器