瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第九期_设备模型_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第102章 platform总线注册流程实例分析实验
在上个章节中,我们详细地从代码的层面分析了总线注册的流程,并深入了解了总线的实现过程。现在,在本章节中,我们将继续承接前文的内容,进一步分析 platform 总线的注册流程。本章节将深入研究 platform 总线注册的关键步骤。揭示 platform 总线注册的内部机制。让我们开始吧!
内核在初始化的过程中调用platform_bus_init()函数来初始化平台总线,调用流程如下所示:
图102-1
我们直接分析platform_bus_init函数。在内核driver/base/platform.c文件中注册了platform文件,platform_bus_init函数如下所示:
int __init platform_bus_init(void)
{int error;early_platform_cleanup(); // 提前清理平台总线相关资源error = device_register(&platform_bus); // 注册平台总线设备if (error) {put_device(&platform_bus); // 注册失败,释放平台总线设备return error; // 返回错误代码}error = bus_register(&platform_bus_type); // 注册平台总线类型if (error) {device_unregister(&platform_bus); // 注册失败,注销平台总线设备return error; // 返回错误代码}of_platform_register_reconfig_notifier(); // 注册平台重新配置的通知器return error; // 返回错误代码(如果有)
}
函数首先清空总线early_platform_device_list上的所有节点。然后使用调用device_register(platform_bus_type) 注册平台总线设备,将platform_bus结构体注册到设备子系统中。然后使用bus_register(&platform_bus_type)函数注册平台总线类型,将 platform_bus_type 结构体注册到总线子系统中。
在上面的函数中使用bus_register(&platform_bus_type)注册了平台总线。platform_bus_type结构体如下所示:
struct bus_type platform_bus_type = {.name = "platform",.dev_groups = platform_dev_groups,.match = platform_match,.uevent = platform_uevent,.dma_configure = platform_dma_configure,.pm = &platform_dev_pm_ops,
};
上述代码定义了一个名为platform_bus_type的struct bus_type结构体变量,表示平台总线类型。
该结构体变量的成员包括:
- .name = "platform":指定平台总线类型的名称为"platform"。
- .dev_groups = platform_dev_groups:指定设备组的指针,用于定义与平台总线相关的设备属性组。
- .match = platform_match:指定匹配函数的指针,用于确定设备是否与平台总线兼容。
- .uevent = platform_uevent:指定事件处理函数的指针,用于处理与平台总线相关的事件。
- .dma_configure = platform_dma_configure:指定DMA配置函数的指针,用于配置平台总线上的DMA。
- .pm = &platform_dev_pm_ops:指定与电源管理相关的操作函数的指针,用于管理平台总线上的设备电源。
我们重点来看看platform_match函数,如下所示:
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);
}
platform_match是一个用于判断设备和驱动程序是否匹配的函数。它接受两个参数:dev表示设备对象指针,drv表示驱动程序对象指针。上述函数的主要逻辑如下:
1首先,将dev和drv分别转换为struct platform_device和struct platform_driver类型的指针,以便后续使用。
2 检查pdev->driver_override是否设置。如果设置了,表示只要与指定的驱动程序名称匹配,即可认为设备和驱动程序匹配。函数会比较pdev->driver_override和drv->name的字符串是否相等,如果相等则返回匹配(非零)。
3 如果pdev->driver_override未设置,首先尝试进行OF风格的匹配(Open Firmware)。调用of_driver_match_device(dev, drv)函数,该函数会检查设备是否与驱动程序匹配。如果匹配成功,则返回匹配(非零)。
4 如果OF风格的匹配失败,接下来尝试进行ACPI风格的匹配(Advanced Configuration and Power Interface)。调用acpi_driver_match_device(dev, drv)函数,该函数会检查设备是否与驱动程序匹配。如果匹配成功,则返回匹配(非零)。
5 如果ACPI风格的匹配也失败,最后尝试根据驱动程序的ID表进行匹配。检查pdrv->id_table是否存在。如果存在,则调用platform_match_id(pdrv->id_table, pdev)函数来检查设备是否与ID表中的任何条目匹配。如果匹配成功,则返回匹配(非零)。
6如果以上所有匹配尝试都失败,最后使用驱动程序名称与设备名称进行比较。比较pdev->name和drv->name的字符串是否相等,如果相等则返回匹配(非零)。
通过上述分析,我们终于明白了为什么在platform总线匹配优先级的时候,of_match_table>id_table>name。
至此,platform总线注册流程分析完毕。