struct of_device_id

📅 发布时间:2026/7/9 6:05:59 👁️ 浏览次数:
struct of_device_id
struct of_device_id是Linux 设备树Device Tree, DT机制中用于驱动与设备树节点进行匹配的核心数据结构主要在 ARM、ARM64、RISC-V 等现代架构的驱动开发中使用替代了传统的platform_device_id匹配方式实现了「硬件信息与驱动代码的解耦」。核心定位struct of_device_id的核心作用是在驱动中定义「需要匹配的设备树节点规则」让总线如 Platform 总线能够根据该规则找到对应的设备树节点并完成驱动与设备的绑定。简单来说设备树中用compatible等属性描述硬件设备驱动中用struct of_device_id列出「支持的硬件设备列表」总线的match函数会对比两者的compatible属性匹配成功则调用驱动的probe函数。它的定义在include/linux/of.h头文件中是设备树驱动开发的「必备组件」。完整定义Linux 5.x 及以上版本struct of_device_id { char *compatible; // 核心匹配设备树节点的 compatible 属性 const void *data; // 驱动私有数据匹配成功后传递给 probe 函数的附加数据 };关键字段深度解析compatible核心匹配字段重中之重作用用于与设备树节点中的compatible属性进行字符串比对是设备与驱动匹配的「核心依据」。格式要求采用「厂商名设备名」的格式确保全球唯一避免设备冲突格式为vendor,device也可支持多个兼容值设备树中compatible属性可定义多个字符串。厂商名通常是芯片厂商缩写如fsl飞思卡尔、ti德州仪器、rockchip瑞芯微、intel英特尔。设备名通常是芯片型号或外设名称如imx6ul-uart、am335x-i2c、rk3399-gpio。设备树对应示例设备树中一个 UART 节点的compatible属性定义如下uart1: serial12340000 { compatible fsl,imx6ul-uart, ns16550a; // 两个兼容值优先匹配前者 reg 0x12340000 0x1000; };驱动中对应的compatible字段可写fsl,imx6ul-uart精确匹配或ns16550a通用匹配支持多款兼容 NS16550 协议的 UART。匹配规则总线会遍历设备树节点的compatible字符串数组只要有一个与驱动的of_device_id.compatible完全一致即判定为匹配成功大小写敏感、字符串完全一致。data驱动私有数据作用匹配成功后将该字段的指针传递给驱动的probe函数用于向probe函数传递额外的硬件配置信息如寄存器偏移、硬件参数等避免在probe函数中硬编码。使用场景当一个驱动支持多款相似硬件设备且不同设备的配置存在差异时可通过data字段传递差异化配置。示例定义两款 UART 设备的私有配置通过data传递// 定义两款 UART 的私有配置结构体 struct uart_config { int baud_rate; // 默认波特率 int reg_offset; // 寄存器偏移量 }; // 具体配置实例 static const struct uart_config imx6ul_uart_cfg { .baud_rate 115200, .reg_offset 0x0, }; static const struct uart_config rk3399_uart_cfg { .baud_rate 9600, .reg_offset 0x10, }; // 定义 of_device_id 表关联 compatible 和私有配置 static const struct of_device_id uart_of_match[] { { .compatible fsl,imx6ul-uart, .data imx6ul_uart_cfg }, { .compatible rockchip,rk3399-uart, .data rk3399_uart_cfg }, { /* 哨兵节点标记数组结束必须存在 */ } };在probe函数中可通过of_match_device()函数获取该data指针static int uart_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct uart_config *cfg; // 获取匹配成功的 of_device_id 节点 match of_match_device(uart_of_match, pdev-dev); if (!match) return -ENODEV; // 获取私有配置数据 cfg match-data; printk(KERN_INFO 默认波特率%d寄存器偏移%d\n, cfg-baud_rate, cfg-reg_offset); // 后续硬件初始化逻辑... return 0; }声明匹配表向内核导出使用MODULE_DEVICE_TABLE(of, 匹配表名)宏将匹配表导出到内核模块的符号表中方便内核在加载驱动时识别该驱动支持的设备树节点。//向内核导出匹配表必须有否则内核无法识别 MODULE_DEVICE_TABLE(of, my_dev_of_match);宏MODULE_DEVICE_TABLE(of, my_drv_of_match)将匹配表导出到内核模块的符号表中内核可以通过该宏识别驱动支持的设备树兼容属性同时也方便模块工具如modinfo查看驱动支持的设备。将匹配表关联到platform_driver结构体of_match_table并不是一个新的结构体而是 **struct of_device_id类型的数组匹配表**用于存储一个驱动所支持的所有硬件设备的匹配规则多个of_device_id项。它是一个以空元素{}结尾的数组内核要求用于遍历结束判断。通常在驱动中定义为static const struct of_device_id xxx_of_match[]静态常量避免内存泄露。驱动需要将该匹配表赋值给对应驱动结构体的of_match_table成员如platform_driver中的of_match_table让内核能够找到并使用该匹配表。关键特性解耦硬件与驱动驱动无需硬编码硬件资源如 IO 地址、中断号只需通过设备树获取提升驱动的可移植性。支持多兼容值设备树节点的compatible可定义多个字符串驱动可匹配其中任意一个提升驱动的通用性如通用 UART 驱动匹配ns16550a。私有数据传递通过data字段向probe函数传递差异化配置支持一款驱动适配多款相似硬件。仅适用于设备树架构仅在启用了CONFIG_OF内核配置的架构ARM、ARM64、RISC-V中有效x86 架构通常不使用设备树因此不使用该结构体。关键要点必须包含哨兵节点of_device_id匹配表必须以{}结尾哨兵节点否则内核遍历匹配表时会发生越界访问导致系统崩溃。compatible字符串大小写敏感设备树中的compatible与驱动中的compatible必须完全一致包括大小写、标点符号否则匹配失败。必须导出匹配表MODULE_DEVICE_TABLE(of, ...)宏必须存在否则内核无法识别驱动支持的设备树节点导致匹配失败。data字段必须是常量数据data指向的数据必须是静态 / 全局常量如static const定义不能是栈上数据否则驱动加载后可能出现数据丢失。struct of_device_id是设备树驱动中驱动与设备节点匹配的核心结构体核心字段是compatible用于比对设备树节点的compatible属性。使用流程固定定义匹配表含哨兵节点→ 导出匹配表 → 关联到platform_driver结构体。核心优势是实现硬件信息与驱动代码解耦提升驱动的可移植性和通用性是现代嵌入式 Linux 驱动开发的必备知识点。关键注意事项哨兵节点不可少、compatible字符串大小写敏感、必须通过MODULE_DEVICE_TABLE导出匹配表。