行业资讯
📅 2026/7/17 20:11:49
Linux平台设备驱动开发详解与实践
1. Linux平台设备驱动开发基础在嵌入式Linux开发中平台设备驱动(Platform Device Driver)是一种重要的驱动模型它专门用于管理那些没有物理总线的简单设备。这类设备通常包括LED、按键、蜂鸣器等常见外设。platform_driver_register()和platform_device_register()是Linux内核提供的两个核心API用于实现平台设备和驱动的注册与管理。1.1 平台设备与驱动的基本概念平台总线(Platform Bus)是Linux内核中的一种虚拟总线用于连接那些没有专用物理总线的设备。这种设计使得简单外设也能遵循Linux设备模型实现设备与驱动的分离。平台设备(Platform Device)通过platform_device结构体描述主要包含设备名称(name)设备ID(id)资源信息(resource)私有数据(platform_data)平台驱动(Platform Driver)通过platform_driver结构体描述核心成员包括probe/remove回调函数驱动名称(driver.name)兼容设备表(id_table)2. 平台设备注册详解2.1 platform_device结构体解析struct platform_device { const char *name; int id; struct device dev; u32 num_resources; struct resource *resource; const struct platform_device_id *id_entry; };关键字段说明name设备名称用于总线匹配id设备实例编号dev内嵌的device结构体resource设备资源数组num_resources资源数量2.2 设备资源定义设备资源通过struct resource描述struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; };常用资源类型标志IORESOURCE_MEM内存映射资源IORESOURCE_IOI/O端口资源IORESOURCE_IRQ中断资源2.3 平台设备注册流程定义设备资源static struct resource pdev_res[] { [0] DEFINE_RES_MEM(0xFDD60000, 0x10), [1] DEFINE_RES_IRQ(32), };初始化platform_device结构体static struct platform_device pdev { .name sample-device, .id 0, .num_resources ARRAY_SIZE(pdev_res), .resource pdev_res, };注册设备int ret platform_device_register(pdev); if (ret) { pr_err(Failed to register platform device\n); return ret; }3. 平台驱动开发实践3.1 platform_driver结构体详解struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; };关键操作函数probe设备匹配成功后调用remove设备移除时调用3.2 驱动注册实现定义id_tablestatic const struct platform_device_id sample_ids[] { { sample-device, 0 }, { } }; MODULE_DEVICE_TABLE(platform, sample_ids);实现probe函数static int sample_probe(struct platform_device *pdev) { struct resource *mem; void __iomem *regs; mem platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(pdev-dev, No memory resource\n); return -ENODEV; } regs devm_ioremap_resource(pdev-dev, mem); if (IS_ERR(regs)) return PTR_ERR(regs); /* 设备初始化代码 */ return 0; }注册平台驱动static struct platform_driver sample_driver { .driver { .name sample-driver, }, .probe sample_probe, .remove sample_remove, .id_table sample_ids, }; module_platform_driver(sample_driver);4. 设备与驱动的匹配机制4.1 匹配优先级平台总线匹配设备和驱动时按照以下优先级顺序设备树匹配(of_driver_match_device)ACPI匹配(acpi_driver_match_device)id_table匹配名称匹配(strcmp)4.2 匹配函数实现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); /* 设备树匹配 */ if (of_driver_match_device(dev, drv)) return 1; /* ACPI匹配 */ if (acpi_driver_match_device(dev, drv)) return 1; /* id_table匹配 */ if (pdrv-id_table) return platform_match_id(pdrv-id_table, pdev) ! NULL; /* 名称匹配 */ return (strcmp(pdev-name, drv-name) 0); }5. 实战案例LED平台驱动5.1 设备端实现/* 定义GPIO资源 */ static struct resource led_res[] { [0] DEFINE_RES_MEM(0xFDD60000, 0x10), [1] DEFINE_RES_MEM(0xFDD60004, 0x10), }; /* 定义私有数据 */ static unsigned int led_pin 7; /* 定义平台设备 */ static struct platform_device led_pdev { .name platform-led, .id 0, .num_resources ARRAY_SIZE(led_res), .resource led_res, .dev { .platform_data led_pin, }, };5.2 驱动端实现struct led_platform_data { unsigned int pin; }; static int led_probe(struct platform_device *pdev) { struct led_platform_data *pdata dev_get_platdata(pdev-dev); struct resource *mem; void __iomem *regs; /* 获取资源 */ mem platform_get_resource(pdev, IORESOURCE_MEM, 0); regs devm_ioremap_resource(pdev-dev, mem); /* 初始化GPIO */ iowrite32(ioread32(regs) | (1 pdata-pin), regs); /* 注册字符设备 */ /* ... */ return 0; } static struct platform_driver led_driver { .driver { .name platform-led, }, .probe led_probe, /* ... */ };6. 常见问题与调试技巧6.1 匹配失败排查检查/sys/bus/platform/devices和/sys/bus/platform/drivers目录确认设备和驱动的name字段一致检查probe函数是否被调用6.2 资源获取失败处理res platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(pdev-dev, Failed to get MEM resource\n); return -ENXIO; } irq platform_get_irq(pdev, 0); if (irq 0) { dev_err(pdev-dev, Failed to get IRQ\n); return irq; }6.3 内存映射注意事项使用devm_ioremap_resource自动管理资源检查返回的指针是否有效注意资源的大小和对齐7. 现代Linux驱动开发实践7.1 设备树与平台设备的结合sample_device: sample-devicefdd60000 { compatible vendor,sample-device; reg 0xfdd60000 0x1000; interrupts 0 32 4; led-pin 7; };7.2 使用devm_系列函数管理资源/* 自动释放的资源管理 */ regs devm_ioremap_resource(pdev-dev, res); clk devm_clk_get(pdev-dev, NULL); irq devm_request_irq(pdev-dev, irq_num, handler, flags, name, dev);7.3 平台驱动的最佳实践充分利用设备树传递配置信息使用devres机制管理资源实现适当的电源管理回调提供sysfs接口进行调试和控制在实际开发中平台设备驱动模型为简单外设提供了标准化的管理方式使得驱动代码可以更好地与硬件信息分离提高了代码的可维护性和可移植性。通过合理使用platform_device_register()和platform_driver_register()开发者可以构建出符合Linux设备模型的优质驱动。