用户通用驱动spidev.c与设备匹配问题
发现了一个奇怪的现象:
- 匹配成功了:驱动确实跑起来了,
probe函数被调用了。 - 代码却说不匹配:
spidev_dt_ids里明明没有"spidev",而且probe函数里还打印了“Buggy DT”警告。
设备树定义:
&ecspi1{pinctrl-names="default";pinctrl-0=<&pinctrl_ecspi1>;fsl,spi-num-chipselects=<2>;cs-gpios=<&gpio426GPIO_ACTIVE_LOW>,<&gpio424GPIO_ACTIVE_LOW>;status="okay";dac: dac{compatible="spidev";reg=<0>;spi-max-frequency=<2000000>;};};spi_driver定义:
staticstructspi_driverspidev_spi_driver={.driver={.name="spidev",.of_match_table=of_match_ptr(spidev_dt_ids),.acpi_match_table=ACPI_PTR(spidev_acpi_ids),},.probe=spidev_probe,.remove=spidev_remove,};转入of_match_table的设备列表:
staticconststructof_device_idspidev_dt_ids={{.compatible="rohm,dh2228fv"},{.compatible="lineartechnology,ltc2488"},{},};MODULE_DEVICE_TABLE(of,spidev_dt_ids);发现spidev_dt_ids中并没有定义{ .compatible = "spidev" },,但最后还是能匹配成功。
先去看spi总线类型结构体:
structbus_typespi_bus_type={.name="spi",.dev_groups=spi_dev_groups,.match=spi_match_device,.uevent=spi_uevent,};找到match函数
spi_match_device:staticintspi_match_device(structdevice*dev,structdevice_driver*drv){conststructspi_device*spi=to_spi_device(dev);conststructspi_driver*sdrv=to_spi_driver(drv);/* Attempt an OF style match */if(of_driver_match_device(dev,drv))return1;/* Then try ACPI */if(acpi_driver_match_device(dev,drv))return1;if(sdrv->id_table)return!!spi_match_id(sdrv->id_table,spi);returnstrcmp(spi->modalias,drv->name)==0;}- 第 1 关:OF (设备树) 匹配
- 代码:
of_driver_match_device(dev, drv) - 动作:内核拿着你的
compatible = "spidev"去spidev_dt_ids列表里找。 - 结果:失败。列表里只有
"rohm,dh2228fv"和"lineartechnology,ltc2488"。
- 代码:
- 第 2 关:ACPI 匹配
- 动作:x86 架构用的。
- 结果:失败。
- 第 3 关:ID Table 匹配
- 动作:检查传统 ID 表。
- 结果:失败。
- 第 4 关:名称 (Name) 匹配(在这里匹配成功)
- 代码:
return strcmp(spi->modalias, drv->name) == 0; - 核心逻辑:
- 驱动名字
drv->name是"spidev"。 - 内核 SPI 核心层在解析设备树时,发现
compatible = "spidev",会将其设为该设备的modalias。 strcmp("spidev", "spidev")相等。
- 驱动名字
- 结果:匹配成功
- 代码:
- 第 1 关:OF (设备树) 匹配
为什么能匹配?
靠的是 spi_match_device 最后的字符串名称硬匹配机制(Fallback)。
为什么有警告?
[root@100ask:~]# dmesg | grep "DT" [ 2146.942455] spidev spi0.0: buggy DT: spidev listed directly in DTspidev_probe做了检查:
if(spi->dev.of_node&&!of_match_device(spidev_dt_ids,&spi->dev)){dev_err(&spi->dev,"buggy DT: spidev listed directly in DT\n");WARN_ON(spi->dev.of_node&&!of_match_device(spidev_dt_ids,&spi->dev));}