重要结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct platform_device { const char *name; int id; bool id_auto; struct device dev ; u32 num_resources; struct resource *resource ; const struct platform_device_id *id_entry ; char *driver_override; struct mfd_cell *mfd_cell ; struct pdev_archdata archdata ; };
1 2 3 4 5 6 7 8 9 10 11 struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver ; const struct platform_device_id *id_table ; bool prevent_deferred_probe; };
先讨论platform_match这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 (pdev->driver_override) return !strcmp (pdev->driver_override, drv->name); if (of_driver_match_device(dev, drv)) return 1 ; if (acpi_driver_match_device(dev, drv)) return 1 ; if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL ; return (strcmp (pdev->name, drv->name) == 0 ); }
函数按照以下顺序进行匹配,一旦某个匹配成功就返回:
driver_override(强制绑定)
设备树匹配
ACPI匹配
ID表匹配
名称匹配(兜底方案)
详细分析 数据类型转化: 1 2 struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);
将通用的device和device_driver结构转换为platform特定的结构体,方便访问platform特有的字段。
to_platform_device用于通过struct device类型的dev指针,得到包含它的struct platform_device类型的指针。
to_platform_driver用于通过struct device_driver类型的drv指针,得到包含它的struct platform_driver类型的指针。
这两个宏定义由contain_of宏定义实现
1 2 #define to_platform_device(x) container_of((x), struct platform_device, dev) #define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver))
driver_override匹配 1 2 if (pdev->driver_override) return !strcmp (pdev->driver_override, drv->name);
检查设备是否指定了强制绑定的驱动名称
如果指定,则只与该名称完全匹配的驱动绑定
这通常用于调试或强制特定设备使用特定驱动
设备树匹配 1 2 if (of_driver_match_device(dev,drv)) return 1 ;
调用设备树匹配函数
通过设备节点的”compatible”属性与驱动的of_match_table进行匹配
这是现代嵌入式系统中最常用的匹配方式
ACPI匹配 1 2 if (acpi_driver_match_device(dev, drv)) return 1 ;
在ACPI系统中,通过ACPI_hid和驱动进行匹配
主要用于x86系统
ID表匹配 1 2 if (pdrv->id_table) return platform_match_id(pdrv->id_table,pdev) != NULL ;
使用驱动中定义的id_table与设备名称进行匹配
遍历驱动的ID表,查找与设备名称匹配的项
名称匹配 1 return (strcmp (pdev->name,drv->name) == 0 )
简单地比较设备名称和驱动名称是否相同
这是最基本的匹配方式
区分设备树匹配和ID表匹配 1. of_driver_match_device
用于**设备树(Device Tree)**匹配机制
通过设备树中的compatible属性进行匹配
工作原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 my_device: my-device@10000000 { compatible = "vendor,device-name" , "generic-name" ; reg = <0x10000000 0x1000 >; }; static const struct of_device_id my_of_match [] = { { .compatible = "vendor,device-name" , .data = &my_data }, { .compatible = "generic-name" , .data = &generic_data }, { } }; static struct platform_driver my_driver = { .driver = { .name = "my-driver" , .of_match_table = my_of_match, }, .probe = my_probe, };
匹配过程
遍历驱动的of_match_table数组
将设备树节点的compatible属性与表中条目逐一比较
找到第一个匹配项即成功
用于传统platform设备ID表 匹配机制
通过设备和驱动的名称进行匹配
工作原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 c static const struct platform_device_id my_id_table [] = { { "my-device-name" , .driver_data = MY_DATA_1 }, { "my-old-device" , .driver_data = MY_DATA_2 }, { } }; static struct platform_driver my_driver = { .driver = { .name = "my-driver" , }, .id_table = my_id_table, .probe = my_probe, }; static struct platform_device my_device = { .name = "my-device-name" , .id = -1 , };
匹配过程
遍历驱动的id_table数组
将设备的name字段与表中条目的name字段比较
找到匹配项即成功,并将匹配的表项保存到设备的id_entry字段
设备树匹配和ID表匹配不同点
维度
of_driver_match_device(设备树匹配)
platform_match_id(ID 表匹配)
匹配依据
基于设备树(Device Tree)中的 compatible 属性。
基于驱动中定义的 id_table(struct platform_device_id 数组)。
适用场景
主要用于使用设备树的系统 (现代嵌入式系统主流,如 ARM、RISC-V 平台)。
主要用于不使用设备树的系统 (如部分 x86 平台、老的嵌入式系统),或作为设备树匹配的补充。
实现逻辑
1. 设备在设备树中通过 compatible 属性声明自己的「兼容标识」(如 vendor,chip-name); 2. 驱动通过 of_match_table 成员声明自己支持的 compatible 列表; 3. 函数比较设备的 compatible 与驱动的 of_match_table,若有一致则匹配成功。
1. 驱动通过 id_table 定义支持的设备名称列表(name 字段)和设备 ID(id 字段); 2. 设备通过 name 和 id 成员标识自己; 3. 函数遍历 id_table,若设备的 name 和 id 与表中某条目一致,则匹配成功。
灵活性
更高。compatible 属性可包含多个值(如 vendor,chip-v2、vendor,chip-v1),支持「向下兼容」(驱动可匹配多个版本的设备)。
较低。依赖精确的名称和 ID 匹配,通常只能匹配固定名称或 ID 的设备。
在匹配链中的优先级
较高(在 platform_match 中先于 platform_match_id 执行)。
较低(在设备树、ACPI 匹配失败后才执行)。
3. 实例 文件地址:drivers\gpio\gpio-mxc.c
1 2 3 4 5 6 7 static const struct of_device_id mxc_gpio_dt_ids [] = { { .compatible = "fsl,imx1-gpio" , .data = &mxc_gpio_devtype[IMX1_GPIO], }, { .compatible = "fsl,imx21-gpio" , .data = &mxc_gpio_devtype[IMX21_GPIO], }, { .compatible = "fsl,imx31-gpio" , .data = &mxc_gpio_devtype[IMX31_GPIO], }, { .compatible = "fsl,imx35-gpio" , .data = &mxc_gpio_devtype[IMX35_GPIO], }, { } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static const struct platform_device_id mxc_gpio_devtype [] = { { .name = "imx1-gpio" , .driver_data = IMX1_GPIO, }, { .name = "imx21-gpio" , .driver_data = IMX21_GPIO, }, { .name = "imx31-gpio" , .driver_data = IMX31_GPIO, }, { .name = "imx35-gpio" , .driver_data = IMX35_GPIO, }, { } };
1 2 3 4 5 6 7 8 9 static struct platform_driver mxc_gpio_driver = { .driver = { .name = "gpio-mxc" , .pm = &mxc_gpio_dev_pm_ops, .of_match_table = mxc_gpio_dt_ids, }, .probe = mxc_gpio_probe, .id_table = mxc_gpio_devtype, };