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

本章定位:Platform驱动是Linux驱动最常用的框架,结合设备树实现硬件描述与驱动解耦。面试官重点考察你对驱动模型的理解深度、设备树匹配原理、of API操作熟练度,以及在实际项目中处理资源、中断、DMA的能力。

建议复习路径:设备树语法 → of_match_table结构 → platform_driver注册流程 → probe中of API调用 → 实际项目踩坑点。以下通过3个高频问答和1个真实项目模板,系统梳理面试常考内容。

Platform驱动+设备树 回答框架 设备树匹配 compatible属性 platform_driver 注册与卸载 probe函数 获取私有数据 of API调用 资源/中断/属性 驱动绑定与移除 remove/电源管理 对应节点 ---

面试问答卡片

Q1:请简述Linux platform驱动模型的工作原理,以及设备树如何与platform驱动建立联系?

考察点:驱动框架整体理解、设备树匹配流程、probe触发时机

回答框架:① 先说明platform总线将设备和驱动分离,通过name/of_match_table匹配;② 设备树节点会被内核解析为platform_device并注册到平台总线;③ 驱动注册时遍历总线,匹配成功则调用probe。

示例回答:Platform驱动是一种虚拟总线驱动,用于无真实总线的设备。设备树中每个匹配compatible属性的节点会被内核创建为platform_device。驱动通过.of_match_table定义兼容数组,注册platform_driver后,内核在设备树上查找匹配并调用probe。例如i2c控制器驱动常用pdev->name匹配设备。

可能追问:● 如果设备树有多个匹配项,驱动如何处理?● probe失败后资源如何释放?● platform_device如何手动注册?

避坑提醒:不要混淆platform_driver和device_driver;强调of_match_table以compatible为匹配优先级,避免仅依赖name。
Q2:设备树中如何定义一个I2C控制器节点?驱动中如何通过of_match_table和设备树匹配?请给出具体代码结构。

考察点:设备树节点编写、of_match_table宏、MODULE_DEVICE_TABLE

回答框架:① 设备树节点定义compatible、reg、interrupts等;② 驱动中定义of_device_id数组并指定compatible字符串;③ 使用MODULE_DEVICE_TABLE(of, xxx_of_match)导出;④ probe中即可通过device_of_node获取节点。

示例回答:设备树节点形如i2c0: i2c@ff000000 { compatible = "vendor,i2c-ctrl"; reg = <0xff000000 0x1000>; interrupts = ; };驱动中static const struct of_device_id i2c_of_match[] = { { .compatible = "vendor,i2c-ctrl" }, {} }; MODULE_DEVICE_TABLE(of, i2c_of_match); 注册platform_driver时赋值.of_match_table。

可能追问:● 如果多个驱动声明相同的compatible字符串,会发生什么?● of_match_table可以同时兼容多个不同版本吗?

避坑提醒:compatible的命名规范推荐"厂商,设备名",避免使用下划线;of_match_table必须以空结构体结尾。
Q3:在probe函数中,如何使用of API获取设备树中的寄存器地址、中断号和自定义属性?请列举常用API及注意事项。

考察点:of_address_to_resource、of_iomap、of_irq_get、of_property_read_xxx等实际使用

回答框架:① 先通过of_node = pdev->dev.of_node拿到节点;② 使用of_address_to_resource或platform_get_resource获取物理地址;③ 调用of_iomap映射;④ 用of_irq_get获取中断号;⑤ 自定义属性用of_property_read_u32/of_property_read_string。

示例回答:struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); irq = platform_get_irq(pdev, 0); of_property_read_u32(np, "clock-frequency", &freq); 注意资源计数从0开始,错误处理用IS_ERR。

可能追问:● of_iomap和devm_ioremap_resource的区别?● 设备树属性节点包含多个值如何解析?● 如何读取64位地址?

避坑提醒:优先使用devm_版本自动管理生命周期;手动of_iomap需要在remove中对应的iounmap,否则内存泄漏;检查np是否为空。
---

项目案例:智能音箱语音信号预处理加速器驱动

项目名称智能音箱语音信号预处理加速器驱动(基于Xilinx Zynq FPGA)
业务背景为智能音箱提供硬件FFT/滤波加速,降低CPU负载,实现低延迟语音唤醒。
规模指标驱动代码约1500行,支持10路音频通道、4组DMA,延迟低于10ms,驱动已在量产版本中使用。
技术栈Linux 4.14, Platform驱动, 设备树(FPGA IP核描述), DMAC, 中断, 用户态ioctl接口
核心难点1. 多个IP核共用同一地址空间,需通过设备树reserved-memory管理;2. 中断与DMA协同,需处理竞态;3. 驱动与前级I2S驱动数据交互。
面试高频追问● 设备树中如何描述多个IP核的地址空间?● 你的驱动如何处理DMA中断与CPU访问的同步?● 为什么选择platform驱动而不是直接字符设备?● 调试驱动时你用了哪些工具?
可迁移回答话术“我们使用设备树的ranges属性映射多个IP核到CPU地址空间,驱动通过of API解析后统一管理。中断处理采用workqueue推迟耗时操作,DMA使用dmaengine框架。选platform驱动是因为芯片没有真实总线,且可以通过设备树描述多实例。”
面试加分点:能主动提到设备树中的interrupt-names配合platform_get_irq_byname获取有语义的中断;使用of_property_read_bool检查设备树节点是否存在可选属性;提出将驱动拆分为核心层和实例层(如使用of_match_ptr宏)的设计模式。