(1)因为在Linux驱动开发中,驱动可以和设备c文件文件进行匹配,也可以和设备树dts文件进行匹配。为了弄明白驱动与他们的匹配规则,我查阅了一些资料同时阅读了源码,最终打算使用图片的方式形象具体的写成博客。
(2)网上的资料基本都大同小异,都是直接干巴巴的贴出源码,然后一顿分析。而Linux中的调用关系太复杂,很容易看的头晕.
(3)因此我就根据大佬们的分析,对着代码一点一点的慢慢看。最终对驱动与设备的匹配规则有了一定的认识。
(4)通过源码我们可以知道Linux的匹配规则是有5条。但是很多时候,在网上说只有4条,要么就是无视了acpi匹配规则,要么就是无视了设备中的driver_override匹配规则。我也翻阅了正点原子,韦东山,北京迅为的教程,发现他们对这些匹配规则都进行了一定程度的无视。后面我将会讲解为什么会进行无视。
(1)在Linux的平台总线中,我们是使用platform_match()函数进行设备与驱动匹配的。
(2)platform_match()函数定义在文件 drivers/base/platform.c 中,函
数内容如下所示:
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);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
(3)从上面的代码我们可以看到,有四个if判断,最后那个return 还调用了strcmp()函数进行字符串的对比。因此我们可以得出结论:Linux中,驱动和设备是有5条匹配规则的。
(1)首先我们需要知道,dev,drv,pdev和pdrv分别代表什么意思。其实我们从他的变量定义就可以看出来。
<1>pdev = platform_device
<2>dev = platform_device.dev
<3>pdrv = platform_driver
<4>drv = platform_driver.driver
(2)由此可见,他首先判断platform_device.driver_override有没有赋值,如果被赋值了无论有没有被匹配上,后面的程序都不会再进行了!
(3)如果platform_device.driver_override被赋值了,那么我们就开始判断platform_device.driver_override == platform_driver.driver.name是否成立。如果成立就匹配成功,否则匹配失败。
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
(1)这一条主要是用来与设备树进行匹配的。这里有一个知识点,我们可以看到这个函数是of类型的,前缀是 of 的函数都是用于和设备树进行匹配的。
(2)我们可以看到,这里其实就是platform_driver.driver.of_match_table与设备树的compatible 属性进行匹配。(如下图)
static inline int of_driver_match_device(struct device *dev,const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
if (of_driver_match_device(dev, drv))
return 1;
(1)这一条很多人都是直接一句ACPI 匹配方式,然后就没有了。一开始我认为是使用的人太少,所以都避而不谈。后面发现是你根本改不了。
(2)ACPI主要用于x86架构的传统PC平台,特别是在桌面和笔记本电脑上。它较为复杂,包含了丰富的系统管理和电源管理功能。开发人员无法修改,只能由主板供应商修改BIOS固件。
(3)所以这个你不用理会。
if (acpi_driver_match_device(dev, drv))
return 1;
(1)第4条规则,判断platform_driver.id_table有没有赋值,如果被赋值了无论有没有被匹配上,后面的程序都不会再进行了!
(2)这个说白了就是就是让platform_driver.id_table.name == platform_device.name进行名字匹配,如果名字相同,就匹配成功。
static const struct platform_device_id *platform_match_id(
const struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
(1)这个就是下下策了,platform_device.driver_override和platform_driver.id_table都没有被定义。同时,设备树没有匹配成功。最终才会进行此次匹配。
(2)这个匹配很简单,platform_device.name == platform_driver.driver.name是否相等,如果相等,表示驱动和设备匹配成功。否则驱动和设备彻底匹配失败。
return (strcmp(pdev->name, drv->name) == 0);
(1)一般来说,我们在驱动的platform_driver结构体只会写两个。
<1>platform_driver.driver.name用于和c文件匹配。
<2>platform_driver.driver.of_match_table 用于和设备树匹配。
(2)注意:如果我们我们只写上面两种匹配方式,那么platform_device.driver_override和platform_driver.id_table都不能赋值!
(3)为什么别人常常说Linux驱动只有4条匹配规则呢?原因很简单,ACPI开发人员无法进行更改,只能由主板供应商修改BIOS固件,所以大家都选择了无视。
(4)为甚很多人会无视driver_override匹配规则呢?很简单,如果driver_override匹配规则被赋值了,那么后面的四条规则都将会失效。所以一般不写这一条。
static struct platform_driver gpio_platform_driver = {
.driver = {
.name = "100ask_gpio_plat_drv", //用于和设备c文件匹配
.of_match_table = gpio_dt_ids, //用于与设备树匹配
},
.probe = gpio_drv_probe,
.remove = gpio_drv_remove,
};