内核添加dts后,device和device_driver的match匹配的变动:通过compatible属性进行匹配

内核添加dts后,device和device_driver的match匹配的变动:

先看platform总线:

/driver/base/platform.c文件:

static int platform_match(struct device *dev, struct device_driver *drv)

{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);

/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))//通过这个OpenFirmware的匹配方式(of就是OpenFirmware的缩写)
return 1;


/
<think>我们正在分析Linux内核驱动中用于设备树匹配的结构体数组定义: static const struct of_device_id my_driver_of_match[] = { { .compatible = "vendor,my-device", }, { /* sentinel */ } }; 这个结构体数组用于定义驱动所兼容的设备树节点。以下是详细解释: 1. **结构体类型**: `struct of_device_id` 是Linux内核中用于描述设备树兼容性匹配的结构体,定义在`<linux/mod_devicetable.h>`。其核心字段是`.compatible`(字符串),用于匹配设备树节点的`compatible`属性。 2. **数组内容**: - 第一个元素:`.compatible = "vendor,my-device"` - `"vendor,my-device"` 是驱动声明支持的设备标识符。 - 当设备树中某个节点的`compatible`属性包含这个字符串时,内核会将此驱动与该节点关联。 - 字符串格式惯例:`<制造商>,<型号>`,例如`"ti,omap3-uart"`。 - 第二个元素:`{ /* sentinel */ }`(哨兵元素) - 这是一个空结构体,作为数组结束标记。 - 其作用相当于终止符(类似字符串的`'\0'`),确保内核在遍历数组时能安全结束。 3. **工作原理**: 内核在加载驱动时,会遍历设备树的所有节点。对于每个节点,内核: - 读取节点的`compatible`属性(可能是多个字符串的列表) - 依次与`my_driver_of_match[]`数组中的每个`.compatible`字符串比较 - 若节点属性中的任意字符串与数组中某一项完全匹配,则触发驱动的`probe`函数 4. **匹配优先级**: 如果设备树节点有多个兼容字符串,如: compatible = "vendor,my-device-v2", "vendor,my-device", "generic-device"; 内核会按声明顺序尝试匹配,因此驱动数组中的顺序决定了匹配优先级(通常从最具体到最通用)。 5. **实际应用**: 此数组需赋值给`platform_driver.driver.of_match_table`(或`i2c_driver.driver.of_match_table`等): ```c static struct platform_driver my_driver = { .driver = { .name = "my-driver", .of_match_table = my_driver_of_match, // 注册匹配表 }, .probe = my_probe_function, ... }; ``` 6. **哨兵元素的必要性**: 内核源码中遍历匹配表的代码通常类似: ```c const struct of_device_id *match; for (match = table; match->compatible[0] != '\0'; match++) { // 检查匹配 } ``` 哨兵元素确保循环终止(因为其`.compatible`字段为`NULL`或空字符串)。 7. **扩展应用**: 可通过`MODULE_DEVICE_TABLE(of, my_driver_of_match)`将匹配表信息加入模块,以实现自动加载驱动。 8. **错误处理**: 如果设备树节点定义了该驱动不支持的属性或资源,`probe`函数应返回错误码(如`-EINVAL`),驱动加载失败。 9. **设备树节点示例**: ```dts // 设备树片段 my_device_node { compatible = "vendor,my-device"; // 匹配此字符串 reg = <0x10000000 0x1000>; // 寄存器地址长度 interrupts = <25>; // 中断号 }; ``` 10. **驱动兼容多个设备**: 数组可声明多个兼容设备: ```c static const struct of_device_id my_driver_of_match[] = { { .compatible = "vendor,device-v2" }, { .compatible = "vendor,device-v1" }, { } }; ``` 11. **相关内核API**: - `of_match_device(table, dev)`:用于在驱动`probe`函数中获取匹配的设备ID(返回`of_device_id`项指针)[^1] - `of_device_get_match_data(dev)`:获取匹配项中的`.data`字段(常用于传递设备变体参数) 12. **兼容性与ACPI**: 现代Linux内核同时支持设备树(DT)ACPI。对于x86平台,通常使用ACPI;而嵌入式平台(如ARM)使用设备树。驱动可通过同时支持两种机制实现跨平台。 13. **数据结构定义**: 内核中`of_device_id`的实际定义如下(简化): ```c struct of_device_id { char name[32]; // 设备名称(可选) char type[32]; // 设备类型(可选) char compatible[128]; // 兼容性字符串(核心) const void *data; // 私有数据指针 }; ``` 14. **匹配流程**: 以I2C总线为例(引用[2]),设备匹配函数会依次尝试: - 设备树匹配(`of_driver_match_device`) - ACPI匹配 - 传统ID表匹配 这体现了设备树匹配的优先性。 ### 总结 该代码段定义了一个驱动支持的设备树兼容性列表,是实现Linux设备树驱动匹配的关键数据结构。 </think>### 解释:`static const struct of_device_id my_driver_of_match[]` 这段代码是 Linux 设备驱动中用于**设备树(Device Tree)匹配**的关键数据结构,其作用是声明驱动程序支持的硬件设备标识符。以下是详细分解: #### 1. **数据结构定义** ```c static const struct of_device_id my_driver_of_match[] = { { .compatible = "vendor,my-device", }, { /* sentinel */ } }; ``` #### 2. **核心组件解析** | 组件 | 类型 | 用途 | |------|------|------| | `static` | 存储类 | 限制作用域为当前文件,避免全局命名冲突 | | `const` | 修饰符 | 确保数组内容在运行时不可修改 | | `struct of_device_id` | 内核结构体 | 设备树匹配的标准数据结构(定义于 `<linux/mod_devicetable.h>`) | | `.compatible` | 字符串字段 | **关键匹配标识**,格式:`<制造商>,<设备型号>` | | `{ /* sentinel */ }` | 空元素 | **哨兵终止符**,标记数组结束 | #### 3. **匹配机制详解** 当内核加载驱动时,会执行以下流程: 1. **遍历设备树节点** 扫描所有设备树节点中 `compatible` 属性(如:`compatible = "vendor,my-device";`) 2. **字符串匹配** 内核调用 `of_match_device()` 函数[^1],将设备树节点的 `compatible` 属性值与驱动声明的 `my_driver_of_match` 数组逐项比对 3. **触发驱动绑定** 若找到完全匹配的字符串(如 `"vendor,my-device"`), 则调用驱动的 `.probe()` 函数初始化硬件 4. **哨兵的作用** 空元素 `{ }` 确保循环终止,其等效于: ```c { .compatible = NULL } // 显式终止标记 ``` #### 4. **典型应用场景** 在平台驱动注册中链接匹配表: ```c static struct platform_driver my_driver = { .driver = { .name = "my-device-driver", .of_match_table = my_driver_of_match, // 关键绑定 }, .probe = my_probe_function, // 匹配成功时调用 }; ``` #### 5. **设备树节点示例** 匹配DTS (Device Tree Source) 节点: ```dts // 设备树片段 my_device: device@0 { compatible = "vendor,my-device"; // 匹配此字符串 reg = <0x10000000 0x1000>; // 硬件寄存器地址 interrupts = <15>; // 中断号 }; ``` #### 6. **设计要点** 1. **多设备支持**: 可声明多个兼容设备: ```c { .compatible = "vendor,device-v1" }, { .compatible = "vendor,device-v2" }, ``` 2. **优先级规则**: 内核按数组顺序匹配,优先使用第一个命中项 3. **数据传递**: 可通过 `.data` 字段传递设备私有数据: ```c { .compatible = "vendor,my-device", .data = &config_data }, ``` #### 7. **对比其他匹配机制** 在复合总线(如 I2C)中,设备树匹配优先级最高[^2]: ```c // 内核设备匹配流程(简化) if (of_driver_match_device(dev, drv)) return 1; // 设备树优先 if (acpi_driver_match_device(dev, drv)) return 1; // 其次ACPI if (driver->id_table) return ...; // 最后传统ID表 ``` ### 总结 此结构体数组建立了**驱动源代码**与**设备树硬件描述**之间的绑定关系,是实现硬件无关驱动的核心机制,使同一驱动能适配不同硬件变种。 --- ### 相关问题 1. 如何在驱动代码中获取设备树节点中定义的寄存器地址或中断号? 2. 如果设备树节点包含多个兼容性字符串(如 `compatible = "vendor-v2,v2-device", "vendor,v1-device";`),内核如何选择驱动? 3. 如何使用设备树为不同硬件变体传递定制化参数? 4. 当设备树匹配失败时,驱动开发人员应如何调试? 5. 设备树匹配与传统硬件探测(如 PCI ID 表)有何本质区别? [^1]: 引用 `of_match_device()` 的内核实现原型 [^2]: 参考 I2C 总线匹配优先级实现逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值