4.8.5. 通用硬件寄存器
ACPI 提供了一种机制,允许在 ACPI 命名空间中向 OSPM 描述一类独特的“增值”硬件。在设计与 ACPI 兼容的硬件时,需要遵循若干规则。
编程位可以位于任何已定义的通用硬件地址空间中(系统 I/O、系统内存、PCI 配置、嵌入式控制器或 SMBus),但顶层事件位包含在通用事件寄存器中。通用事件寄存器由 GPE0_BLK 和 GPE1_BLK 寄存器块指向,而通用硬件寄存器可以位于任何已定义的 ACPI 地址空间中。设备的通用硬件编程模型通过 ACPI 命名空间中的关联对象进行描述,该对象指定该位的功能、位置、地址空间和地址位置。
设备的编程模型通常分解为状态和控制功能。状态位用于生成事件,使 OSPM 能够调用与待处理状态位关联的控制方法。随后,被调用的控制方法可以通过操作硬件控制位来控制硬件,或者通过检查子状态位并调用其各自的控制方法来进行控制。ACPI 要求顶层“父”事件状态位和使能位位于 GPE0_STS 或 GPE1_STS 寄存器中,而“子”事件状态位可以位于通用地址空间中。
下面的示例说明了其中一些概念。顶部图示展示了逻辑如何划分为两个芯片:一个芯片组和一个嵌入式控制器。
芯片组包含中断逻辑,处理电源按钮(其属于固定寄存器空间,此处不讨论)、盖子开关(在便携式设备中用于指示翻盖是打开还是关闭)以及 RI# 功能(可用于唤醒处于睡眠中的系统)。
嵌入式控制器芯片用于执行交流电源检测以及插接/拔接扩展坞事件逻辑。此外,嵌入式控制器还通过嵌入式控制器中的对操作系统透明中断支持某些系统管理功能(由 EXTSMI# 信号表示)。

图 4.13 通用事件与通用硬件事件示例
在顶层,GPEx_STS 寄存器中的通用事件包括:
嵌入式控制器中断,其中包含两个查询事件:一个用于交流电检测,另一个用于扩展坞插接(该扩展坞查询事件在扩展坞芯片中具有一个子中断状态位)。
振铃指示状态(用于唤醒系统)。
盖子状态。
嵌入式控制器事件状态位(EC_STS)用于指示两个查询事件中的一个处于活动状态。
- 当 AC# 信号被置位时,会生成一个查询事件。嵌入式控制器在响应此事件的查询命令时返回查询值 34(可以使用任意字节编号);随后 OSPM 将调度执行与查询值 34 关联的控制方法。
另一个查询事件用于生成扩展坞事件的扩展坞芯片。在这种情况下,嵌入式控制器将在响应来自系统软件、针对嵌入式控制器发出的 SCI 的查询命令时返回查询值 35。随后 OSPM 将调度执行与查询值 35 关联的控制方法,以处理该扩展坞事件。
对于 GPEx_STS 寄存器中的每个状态位,在 GPEx_EN 寄存器中都有一个对应的使能位。请注意,子状态位不一定需要使能位(参见 DOCK_STS 位)。
盖子逻辑包含一个控制位,用于确定当 LID 打开时其状态位是否被置位(LID_POL 被置位且 LID 被置位),或者当 LID 关闭时其状态位是否被置位(LID_POL 被清零且 LID 被清零)。该控制位位于通用 I/O 空间中(在本例中,为系统 I/O 空间 33h 的第 2 位),并将通过与盖子对象关联的控制方法进行操作。
与固定硬件事件一样,OSPM 将清除 GPEx 寄存器块中的状态位。然而,AML 代码会清除通用硬件中的所有等效状态位。
通用硬件特性由 OEM 提供的、以 AML 编码的控制方法控制。ACPI 为开发这些特性同时提供了事件模型和控制模型。ACPI 规范还提供了用于通知 OSPM 某些电源管理和即插即用事件的特定控制方法。ACPI 软件编程模型 提供了关于支持不同类型子系统的硬件功能类型的信息。以下是 ACPI 支持的特性列表。该列表并非旨在完整或全面。
设备插入/弹出(例如,扩展坞、设备仓、A/C 适配器)
电池 *
平台热子系统
打开/关闭电源资源
移动设备盖子接口
嵌入式控制器
系统指示器
OEM 特定唤醒事件
即插即用配置
注意
- ACPI 操作系统假定对电池使用由智能电池系统实施者论坛定义的标准,称为“智能电池规范”(SBS)。ACPI 提供了一组控制方法,供使用专有“控制方法”电池接口的 OEM 使用。
4.8.5.1. 通用事件寄存器块
ACPI 支持 FADT 中描述的最多两个通用寄存器块(参见 ACPI 软件编程模型),以及在 ACPI 命名空间中作为设备描述的任意数量附加 GPE 块。每个寄存器块包含两个寄存器:一个使能寄存器和一个状态寄存器。每个寄存器块都是 32 位对齐的。块中的每个寄存器都按字节访问。是否这些位在睡眠状态或软关机状态之间保持其上下文,取决于具体设计。如果它们在睡眠状态或软关机状态之间丢失其上下文,则平台引导固件会在唤醒后将控制权交给 OS 之前重置相应的使能位。
4.8.5.1.1. 通用事件 0 寄存器块
该寄存器块由两个寄存器组成:GPE0_STS 和 GPE0_EN 寄存器。每个寄存器的长度被定义为 GPE0 寄存器块长度的一半,并由 ACPI FADT 的 GPE0_BLK 和 GPE0_BLK_LEN 操作符描述。OSPM 拥有通用事件资源,这些位仅由 OSPM 操作;AML 代码不能访问通用事件寄存器。
可以预见,芯片组将包含 GPE 事件寄存器,为各种事件提供 GPE 输入引脚。
然后平台设计者会将 GPE 连接到各种增值事件硬件,而 AML 代码将向 OSPM 描述如何利用这些事件。因此,会存在这样一种情况:平台具有未连接到任何设备的 GPE 事件(它们存在于芯片组中),但平台并未使用它们,也没有关联的 AML 代码。在这种情况下,这些事件引脚应被拉到非活动状态,以使 GPE 寄存器中相应的 SCI 状态位不会因悬空输入引脚而被置位。
4.8.5.1.1.1. 通用事件 0 状态寄存器
寄存器位置:<GPE0_STS> 系统 I/O 或系统内存空间
默认值:00h
属性:读/写
大小:GPE0_BLK_LEN/2
通用事件 0 状态寄存器包含通用寄存器第零组中的通用事件状态位。该寄存器中每个可用状态位都对应于 GPE0_EN 寄存器中具有相同位位置的位。该寄存器中每个可用状态位在事件处于活动状态时被置位,并且只能由软件向其相应位位置写入“1”来清除。对于通用事件寄存器,未实现的位会被 OSPM 忽略。
如果某状态位在系统处于睡眠状态时被置位,并且其对应的使能位已设置,则该状态位可选择性地唤醒系统。OSPM 通过字节访问来访问 GPE 寄存器(无论其长度如何)。
4.8.5.1.1.2. 通用事件 0 使能寄存器
寄存器位置:<GPE0_EN> 系统 I/O 或系统内存空间
默认值:00h
属性:读/写
大小:GPE0_BLK_LEN/2
通用事件 0 使能寄存器包含通用事件使能位。该寄存器中每个可用使能位都对应于 GPE0_STS 寄存器中具有相同位位置的位。使能位的工作方式类似于固定事件寄存器中使能位的定义方式:当使能位被置位时,相应状态位中的已置位状态位将生成一个 SCI 位。OSPM 通过字节访问来访问 GPE 寄存器(无论其长度如何)。
4.8.5.1.2. 通用事件 1 寄存器块
该寄存器块由两个寄存器组成:GPE1_STS 和 GPE1_EN 寄存器。每个寄存器的长度被定义为 GPE1 寄存器块长度的一半,并由 ACPI FADT 的 GPE1_BLK 和 GPE1_BLK_LEN 操作符描述。
4.8.5.1.2.1. 通用事件 1 状态寄存器
寄存器位置:<GPE1_STS> 系统 I/O 或系统内存空间
默认值:00h
属性:读/写
大小:GPE1_BLK_LEN/2
通用事件 1 状态寄存器包含通用事件状态位。该寄存器中每个可用状态位都对应于 GPE1_EN 寄存器中具有相同位位置的位。该寄存器中每个可用状态位在事件处于活动状态时被置位,并且只能由软件向其相应位位置写入“1”来清除。对于通用事件寄存器,未实现的位会被操作系统忽略。
每个状态位在系统处于睡眠状态且其对应的使能位被设置时,如果被置位,则都可以选择性地唤醒系统。
OSPM 通过字节访问来访问 GPE 寄存器(无论其长度如何)。
4.8.5.1.2.2. 通用事件 1 使能寄存器
寄存器位置:<GPE1_EN> 系统 I/O 或系统内存空间
默认值:00h
属性:读/写
大小:GPE1_BLK_LEN/2
通用事件 1 使能寄存器包含通用事件使能。本寄存器中每个可用的使能位都对应于 GPE1_STS 寄存器中具有相同位位置的位。这些使能位的工作方式类似于固定事件寄存器中使能位的定义方式:当使能位被设置时,相应状态位中被置位的状态位将生成一个 SCI 位。
OSPM 通过字节访问来访问 GPE 寄存器(无论其长度如何)。
4.8.5.2. 通用设备示例
本节指出了具有特定 ACPI 驱动程序支持的通用设备。
4.8.5.2.1. 盖子开关
盖子开关是在大多数“翻盖式”移动计算机中存在的一项可选功能。OS 可以将其用作使系统进入睡眠状态的策略输入,或用于将系统从睡眠状态唤醒。如果使用该功能,则 OEM 需要将盖子开关定义为一个设备,其 _HID 对象值为 “PNP0C0D”,以便 OSPM 将该设备识别为盖子开关。盖子设备需要包含一个返回其状态的控制方法。盖子事件处理程序 AML 代码会重新配置盖子硬件(如果需要),使其在相反方向上生成事件,清除状态,然后将该事件通知给 OSPM。
下面给出了此类设计的硬件和 ASL 代码示例。

图 4.14 通用地址空间盖子开关逻辑示例
当按钮被按下或释放时(取决于盖子极性位),该逻辑将设置盖子状态位。
下面的 ASL 代码定义了以下内容:
一个操作区域,其中盖子极性位于系统地址空间中的寄存器 0x201。
一个字段操作符,以允许 AML 代码访问该位:极性控制位(LID_POL)称为 LPOL,并在 0x201.0 处访问。
一个名为 \_SB.LID 的设备,具有以下内容:
一个即插即用标识符 “PNP0C0D”,用于将 OSPM 与该对象关联。
定义了一个对象,用于指定盖子状态位的变化可以从 S4 睡眠状态以及所有更高的睡眠状态(S1、S2 或 S3)唤醒系统。
盖子开关事件处理程序,其执行以下操作:
将盖子状态位(LID_STS)定义为通用事件 0 寄存器位 1 的子项。
为盖子定义事件处理程序(该状态位上的唯一事件处理程序),其执行以下操作:
翻转 LPOL 位的极性(以便在相反条件下生成事件)。
向 OS 生成一个通知,其执行以下操作:
传递 \_SB.LID 对象。
指示一个设备特定事件(通知值 0x80)。
// Define a Lid switch
OperationRegion (\PHO, SystemIO, 0x201, 0x1)
Field (\PHO, ByteAcc, NoLock, Preserve)
{
LPOL, 1 // Lid polarity control bit
}
Device (\_SB.LID)
{
Name (_HID, EISAID ("PNP0C0D"))
Method (_LID)
{
Return(LPOL)
}
Name (_PRW, Package (2){
1, // bit 1 of GPE to enable Lid wakeup
0x04}) // can wakeup from S4 state
}
Scope(\_GPE)
{
Method(_L01) // uses bit 1 of GP0_STS register
{
LPOL ~= LPOL // Flip the lid polarity bit
Notify (\_SB.LID, 0x80) // Notify OS of event
}
}
4.8.5.2.2. 嵌入式控制器
ACPI 提供了一个标准接口,使 AML 代码能够在“嵌入式控制器空间”中定义和访问通用逻辑。这支持当前的计算机模型,其中许多增值硬件都包含在嵌入式控制器中,同时允许 AML 代码以抽象方式访问这些硬件。
嵌入式控制器被定义为一个设备,并且必须包含若干控制方法:
_HID,其值为 PNP0C09,用于将该设备与 ACPI 的嵌入式控制器驱动程序关联。
_CRS,用于返回嵌入式控制器正在消耗的资源。
_GPE,返回该嵌入式控制器连接到的通用事件位。
此外,每个嵌入式控制器最多可以支持 255 个通用事件,称为查询事件。这些查询事件处理程序在嵌入式控制器设备内定义为控制方法。下面给出了定义嵌入式控制器设备的示例:
Device(EC0) {
// PnP ID
Name(_HID, EISAID("PNP0C09"))
// Returns the "Current Resources" of EC
Name (_CRS, ResourceTemplate()
{
IO(Decode16, 0x62, 0x62, 0, 1)
IO(Decode16, 0x66, 0x66, 0, 1)
})
// Indicate that the EC SCI is bit 0 of the GP_STS register
Name (_GPE, 0) // embedded controller is wired to bit 0 of GPE
OperationRegion (\EC0, EmbeddedControl, 0, 0xFF)
Field (EC0, ByteAcc, Lock, Preserve)
{
// Field units of EC0
}
// Query methods
Method(_Q00)
{ ... }
Method(_QFF)
{ ... }
}
有关嵌入式控制器的更多信息,请参见 ACPI 嵌入式控制器接口规范
4.8.5.2.3. 风扇
ACPI 具有一个设备驱动程序,用于控制平台中的风扇(主动冷却设备)。风扇被定义为一个设备,其即插即用 ID 为 “PNP0C0B”。然后它应包含用于控制风扇的电源资源列表。
有关更多信息,请参见 ACPI 定义的设备和设备特定对象。