Heng30的博客
搜索 分类 关于 订阅

Linux驱动如何匹配设备?

2025-03-26

在Linux内核的struct platform_driver驱动结构中,id_tableof_match_table都用于驱动与设备的匹配,但它们的用途和工作方式有所不同。

设备树

// test.dst

/dts-v1/;

/ {
    #address-cells = <1>;
    #size-cells = <1>;

    // 模拟数据
    gpioe: gpio@50006000 {
        #gpio-cells = <0x2>;
        reg =  <0x50006000 0x4 0x50006014 0x4 0x50000a28 0x4>;
    };

    // 模拟数据
    gpiof: gpio@50008000 {
        gpio-controller;
        #gpio-cells = <0x2>;
        interrupt-controller;
        #interrupt-cells = <0x2>;

        reg =  <0x50008000 0x4 0x50008014 0x4 0x50008a28 0x4>;
        gpio-ranges = <0x55 0x0 0x50 0x10>;
        status = "okay";
    };

    // 该节点会被转换为`struct platform_device`设备对象
    myled: led {
        model = "This is LED";
        dev-type = "LED";

        // 参数:gpio对象引用,第几个引脚,是否使能
        led-gpios = <&gpioe 10 0>,<&gpiof 10 0>,<&gpioe 8 0>;

        // 与驱动匹配的关键设置
        compatible = "my_device_001";

        // 表示启用设备节点
        status = "okay";
    };

    mykey: key {
        model = "This is key";
        dev-type = "KEY";

        interrupt-parent = <&gpiof>;

        interrupts = <9 0>,<7 0>,<8 0>;

        key-gpios = <&gpiof 9 0>,<&gpiof 7 0>,<&gpiof 8 0>;

        // 与驱动匹配的关键设置
        compatible = "my_device_002";

        // 表示启用设备节点
        status = "okay";
    };
};

驱动代码

// simple.c

...

#define PLATFORM_DEVICE_BASENAME "my_device"
#define PLATFORM_DEVICE_NAME_1 "my_device_001"
#define PLATFORM_DEVICE_NAME_2 "my_device_002"

#define PLATFORM_DEVICE_ALIAS_NAME_1 "myled"
#define PLATFORM_DEVICE_ALIAS_NAME_2 "mykey"

...

// 会与insmod安装的platform_device进行匹配
struct platform_device_id id_table_match[] = {
    // 名称要在20个字节以内
    [0] = {PLATFORM_DEVICE_ALIAS_NAME_1, 1},
    [1] = {PLATFORM_DEVICE_ALIAS_NAME_2, 2},
    [2] = {}, // 空元素代表结束
};

// 会与设备树安装的platform_device进行匹配
struct of_device_id of_node_match_table[] = {
    [0] = {.compatible = PLATFORM_DEVICE_NAME_1},
    [1] = {.compatible = PLATFORM_DEVICE_NAME_2},
    [2] = {}, // 空元素代表结束
};

struct platform_driver key_driver = {
    .probe = _probe,
    .remove = _remove,

    // 通过id_table匹配, 实现一个驱动对多个设备
    .driver =
        {
            .name = PLATFORM_DEVICE_BASENAME,

            // 设备树的匹配方式
            .of_match_table = of_node_match_table,
        },
    .id_table = id_table_match,
};

static int __init key_driver_init(void) {
    int ret = platform_driver_register(&key_driver);
    if (ret < 0) {
        pr_err("key_driver_register failed\n");
        return -1;
    }
    return 0;
}

...

主要区别

  • id_table

    • 匹配机制:设备ID(.modalias)
    • 适用系统:传统板级文件(非设备树)
    • 数据结构:platform_device_id
    • 典型用途:旧版内核、非设备树系统
  • of_match_table

    • 匹配机制:设备树compatible字符串
    • 适用系统:设备树(DT)或 ACPI 系统
    • 数据结构:of_device_id
    • 典型用途:现代内核(支持设备树)

总结

  • 如果同时提供id_tableof_match_table,内核会优先检查设备树(of_match_table)。

  • 如果没有匹配的设备树节点,则回退到id_table匹配。

  • 这种设计确保了驱动在设备树和非设备树系统 中均能正常工作。