Linux下of常用函数集

在 Linux 内核中,设备树(Device Tree) 的操作通过一组 of_ 开头的函数(OF 表示 Open Firmware,即设备树标准来源)实现。这些函数定义在 include/linux/of.hdrivers/of/ 目录下,用于解析设备树节点、属性及硬件资源。以下是常用函数的分类总结,基本上分两类,一类寻找节点及父子兄弟关系,一类读取节点属性,还有一种是获取remote-endpoint的跨节点操作;

核心数据结构 device_node:

struct device_node {
	const char *name;		//节点名字
	phandle phandle;		//节点phandle,u32类型
	const char *full_name;	//节点全路径名字
	struct fwnode_handle fwnode;

	struct	property *properties;//节点内所有属性链表
	struct	property *deadprops;	/* removed properties */ // 被标记/delete-property/属性
	struct	device_node *parent;
	struct	device_node *child;
	struct	device_node *sibling; //并行的、同层次的几个兄弟节点链表
#if defined(CONFIG_OF_KOBJ)
	struct	kobject kobj;//对接驱动模型、sysfs需要的kobj
#endif
	unsigned long _flags;//表明节点处理状态
	void	*data;
};


1. 设备树节点操作

(1) 节点查找与遍历
函数作用示例
of_find_node_by_name(root, name)通过节点名查找节点node = of_find_node_by_name(NULL, "memory");
of_find_node_by_path(path)通过完整路径查找节点node = of_find_node_by_path("/soc/usb");
of_find_compatible_node(root, compat)通过 compatible 字符串查找节点node = of_find_compatible_node(NULL, NULL, "ti,omap3-uart");
of_get_parent(node)获取父节点parent = of_get_child_by_name(node, "interrupt-controller");
of_get_next_child(parent, prev)遍历子节点(需循环)while ((child = of_get_next_child(parent, child)) != NULL) { ... }
of_get_next_available_child()遍历可用的子节点(跳过 status = "disabled" 的节点)
(2) 节点状态检查

| of_device_is_available(node) | 检查节点是否可用(status = "okay"
比如 | if (of_device_is_available(node)) { ... } |
| of_node_name_eq(node, name) | 比较节点名是否匹配
比如| if (of_node_name_eq(node, "uart0")) { ... } |


2. 属性(Property)操作

(1) 读取属性值
函数作用示例
of_property_read_u32(node, prop, &val)读取 32 位整数属性of_property_read_u32(node, "clock-frequency", &clk);
of_property_read_u64()读取 64 位整数属性
of_property_read_string()读取字符串属性of_property_read_string(node, "compatible", &str);
of_property_read_bool()检查布尔属性是否存在(如 "enable"if (of_property_read_bool(node, "dma-coherent")) { ... }
of_property_count_elems_of_size()获取属性中元素的数量(如数组长度)len = of_property_count_elems_of_size(node, "reg", sizeof(u32));
(2) 特殊属性处理

| of_get_address() | 解析 reg 属性中的地址和大小(用于寄存器映射) | addr = of_get_address(node, 0, &size, &flags); |
| of_get_mac_address() | 读取 MAC 地址属性(如 "local-mac-address") | of_get_mac_address(node, mac_addr); |
| of_irq_get(node, index) | 解析中断号(interrupts 属性) | irq = of_irq_get(node, 0); |


3. 资源管理(寄存器、中断、DMA等)

函数作用
of_iomap(node, index)映射寄存器地址到内核虚拟地址(替代 ioremap
of_dma_configure()配置 DMA 参数(如 dma-ranges
of_clk_get(node, index)获取时钟资源
of_reset_control_get()获取复位控制器

示例(映射寄存器):

void __iomem *regs = of_iomap(node, 0);
if (!regs) {
    pr_err("Failed to map registers\n");
    return -ENXIO;
}

4. 设备树与平台设备

函数作用
of_platform_populate(parent)根据设备树节点自动创建平台设备
of_find_device_by_node(node)通过节点找到关联的 platform_device

5. 常用工具宏

作用
for_each_child_of_node(parent, child)循环遍历所有子节点
for_each_property_of_node(node, prop)循环遍历节点所有属性
of_node_put(node)减少节点引用计数(防止内存泄漏)

6. 实际应用示例

(1) 解析 UART 设备节点
struct device_node *node;
u32 baud_rate;

node = of_find_compatible_node(NULL, NULL, "ns16550a");
if (!node) {
    pr_err("UART node not found\n");
    return -ENODEV;
}

if (of_property_read_u32(node, "current-speed", &baud_rate))
    baud_rate = 115200; // 默认值

pr_info("UART baud rate: %d\n", baud_rate);
of_node_put(node);
(2) 处理中断
int irq = of_irq_get(node, 0);
if (irq <= 0) {
    dev_err(dev, "Failed to get IRQ\n");
    return irq ? : -ENXIO;
}

总结

  • 核心头文件#include <linux/of.h>
  • 关键设计思想:通过设备树解耦硬件描述与驱动代码,提高可移植性。
  • 调试工具
    • 查看设备树:cat /proc/device-treedtc -I fs /proc/device-tree
    • 内核配置:确保 CONFIG_OF 启用。

这些函数是 Linux 驱动开发中操作设备树的核心接口,熟练掌握后可高效编写与硬件无关的驱动代码。

Linux驱动开发中,`of`函数族用于与设备树(Device Tree)进行交互。设备树是一种描述硬件配置的数据结构,在嵌入式Linux系统中广泛使用,尤其是在ARM架构上。`of`函数主要定义在`<linux/of.h>`头文件中,提供了一系列API来访问设备树节点及其属性。 ### 设备树的基本概念 设备树由多个节点(node)组成,每个节点可以包含子节点和属性(property)。根节点为`/`,其下是各个硬件模块的描述节点。每个节点通常具有`compatible`属性,用来指定该节点所代表的硬件设备类型。 ### 常用的 `of` 函数 以下是一些常用的 `of` 函数及其用途: - **`of_find_node_by_name()`** 根据名称查找设备树中的节点。例如,查找名为`ethernet`的节点: ```c struct device_node *np = of_find_node_by_name(NULL, "ethernet"); ``` - **`of_find_node_by_type()`** 根据设备类型查找节点。例如,查找类型为`memory`的节点: ```c struct device_node *np = of_find_node_by_type(NULL, "memory"); ``` - **`of_find_compatible_node()`** 根据`compatible`字符串查找匹配的节点。这是最常用的方式之一,用于根据设备兼容性字符串查找对应的设备树节点: ```c struct device_node *np = of_find_compatible_node(NULL, NULL, "vendor,device"); ``` - **`of_property_read_u32()`** 读取设备树节点中的32位整数属性值。例如,读取`reg`属性的值: ```c u32 reg_value; if (of_property_read_u32(np, "reg", &reg_value)) { pr_err("Failed to read 'reg' property\n"); } ``` - **`of_property_read_string()`** 读取设备树节点中的字符串属性。例如,读取`label`属性: ```c const char *label; if (of_property_read_string(np, "label", &label)) { pr_err("Failed to read 'label' property\n"); } else { pr_info("Label: %s\n", label); } ``` - **`of_get_child_count()`** 获取指定节点下的子节点数量: ```c int child_count = of_get_child_count(np); pr_info("Number of child nodes: %d\n", child_count); ``` - **`of_get_next_child()`** 遍历指定节点的所有子节点: ```c struct device_node *child; for_each_child_of_node(np, child) { pr_info("Child node name: %s\n", child->name); } ``` ### 示例代码 以下是一个简单的示例,展示如何在驱动程序中使用 `of` 函数来获取设备树信息并初始化硬件资源: ```c #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/io.h> static int my_driver_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; void __iomem *regs; u32 reg_value; /* 获取寄存器地址 */ regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); /* 读取 reg 属性 */ if (of_property_read_u32(np, "reg", &reg_value)) { dev_err(&pdev->dev, "Failed to read 'reg' property\n"); return -EINVAL; } dev_info(&pdev->dev, "Register value from DT: 0x%x\n", reg_value); /* 读取 compatible 属性 */ if (of_device_is_compatible(np, "vendor,my-device")) { dev_info(&pdev->dev, "Device is compatible with 'vendor,my-device'\n"); } /* 读取 label 属性 */ const char *label; if (!of_property_read_string(np, "label", &label)) { dev_info(&pdev->dev, "Device label: %s\n", label); } /* 写入寄存器 */ writel(0x12345678, regs); return 0; } static const struct of_device_id my_driver_of_match[] = { { .compatible = "vendor,my-device" }, {}, }; MODULE_DEVICE_TABLE(of, my_driver_of_match); static struct platform_driver my_driver = { .probe = my_driver_probe, .driver = { .name = "my-driver", .of_match_table = my_driver_of_match, }, }; module_platform_driver(my_driver); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple driver using OF functions"); MODULE_LICENSE("GPL"); ``` ### 注意事项 - **内核版本兼容性**:确保使用的`of`函数在目标内核版本中可用,并且头文件路径正确(如`/lib/modules/$(uname -r)/build`)。 - **内存安全**:在访问寄存器时,应使用`ioread32`或`iowrite32`等函数,避免直接使用指针操作,以防止潜在的内存越界问题。 - **错误处理**:所有内核函数调用都必须检查返回值,特别是在处理设备树属性时,若属性不存在或读取失败,应及时返回错误码[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值