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 |
| 设备树 compatible | imxaes_beep |
| 驱动 .driver.name | beep |
| 驱动 of_match_table | my,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 兜底匹配。