3.设备和系统状态的名称
电源管理要求的设备和系统电源状态的名称使用小写字母。一些操作,如wsprintf(buf, "%u", n)
或不区分大小写的比较,涉及Locale table查表操作。Locale table在Wince.nls内存映射文件中实现。在挂起期间,电源管理器禁止使用FileSystemPowerFunction访问文件系统。从挂起的线程中试图访问这个文件系统可能造成系统死锁。如果Wince.nls中必须的页面在内存中没有发现就会发生死锁。
处理API调用时,电源管理转换为小写的名称。然而,在挂起和恢复状态,电源管理器在文件系统操作被禁止后访问注册表。这可以防止注册表设置转换为小写。你必须修改你的系统电源状态的注册表设置为小写。例如,WAV1:应作为wav1:。其他则不用修改的注册表设置,如在控制装载设备驱动程序HKLM\Drivers\Builtin.。
三、电源管理接口
电源管理有三种不同的使用类型,包括:
·电源管理器识别的设备驱动程序。
·可能需要更改系统电源状态或者设备电源状态的应用程序。
·需要电源事件通知的应用程序
电源管理器使用不同的编程接口来与这些使用类型进行通讯。
1、设备驱动接口
电源管理器使用两种机制来沟通电源管理驱动程序。电源管理器向下调用设备驱动程序以确定该设备的性能和更新该设备的电源状态。设备向上调用电源管理器请求进行设备电源状态更改。向下调用执行IOCTL,向上设备调用DevicePowerNotify的API沟通电源管理器。(即电源管理器与支持电源管理的设备驱动程序之间的编程接口分为两类,一种是电源管理器自上向下地获取设备驱动程序的电源管理能力和控制改变外设的设备电源状态;另一种是设备驱动程序自下向上地请求电源管理器改变其目的的外设的电源状态。第一种编程接口的实现方式是通过流式接口驱动程序的IOControl函数和特定的为电源管理服务的IOCTLs操作码,专为电源管理而设计的IOCTLs操作码)。
由于电源管理使用DeviceIoControl来沟通电源管理设备,这些设备必须实现一个公开的接口。在某些情况下,可以使用电源管理代理来实现这一接口。网络驱动程序接口规范(NDIS)实现了一个公开的接口,使NDIS微型端口驱动程序使用RegisterPowerRelationship API代理管理。电源管理器使用DeviceIoControl与电源管理的设备通信,所以设备驱动必须导出一个流接口。然而,电源管理器也提供了一种鱼非流驱动直接进行通信的机制,这种方法是由对打开一个设备句柄、发送一个请求等的抽象组成,绝大多是设备支持流接口。例如,位于Public\Common\Oak\Drivers\Pm\Mdd\Pmdisplay.cpp的驱动程序实现了一个基于ExtEscape功能,实现了通信接口。
开放的标准格式的COM1:,等,允许访问公开流接口的驱动程序。然而,电源管理并不要求支持电源管理器的设备必须使用这个格式命名;设备名称可以是任何唯一的字符串。例如: NDIS微型端口可能被命名为VMINI1。
Platform Builder提供的电源管理虽然只是支持流驱动,但是OEM厂商可以自由的运行其他的设备接口。可以通过定义一个新类的全局唯一标识符(GUID)的设备来实现新的接口。但是必须坚持标准的电源管理驱动程序标准。
默认情况下,电源管理器提供以下GUID:
· {A32942B7-920C-486b-B0E6-92A702A99B35} GUID for generic power-managed devices.
· {8DD679CE-8AB4-43c8-A14A-EA4963FAA715} GUID for power-managed block devices.
· {98C5250D-C29A-4985-AE5F-AFE5367E5006} GUID for power-managed NDIS miniports.
应用程序可以从HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control
\Power\Interfaces注册表键中获取可被管理的设备类型的列表。
当应用程序调用一个指定设备的电源管理API时,应用程序应该指定设备类型名。如果设备没有指定设备的类型名,电源管理器会假定该设备属于通用的电源管理设备类。
有效的设备类型是在GUID后加一个反斜杠符号。例如GUID {8DD679CE-8AB4-43c8-A14A-EA4963FAA715}\DSK1:是指一个名为DSK1电源管理块设备。
电源管理器从注册表读取设备类的列表,并使用RequestPowerNotifications决定此类型的设备在什么时候被载入。下面的代码示例显示了一个设备类列表:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Interfaces]
"{A3292B7-920C-486b-B0E6-92A702A99B35}"="Generic power-manageable devices"
"{8DD679CE-8AB4-43c8-A14A-EA4963FAA715}"="Power-manageable block devices"
"{98C5250D-C29A-4985-AE5F-AFE5367E5006}"="Power-manageable NDIS miniports"
Platform Builder附带的电源管理器以上述的设置执行,如果不定义心得设备注册表键。除非你想增加额外的键,在注册表中可以不包含上述设置。下面步骤显示可以管理直接使用ExtEscape代码直接管理显示驱动类型的过程。
1、使用Guidgen.exe创建一个新的GUID类型,并将其添加到注册表中。
2、为了识别GUID,需要修改电源管理器,并使用ExtEscape来与设备进行通信。
3、调用AdvertiseInterface,来使用新的GUID来修改显示驱动。
1.1 设备控制符IOCTL
电源管理器使用如下的IOCTL代码来与设备通信。
电源管理的IOCTLs操作码(作了扩展理解)
电源管理的IOCTLs操作码 | 描述 |
IOCTL_POWER_CAPABILITIES | 电源管理器向设备驱动程序询问其对电源管理的支持能力 |
IOCTL_POWER_SET | 电源管理器请求外设进入指定的设备电源状态,如果外设不支持IOControl函数的参数所要求的设备电源状态,则驱动程序应使外设进入相邻的外设可支持的电源状态,并且将此电源状态通过IOControl函数的输出参数反馈给电源管理器 |
IOCTL_POWER_QUERY | 电源管理器询问外设及其驱动程序是否准备好进入某个新的设备电源状态,默认的电源管理器实现不支持这个操作码,有需要的用户应该定制动态链接库pm.dll实现代码。 |
IOCTL_POWER_GET | 电源管理器询问外设当前所处的设备电源状态 |
IOCTL_REGISTER_POWER_RELATIONSHIP | 电源管理器通知母设备(通常是总线设备)注册所有的受它控制的客户端外设。这个操作码即无输入也无输出。返回值也被电源管理器丢弃,仅用作通知消息。 |
1.2 驱动到电源管理器的API函数
电源管理器为设备提供如下函数,设备可以通过掉用以下函数向电源管理器请求服务。
函数名 | 功能 |
DevicePowerNotify | 设备驱动调用该函数请求电源管理器更新其设备的电源状态 |
总线驱动及其他代理电源管理器在需要拦截所有设备的电源IOCTL时调用该函数 | |
结束由该函数调用创建的代理关系 |
2、应用程序接口
电源管理器提供了一些函数,是应用程序可以使用这些函数进行设备电源管理。下表中的API函数中,只有GetSystemPowerState, SetPowerRequirement 和 ReleasePowerRequirement是普通应用程序可以直接执行的。例如,应用程序可以调用SetSystemPowerState来挂起系统,但是电源管理器可以限制应用程序请求进入的系统电源状态。其他的API函数是为如控制面板这样的OEM应用程序准备的。下表是这些函数的说明。
电源管理的应用程序编程接口
函数 | 描述 |
GetSystemPowerState | 返回当前系统电源状态的名称 |
SetSystemPowerState | 请求电源管理器改变当前系统电源状态 |
SetPowerRequirement | 请求电源管理器将给定设备的电源状态维持在最低水平上 |
ReleasePowerRequirement | 通知电源管理器不再需要将给定的设备的电源状态维持在最低水平上 |
GetDevicePower | 返回给定设备的当前电源状态 |
SetDevicePower | 请求电源管理器改变给定设备的电源状态 |
2.1 系统电源状态的设置
在某些情况下的应用程序可能要更改系统电源状态。在特定的Windows CE设备上,应用程序不知道哪些电源状态是可以使用的,也预计他们知道可用的系统电源状态的特点。应用程序使用描述电源状态的掩码来调用SetSystemPowerState进行电源状态切换,而不用调用明确的状态名,电源管理器会将该掩码转换为对应的电源状态。例如,应用程序可以使用POWER_STATE_SUSPEND位元请求进行系统电源状态的切换。请求时系统是否在cradle,电源管理器随后会切换到Suspend或SuspendCradle状态。如果设备被从cradle中取下,电源管理器会将设备切换到Suspend状态。
电源管理器可能会限制进入某些系统电源状态的应用即限制应用程序可以设置进入哪些系统的电源状态。例如,如果电源管理器使用外部输入控制系统电源状态,当转换为电池供电时,它将不会允许进入AcRun状态。Platform Builder附带的电源管理器仅允许应用程序设置系统进入Suspend的状态。
下表描述了预定义的电源状态位元及其含义。
位元 | 描述 |
POWER_STATE_ON | 高性能高功耗 |
POWER_STATE_OFF | 所有设备都被关闭 |
POWER_STATE_CRITICAL | 电池电量低 |
POWER_STATE_BOOT | 系统正在启动 |
POWER_STATE_IDLE | 空闲状态 |
POWER_STATE_RESET | 清除文件,关闭设备并调KernelIoControl |
POWER_STATE_SUSPEND | 挂起操作系统并最终调用OEMPowerOff |
Platform Builder附带的电源管理器并没有使用上表中全部状态。OEM可以根据其设备自行定义状态标记。
如果应用程序使用SetSystemPowerState请求进入一个新的电源状态,电源管理器将进行以下处理。
·播出PBT_TRANSITION通知。
·如有需要更新设备的电源状态。如果设备已经处于可以接受新的系统电源状态的状态下,电源管理就不需要发出IOCTL_POWER_SET。
·如果设备从挂起状态到恢复。电源管理器将播出PBT_RESUME通知。
2.2 设备电源需求
在某些情况下应用程序需要改变电源管理器对系统电源状态的管理。例如某应用程序页面需要使COM3:保持在运行在D3或者更高的状态,甚至是在挂起时也以此电源状态运行,从而在COM3:收到一个传入页面时能唤醒系统。或者一个流式音频程序即使在系统使用电池供电的情况下需要网卡及音频系统。甚至在已经空闲了一段时间的情况下也能保持在全功耗(Full Power)运行。电源管理提供了SetPowerRequirement API来支持应用具有特殊的电源管理需求。
SetPowerRequiremen API函数允许应用程序请求电源管理器在设备状态上设置一个较低的下限。如果电源要求有效,电源管理器则不允许设备将自己的电源状态设为低于要求的下限值。当电源管理系统电源状态时,它通常会保持在此状态,即使设备需要维持在一个高于系统电源状态的设备的电源状态。
设备的电源要求通常预留的操作系统挂起时。在操作系统挂起状态,CPU停止和中断服务。如果应用程序使用的设备可能是能够在暂停状态下运行,可以在调用SetPowerRequirement时设置POWER_FORCE标记。
电源管理器可预留设备的电源要求,以及其他情况下。例如,OEM可以选择解释为表明操作系统的电池电量严重不足,应关闭所有设备的操作系统电源状态POWER_STATE_CRITICAL标志。