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");
相关推荐
iCxhust2 小时前
windows环境下在Bochs中运行Linux0.12系统
linux·运维·服务器·windows·minix
七七七七076 小时前
【计算机网络】深入理解ARP协议:工作原理、报文格式与安全防护
linux·服务器·网络·计算机网络·安全
lhxcc_fly9 小时前
Linux网络--8、NAT,代理,网络穿透
linux·服务器·网络·nat
摇滚侠9 小时前
Spring Boot3零基础教程,Spring Boot 应用打包成 exe 可执行文件,笔记91 笔记92 笔记93
linux·spring boot·笔记
yuanManGan10 小时前
走进Linux的世界:初识操作系统(Operator System)
android·linux·运维
Thexhy10 小时前
在 CentOS 7 的 Linux 系统中配置 NFS
linux·运维·学习·centos
咯哦哦哦哦10 小时前
linux vscode+cmake+clangd
linux·ide·vscode
lang2015092811 小时前
如何在 Linux 中获取更多信息
linux·运维·服务器
DeBuggggggg11 小时前
linux 安装Python3.9 且支持SSL
linux·运维·ssl