Skip to content

Issue #51: Beep 的 compatible 字符串没有匹配上,但仍然能驱动蜂鸣器

问题描述

驱动的 compatible 字符串与设备树不一致,但蜂鸣器仍能正常工作。

  • 驱动代码:compatible = "my,beep"
  • 设备树:compatible = "imxaes_beep"
  • 驱动成功加载并控制 GPIO

结论

驱动不是靠 compatible 匹配上的,而是靠 platform bus 的最后兜底规则:platform_device.name == platform_driver.driver.name

源码分析

Platform 驱动匹配顺序

Linux 主线内核 drivers/base/platform.c

c
// 第 1376-1399 行
static int platform_match(struct device *dev, const struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    /* 1. 当设置了 driver_override 时,只匹配指定驱动 */
    if (pdev->driver_override)
        return !strcmp(pdev->driver_override, drv->name);

    /* 2. 首先尝试 OF(设备树)风格匹配 */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* 3. 然后尝试 ACPI 风格匹配 */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    /* 4. 尝试匹配 id_table */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

    /* 5. 兜底:驱动名称匹配 ⬅️ Beep 驱动走的是这里 */
    return (strcmp(pdev->name, drv->name) == 0);
}

匹配流程图

                    ┌─────────────────────────┐
                    │  platform_match()      │
                    └───────────┬─────────────┘


                    ┌─────────────────────────┐
                    │ driver_override?       │
                    └───────────┬─────────────┘
                                │ No

                    ┌─────────────────────────┐
                    │ OF 匹配                 │
                    │ (of_match_table)        │
                    └───────────┬─────────────┘
                                │ 失败
                                │ "my,beep" ≠ "imxaes_beep"

                    ┌─────────────────────────┐
                    │ ACPI 匹配               │
                    └───────────┬─────────────┘
                                │ 失败

                    ┌─────────────────────────┐
                    │ id_table 匹配           │
                    └───────────┬─────────────┘
                                │ 失败

                    ┌─────────────────────────┐
                    │ ⭐ 兜底:name 匹配      │
                    │ strcmp(pdev->name,      │
                    │        drv->name) == 0  │
                    └───────────┬─────────────┘


                    "beep" == "beep" ✅ 匹配成功!

实际发生了什么

Beep 驱动案例:

项目
设备树节点名beep
设备树 compatibleimxaes_beep
驱动 .driver.namebeep
驱动 of_match_tablemy,beep
设备树: beep { compatible = "imxaes_beep"; ... }

内核解析: platform_device.name = "beep"

驱动注册: platform_driver.driver.name = "beep"

OF 匹配: "my,beep" ≠ "imxaes_beep" ❌

兜底匹配: "beep" == "beep" ✅

probe() 成功调用!

为什么 GPIO 还能正常工作?

即使不是通过 compatible 匹配,设备树节点仍然挂在 pdev->dev.of_node 上:

c
// beep_driver.c probe 函数
dev->gpio = devm_gpiod_get(&pdev->dev, "beep", GPIOD_OUT_HIGH);
//                           ^^^^^^^^^^^^
//                           仍能访问设备树节点

驱动可以通过 pdev->dev.of_node 访问完整的设备树节点,包括 beep-gpio 属性。

验证方法

bash
# 1. 查看 platform device
ls /sys/bus/platform/devices/
# 输出包含: beep

# 2. 查看 modalias(显示 OF compatible)
cat /sys/bus/platform/devices/beep/modalias
# 输出: of:NbeepTimxaes_beepCimxaes_beep
#       ^^^^节点名  ^^^^^^^^^^^^compatible

# 3. 查看绑定关系
readlink /sys/bus/platform/devices/beep/driver
# 输出: ../../../bus/platform/drivers/beep

# 4. 查看驱动模块信息
strings /lib/modules/beep_driver.ko | grep compatible
# 只有: my,beep(没有 imxaes_beep)

建议

修正驱动和设备树,使用标准 compatible 格式:

c
// beep_driver.c
static const struct of_device_id beep_of_match[] = {
    { .compatible = "imxaes,beep" },
    { /* sentinel */ }
};
c
// imx6ull-aes-beep.dts
beep {
    compatible = "imxaes,beep";
    beep-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;  // 标准复数形式
};

为什么不应该依赖 name 兜底匹配:

问题说明
模块无法自动加载modalias 基于 compatible,不会触发正确的模块加载
代码可读性差compatible 不匹配会让维护者困惑
可能冲突多个驱动使用相同 name 时会冲突

开发板验证结果:

bash
# 1. 模块中的 compatible 已更新
~ # strings /lib/modules/beep_driver.ko | grep -E "my,beep|imxaes,beep|imxaes_beep"
imxaes,beep
alias=of:N*T*Cimxaes,beepC*
alias=of:N*T*Cimxaes,beep

# 2. 设备树中的 compatible(已同步更新)
~ # cat /sys/firmware/devicetree/base/beep/compatible
imxaes,beep

# 3. 驱动加载成功
~ # insmod /lib/modules/beep_driver.ko
[  186.343069] beep_driver: loading out-of-tree module taints kernel.
[  186.345357] beep beep: Beep driver loaded successfully

# 4. 应用程序控制蜂鸣器正常(./beep 来自 [driver/application/beep](../../driver/application/beep/))
~ # ./beep 0
Input: 0 -> Beep turned ON
[  194.780173] beep: device opened
[  194.780241] beep: ON (GPIO set to LOW)
[  194.780756] beep: device released

~ # ./beep 1
Input: 1 -> Beep turned OFF
[  196.957548] beep: device opened
[  196.957620] beep: OFF (GPIO set to HIGH)
[  196.958057] beep: device released

现在驱动通过 OF compatible 匹配工作,而非 name 兜底匹配。

相关链接

Built with VitePress