第4章:平台驱动与设备树

核心定位:设备树是 Linux 驱动开发者必过的“第一关”。面试中60%以上的驱动问题最终都会回归到设备树解析、匹配机制与设备节点操作上。本章覆盖高频问题、结构化回答框架及大厂侧重点。
平台驱动设备树 · 面试回答框架 ① 拆解问题 硬件描述 vs 驱动匹配? ② 匹配流程 of_match_table → compatible ③ 数据获取 of_property_read_xxx 族 ④ 驱动注册 module_platform_driver() ⑤ 板级差异 overlay / 兼容性技巧

3个高频面试问答

面试问题:设备树中 compatible 属性的作用是什么?驱动是如何匹配的?

面试官考察点:是否理解设备树与驱动的绑定机制;能否讲清 of_match_table 与 compatible 的匹配逻辑;对多平台兼容性的处理经验。

回答框架:① 定义 compatible 为设备“身份证”,格式 "厂商,型号";② 简述匹配顺序:内核遍历 of_match_table → 优先精确匹配 → 退而使用 compatible 中第一个条目;③ 配合 platform_driver 注册函数说明整体流程。

简短示例回答:“compatible 是设备树中标识设备型号的字符串,格式'厂商,型号'。驱动通过 of_match_table 定义兼容列表,内核在设备树中查找匹配条目后即绑定 platform_device 与 platform_driver。我曾在移植驱动时仅修改 dts 文件即可适配不同 SoC,大大减少代码改动。”

可能追问:如果 compatible 包含多个值,内核优先匹配哪个?板级文件与 dtb 的关系是什么?如何调试设备树匹配失败?

避坑提醒:不能只说“compatible 用于匹配”,必须讲清“厂商前缀”与“通配符”的优先级,以及 of_match_table 中设置 .data 字段可传递自定义数据。避免只回答理论,要举一个实际匹配案例。

面试问题:设备树中如何获取一个字符串数组属性?用哪个 API?

面试官考察点:是否熟练掌握 of_property_read_xxx 家族函数;对 prop->length、of_find_property 等底层 API 的熟悉程度;处理属性不存在或格式错误的健壮性。

回答框架:① 明确需求:获取字符串数组(如驱动支持的设备列表);② 推荐 of_property_read_string_index() 遍历索引;③ 可先用 of_property_count_strings() 获取数量;④ 处理负值返回错误码。

简短示例回答:“使用 of_property_count_strings() 获取数量,再循环调用 of_property_read_string_index() 逐个读取。例如解析 interrupts-names 时需保证索引越界返回 -ENODATA。我习惯在 probe 入口统一解析所有 dts 属性并做完整性校验。”

可能追问:of_property_read_string 与 of_property_read_string_index 的区别?如何读取整型数组?为什么推荐在 probe 阶段一次性解析?

避坑提醒:不要直接使用 of_get_property() 获取字符串数组,那只能拿到裸指针,不会自动处理 null 结尾。一定要用带 read 字样的接口。同时注意设备树中字符串数组不需要逗号,用空格分隔。

面试问题:设备树中 reg 属性如何解析?地址和大小分别是多少?

面试官考察点:对#address-cells、#size-cells的理解;实际解析时地址与大小位数判断;多段reg(如多寄存器空间)的处理方式。

回答框架:① 说明 devicetree 中 reg 由 address-cells 和 size-cells 决定步长;② 使用 of_address_to_resource() 或 platform_get_resource() 直接获取 struct resource;③ 描述多区段 reg 的索引读取方法。

简短示例回答:“通常用 platform_get_resource(pdev, IORESOURCE_MEM, 0) 获取第一个寄存器区段。更灵活的方式是通过 of_address_to_resource(node, index, &res)。我曾遇到地址宽度配置错误导致驱动无法 probe,排查发现根节点#size-cells 被误设为2。”

可能追问:of_iomap 与 platform_get_resource + ioremap 的区别?如何读取以物理地址方式描述的 reg?

避坑提醒:不要硬编码地址或大小长度,必须动态读取父节点的#address-cells 与#size-cells。使用 platform_get_resource 比直接操作 of_ 函数更安全,因为它已经帮做了 cell 转换。另外注意 MMIO 资源要调用 devm_ioremap_resource()。

项目案例:基于设备树的嵌入式摄像头驱动适配

STAR 项目案例:嵌入式摄像头驱动适配 Situation 主控升级,需重写 Task 适配3款不同sensor Action 设备树+平台驱动 Result 驱动复用率90%+ 核心设计 通用dtsi + 板级dts 两级结构,通过 compatible 动态选择 sensor 驱动 驱动内用 of_match_data 传递寄存器配置表,减少 switch-case 分支 高频追问:dt overlay 如何做?多 sensor 共用 i2c 如何处理?
项目维度 内容
项目名称 嵌入式摄像头驱动平台化适配
业务背景 某物联网终端主控由 Cortex-A7 升级至 Cortex-A35,需同时支持 OV5640、GC2053、IMX335 三款 sensor,要求最小化 BSP 改动
规模指标 1 个平台驱动覆盖 3 款 sensor,2 种 I2C 接口方式,6 套板级 dts 文件,驱动代码行数减少 40%
技术栈 Linux 5.10 + V4L2 + platform_driver + device tree overlay + i2c-core
核心难点 ① sensor 寄存器配置差异大,如何通过 dts 数据驱动而非代码分支;② 运行时动态识别 sensor 并加载对应的初始化序列;③ 多个 sensor 共用同一 i2c 总线时的时序互斥
面试高频追问 1. 为什么用 of_match_data 而不直接在 code 里 if-else?
2. dts overlay 如何保证不会破坏原有总线枚举?
3. 如何调试 dts 解析失败问题?
可迁移回答话术 “我将 sensor 差异化参数(如 ID 寄存器地址、初始化序列长度)放入 of_match_data 结构体中,probe 时根据 compatible 指针直接获取。这样新增 sensor 只需添加 dts 节点和数据结构,不需要改动 probe 流程。”
大厂侧重点提示:
  • 字节/小米(消费电子):侧重设备树 overlay 热插拔场景,追问如何动态加载 dts 片段
  • 华为/中兴(通信设备):关注多板级兼容、大量 dtsi 复用设计,要求讲清 include 层级
  • 海康/大华(安防):摄像头 sensor 适配是必考,会深问 of_match_data 与 regulator/clk 的配合
避坑总提醒:面试中切忌只背诵 API 名称而不展示工程思维。设备树问题最佳回答路径是:问题→硬件差异→数据抽象→设备树配置→驱动解析→错误处理→测试验证。加入你对 of_ 函数族异常处理的理解(如 of_match_table 全为 NULL 场景)会极大加分。