ACPI 扫描处理程序

版权所有:

© 2012, Intel Corporation

作者:

Rafael J. Wysocki <rafael.j.wysocki@intel.com>

在系统初始化和基于 ACPI 的设备热添加期间,会扫描 ACPI 命名空间以搜索通常代表各种硬件的设备对象。 这会导致为 ACPI 命名空间中的每个设备对象创建一个 struct acpi_device 对象并将其注册到驱动程序核心,并且这些 struct acpi_device 对象的层次结构反映了命名空间布局(即,命名空间中的父设备对象由父 struct acpi_device 对象表示,其子对象也类似)。 这些 struct acpi_device 对象在下面称为“设备节点”,但它们不应与设备树解析代码使用的 struct device_node 对象混淆(尽管它们的作用与这些对象的作用类似)。

在基于 ACPI 的设备热移除期间,表示要移除的硬件的设备节点将被取消注册和删除。

drivers/acpi/scan.c 中的核心 ACPI 命名空间扫描代码执行设备节点的基本初始化,例如从它们表示的设备对象检索通用配置信息并使用适当的数据填充它们,但其中一些需要在注册后进行额外处理。 例如,如果给定的设备节点表示 PCI 主桥,则其注册应导致枚举该桥下的 PCI 总线,并将该总线上的 PCI 设备注册到驱动程序核心。 类似地,如果设备节点表示 PCI 中断链接,则必须配置该链接,以便内核可以使用它。

这些额外的配置任务通常取决于给定设备节点所代表的硬件组件的类型,该类型可以根据设备节点的硬件 ID (HID) 确定。 它们由称为 ACPI 扫描处理程序的对象执行,这些对象由以下结构表示

struct acpi_scan_handler {
        const struct acpi_device_id *ids;
        struct list_head list_node;
        int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
        void (*detach)(struct acpi_device *dev);
};

其中 ids 是给定处理程序应处理的设备节点的 ID 列表,list_node 是连接到 ACPI 核心维护的 ACPI 扫描处理程序全局列表的钩子,并且 .attach() 和 .detach() 回调分别在新设备节点注册之后和处理程序先前附加到的设备节点取消注册之前执行。

命名空间扫描函数 acpi_bus_scan() 首先将给定命名空间范围内的所有设备节点注册到驱动程序核心。 然后,它尝试使用可用扫描处理程序的 ids 数组将扫描处理程序与每个设备节点进行匹配。 如果找到匹配的扫描处理程序,则为其给定设备节点执行其 .attach() 回调。 如果该回调返回 1,则表示处理程序已声明该设备节点,现在负责执行与其相关的任何其他配置任务。 在这种情况下,它还将负责准备设备节点以进行取消注册。 然后,设备节点的处理程序字段将填充已声明它的扫描处理程序的地址。

如果 .attach() 回调返回 0,则表示给定扫描处理程序对该设备节点不感兴趣,并且可以与列表中的下一个扫描处理程序匹配。 如果它返回(负)错误代码,则表示由于严重错误,应终止命名空间扫描。 返回的错误代码应反映错误的类型。

命名空间修剪函数 acpi_bus_trim() 首先执行给定命名空间范围内的所有设备节点的扫描处理程序中的 .detach() 回调(如果它们有扫描处理程序)。 接下来,它会取消注册该范围内的所有设备节点。

可以使用 acpi_scan_add_handler() 函数将 ACPI 扫描处理程序添加到 ACPI 核心维护的列表中,该函数将指向新扫描处理程序的指针作为参数。 扫描处理程序添加到列表中的顺序是在命名空间扫描期间它们与设备节点匹配的顺序。

所有扫描处理程序都必须在 acpi_bus_scan() 首次运行之前添加到列表中,并且不能从列表中删除。