news 2026/10/19 5:31:06

struct of_device_id

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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: serial@12340000 { 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项)。

  1. 它是一个以空元素({})结尾的数组(内核要求,用于遍历结束判断)。
  2. 通常在驱动中定义为static const struct of_device_id xxx_of_match[](静态常量,避免内存泄露)。
  3. 驱动需要将该匹配表赋值给对应驱动结构体的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导出匹配表。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 20:54:26

智慧果园苹果病虫害检测系统(YOLO + DeepSeek 双模型 Web 管理系统) YOLO+Deepseek双模型web管理系统 YOLOV8结合deepseek大模型

深度学习框架YOLODeepseek双模型web管理系统&#xff08;带数据集完整代码&#xff09; 核心 ✔️ 多种常见病害精准识别&#xff0c;支持图片/视频/摄像头检测&#xff0c;识别效率拉满&#xff0c;并接入deepseek模型给出个性化防治方案 ✔️ 带数据管理功能&#xff1a;检…

作者头像 李华
网站建设 2026/10/19 0:30:31

SEW变频器MDX61B0300-503-04-00 8279667

孙13665068812SEW变频器MDX61B0300-503-04-00 8279667 技术详解型号说明&#xff1a;MDX61B&#xff1a;系列代号&#xff08;模块化设计变频器&#xff09;0300&#xff1a;额定功率3kW503&#xff1a;输入电压3相400V04&#xff1a;输出电流7A00&#xff1a;标准版本8279667&…

作者头像 李华
网站建设 2026/10/15 0:57:29

C++多文件编译:告别“一锅炖”,让代码管理更优雅

C多文件编译&#xff1a;告别“一锅炖”&#xff0c;让代码管理更优雅 在编程世界中&#xff0c;好的组织方式能让代码维护变得轻松愉快。今天&#xff0c;我们来聊聊C中的多文件编译——这是大型项目管理的必备技能&#xff01; 为什么要拆分代码文件&#xff1f; 想象一下&am…

作者头像 李华
网站建设 2026/10/12 18:09:00

[STM32L5] 【STM32L562E_DK开发板】--1.开箱与开发环境准备

收到活动寄过来的STM32L562E_DK开发板套件如下&#xff1a; 套件包含了两个组成部分&#xff1a;STM32L562E-DK Discovery Board和Fan-Out expansion board,前者作为主控板&#xff0c;后者作为拓展板。一.了解开发板开发板使用ST MCU STM32L562QEI6Q&#xff0c;片内资源512 K…

作者头像 李华
网站建设 2026/10/17 18:43:12

相机标定原理与概念(先搞懂再动手)

以下是一份完整的相机标定教程&#xff08;中文版&#xff09;&#xff0c;专为工业视觉&#xff08;机器视觉&#xff09;初学者和实际项目开发者设计。内容基于 Halcon、OpenCV 和 MVTec 官方文档 工业产线真实经验&#xff0c;涵盖原理、步骤、代码示例、常见问题及解决办法…

作者头像 李华