LV06-05-linux平台总线模型-03-平台总线的匹配

平台总线怎么完成平台设备和平台驱动的匹配的?若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.2的64位版本
VMware® Workstation 17 Pro 17.6.0 build-24238078
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04
linux内核 linux-4.19.71(NXP官方提供)
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
nxp-imx/linux-imx/releases/tag/v4.19.71 NXP linux内核仓库tags中的v4.19.71
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)
Source Code https://elixir.bootlin.com/linux/latest/source linux kernel源码
kernel/git/stable/linux.git - Linux kernel stable tree linux kernel源码(官网,tag 4.19.71)
https://elixir.bootlin.com/u-boot/latest/source uboot源码

一、平台总线匹配

在前面学习总线的时候,我们知道,在编写总线驱动的时候都会实现一个xxx_match()函数来完成驱动和设备的匹配,平台总线也属于总线,内核已经帮我们实现好了这个函数:platform_match()。接下来就来了解一下。

1. platform_match()

platform_match() 函数定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
}
image-20250119100853784

这里调用了 to_platform_device()to_platform_driver() 宏。这两个宏定义的原型如下:

1
2
#define to_platform_device(x)     (container_of((x), struct platform_device, dev)
#define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver))

其中, to_platform_device()to_platform_driver() 实现了对 container_of() 的封装, dev、driver分别作为struct platform_devicestruct platform_driver 的成员变量, 通过 container_of() 宏可以获取到正在进行匹配的platform_driver 和platform_device 。

image-20250119101404739

platform总线提供了四种匹配方式,并且这四种方式存在着优先级:设备树机制 > ACPI匹配模式 > id_table方式 > 字符串比较。

虽然匹配方式有这么多种,但是并没有涉及到任何复杂的算法,都只是在匹配的过程中,比较一下设备和驱动提供的某个成员的字符串是否相同。 设备树是一种描述硬件的数据结构,它用一个非C语言的脚本来描述这些硬件设备的信息,后面会详细学习。驱动和设备之间的匹配时通过比较compatible的值。 acpi主要是用于电源管理,基本上用不到,这里就暂时不去了解了。

2. 四种匹配方式

其实算起来算是5种匹配方式,并且有有优先级:

  • 方式一:最先比较是否强制选择某个 driver
  • 方式二:设备树匹配
  • 方式三:ACPI匹配
  • 方式四:id匹配
  • 方式五:name匹配

2.1 方式一:是否强制选择某个 driver

image-20250119105029722

这种方式比较的是 platform_device.driver_overrideplatform_driver.driver.name。可以设置 platform_device 的 driver_override,强制选择某个 platform_driver。这里就暂时不深入了解了。

2.2 方式二:设备树匹配

这个后面学习设备树的时候再学习,这里先简单了解一下。

image-20250119104932229

设备树匹配比较的是 platform_device.dev.of_nodeplatform_driver.driver.of_match_table。由设备树节点转换得来的 platform_device 中,含有一个结构: struct device_node。它的类型如下:

1
2
3
4
5
6
7
struct device_node {
const char *name; // 来自节点的 name 属性
const char *type; // 来自节点的 device_type 属性
//......
struct property *properties;// 含有 compatible 属性
//......
};

如果一个platform_driver支持设备树,它的 platform_driver.driver.of_match_table 是一个数组,类型为 struct of_device_id

1
2
3
4
5
6
7
8
9
/*
* Struct used for matching a device
*/
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
};

使用设备树信息来判断 dev 和 drv 是否配对时 :

(1)首先,如果 of_match_table 中含有 compatible 值,就跟 dev 的 compatile属性比较,若一致则成功,否则返回失败;

(2)其次,如果 of_match_table 中含有 type 值,就跟 dev 的 device_type 属性比较,若一致则成功,否则返回失败;

(3)最后,如果 of_match_table 中含有 name 值,就跟 dev 的 name 属性比较,若一致则成功,否则返回失败。而设备树中建议不再使用 devcie_type 和 name 属性,所以基本上只使用设备节点的 compatible 属性来寻找匹配的 platform_driver。

2.3 方式三:ACPI匹配

image-20250119105102343

ACPI(高级配置和电源接口),这里就暂时不去了解了。

2.4 方式四:id匹配

image-20250119105133421

比较 platform_device.nameplatform_driver.id_table[i].name, id_table 中可能有多项。

platform_driver.id_table是“platform_device_id”指针,表示该 drv支持若干个 device,它里面列出了各个 device 的{.name, .driver_data},其中的“ name”表示该 drv 支持的设备的名字, driver_data 是些提供给该device 的私有数据。

platform_deviceplatform_driver中均含有“platform_device_id”指针,名字分别为platform_device.id_entryplatform_driver.id_tableplatform_driver.id_table 将会提供一个数组,里面包含这个驱动支持的所有设备的名称,以及私有数据,当设备和驱动匹配之后,会将驱动中匹配的这个设备的名字以及驱动将要提供的私有信息返回给设备中的platform_device.id_entry 成员:

驱动和设备匹配过程

所以,通过这种方式匹配的时候,platform_device.name 一定要存在于 platform_driver.id_table 指向的数组中,这样才可以完成匹配,并且匹配后,还可以获取到驱动中的一些信息。

2.5 方式五:name匹配

image-20250119110516247

当前面的都没有匹配上时,就会使用名称匹配,就是比较 platform_device.nameplatform_driver.driver.name

名称匹配方式

通过这种方式完成匹配的话, platform_driver.id_table 需要为空或者里面没有 platform_device.name

3. 匹配方式总结

画张图来帮助理解,不考虑ACPI匹配方式:

image-20250119115206386

二、平台总线匹配实现demo

1. 名称匹配demo

1.1 demo源码

06_platform_bus/03_name_match · 苏木/imx6ull-driver-demo - 码云 - 开源中国

1.2 开发板验证

将编译完的sdriver_demo.ko、sdevice_demo.ko拷贝到开发板,然后执行以下命令加载:

1
2
insmod sdriver_demo.ko
insmod sdevice_demo.ko

然后就会看到以下打印信息:

image-20250120104158719

可以看到设备和驱动名称相同时,驱动中的xxx_probe()函数执行,然后会有提示驱动和设备匹配成功。我们再看一下 /sys/bus/platform/devices 和 /sys/bus/platform/drivers:

image-20250120104604003

发现两个设备和驱动已经绑定在一起了。需要知道的是,这种匹配方式,驱动和设备的名称都是一样的,都是 sumu-sdev。

2. id匹配demo

2.1 demo源码

06_platform_bus/04_id_match · 苏木/imx6ull-driver-demo - 码云 - 开源中国

2.2 开发板验证

将编译完的sdriver_demo.ko、sdevice_demo.ko拷贝到开发板,然后执行以下命令加载:

1
2
insmod sdevice_demo.ko
insmod sdriver_demo.ko

然后就会看到以下打印信息:

image-20250120110322289

驱动中的xxx_probe()函数执行,然后会有提示驱动和设备匹配成功。我们再看一下 /sys/bus/platform/devices 和 /sys/bus/platform/drivers:

image-20250120110453176

可以看到驱动和设备的名字已经不同了,但是两者还是成功进行了匹配。

3. 设备树匹配

这个后面学习设备树了再说。

参考资料:

一张图掌握 Linux platform 平台设备驱动框架!【建议收藏】-CSDN博客