ACPI 扫描处理器

版权:

© 2012, 英特尔公司

作者:

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() 之前添加到列表中,并且不能将其从列表中删除。