Linux总线设备驱动模型与Platform驱动开发详解

Linux总线设备驱动模型与Platform驱动开发详解 Linux总线设备驱动模型深度解析1. 平台设备驱动概述1.1 Linux驱动设计思想Linux内核开发遵循三个核心设计原则分层设计将功能划分为不同层次每层只关注特定功能分离思想将硬件相关与硬件无关代码分离抽象方法通过统一接口屏蔽底层硬件差异这种设计模式显著提高了代码的低耦合性模块间依赖关系简化高独立性各模块可单独开发和测试强重用性通用代码可跨平台复用1.2 传统驱动模型的局限性在早期Linux驱动开发中存在以下典型问题// 传统驱动写法示例 static int demo_probe(struct pci_dev *pdev, const struct pci_device_id *id) { // 硬件初始化代码 // 业务逻辑代码 // 资源管理代码 return 0; }这种模式导致硬件相关代码与业务逻辑紧耦合相同外设的驱动无法在不同平台复用驱动代码中存在大量重复实现2. 总线设备驱动模型架构2.1 基本组成要素Linux总线设备驱动模型包含三个核心组件组件类型描述头文件bus_type总线类型抽象linux/device.hdevice_driver驱动抽象linux/device.hdevice设备抽象linux/device.h2.2 虚拟总线解决方案对于SoC中无物理总线的外设Linux引入platform虚拟总线机制// drivers/base/platform.c struct bus_type platform_bus_type { .name platform, .match platform_match, .uevent platform_uevent, .pm platform_dev_pm_ops, };关键设计特点提供统一的设备枚举机制实现驱动与设备的动态匹配保持与非平台设备相同的API接口3. Platform驱动实现细节3.1 驱动结构体定义// include/linux/platform_device.h struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; };结构体成员说明probe设备初始化入口remove设备卸载处理driver继承自基类device_driverid_table设备匹配表3.2 驱动注册流程典型驱动注册示例static struct platform_driver my_driver { .driver { .name my-device, .owner THIS_MODULE, }, .probe my_probe, .remove my_remove, }; module_platform_driver(my_driver);注册过程分析通过platform_driver_register()注册驱动内核将驱动加入platform总线驱动列表总线执行匹配流程寻找对应设备4. Platform设备描述方法4.1 设备结构体定义// include/linux/platform_device.h struct platform_device { const char *name; int id; struct device dev; u32 num_resources; struct resource *resource; };关键字段说明name设备名称用于匹配驱动resource设备资源描述IRQ、MEM等dev继承自基类device4.2 资源描述方法// include/linux/ioport.h struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; };资源类型标志IORESOURCE_MEM内存区域资源IORESOURCE_IRQ中断资源IORESOURCE_DMADMA通道5. 驱动设备匹配机制5.1 匹配函数实现// drivers/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); /* 1. 尝试设备树匹配 */ if (of_driver_match_device(dev, drv)) return 1; /* 2. 尝试ACPI匹配 */ if (acpi_driver_match_device(dev, drv)) return 1; /* 3. 尝试id_table匹配 */ if (pdrv-id_table) return platform_match_id(pdrv-id_table, pdev) ! NULL; /* 4. 名称直接匹配 */ return (strcmp(pdev-name, drv-name) 0); }匹配优先级设备树兼容性匹配最高优先级ACPI ID匹配驱动id_table匹配名称字符串匹配5.2 匹配过程示例以UART设备为例的匹配流程设备注册时提供名称serial8250驱动注册时声明支持名称serial8250总线检测到名称匹配后调用驱动probe函数驱动完成设备初始化和功能注册6. 开发实践建议6.1 驱动开发模板static int sample_probe(struct platform_device *pdev) { // 1. 获取设备资源 struct resource *res platform_get_resource(pdev, IORESOURCE_MEM, 0); // 2. 映射寄存器地址 void __iomem *base devm_ioremap_resource(pdev-dev, res); // 3. 申请中断 int irq platform_get_irq(pdev, 0); devm_request_irq(pdev-dev, irq, sample_isr, 0, sample, NULL); // 4. 注册字符设备 misc_register(sample_miscdev); return 0; } static struct platform_driver sample_driver { .driver { .name sample-device, .owner THIS_MODULE, }, .probe sample_probe, .remove sample_remove, };6.2 常见问题排查匹配失败检查设备/驱动名称是否一致确认id_table或设备树配置正确使用ls /sys/bus/platform/devices查看注册设备资源获取失败检查resource数组索引是否正确确认设备树reg属性设置使用cat /proc/iomem验证资源地址probe未执行检查驱动是否成功注册确认模块依赖关系查看内核日志dmesg | grep probe