神医侠侣莫娘:WinCE 电源管理

来源:百度文库 编辑:中财网 时间:2024/03/28 20:11:24
Windows CE设备驱动开发之电源管理
4.7电源管理
电源管理模块管理设备电源,从而全面改进操作系统的电源使用效率;它所有设备的电源使用,同时能与不支持电源管理的应用程序及驱动程序共存。
使用电源管理可以有效的减少目标设备的电源消耗,同时,能在运行、空闲、复位及挂起电源状态时维持并保护RAM中的文件系统。
电源管理具有以下特性:
使设备具有自行电源管理功能的框架;
建立一种在系统中使设备电源在挂起和恢复状态间切换的机制;
一个对系统环境、电源状态、设备电源状态有统一认识的模块。你可以定制电源管理模块,使全系统的电源分配适合您的设备;
当系统挂起或恢复时,使系统跳过所有代码调用PowerOffSystem函数。
对于支持电源管理的驱动程序,在设备枚举时应尽量准确的向电源管理模块报告其性能,然后将收到来自电源管理模块的获取或更改其电源状态的请求。对于自行管理电源的设备,必须通过DevicePowerNotify向电源管理模块发送请求来更改电源状态。
电源管理模块与设备在一个正常的线程执行环境中通过调用DeviceIoControl进行通讯。
4.7.1、            电源管理架构
在不依赖Windows CE电源管理模型的情况下,只能对设备进行简单的管理。电源管理器为OEM厂商提供了较大的灵活性,同时驱动开发人员也不用为了兼容电源管理模型而牺牲驱动程序性能。在基本的Windows CE电源模型中,在操作系统挂起或恢复时,设备会收到标识信息(notification)。这一标识信息在中断处理时产生,所以设备在挂起状态时可以做什么工作,有多长时间做这一工作被严格限制。下图描述了Windows CE电源管理的结构。
使用电源管理器时,设备会从I/O控制代码(IOCTLs)收到电源状态改变通知。因为IOCTLs在线程中执行,在线程中驱动开发者可以更为灵活的处理电源状态改变。使用IOCTLs还能够区分设备电源状态与系统电源状态。这样,在系统运行时可以将部分设备关闭,而某些设备也可以在系统挂起时一直开启。
除了管理设备电源,电源管理器还向应用程序通知其它与电源相关事件的发生。例如:当系统从挂起状态恢复运行时,电源管理器会向相关应用程序发出通知。
电源管理器是一个名为pm.dll的动态链接库,系统运行时被Device.exe进程直接调用。当电源管理API被调用时,Device.exe调用pm.dll的入口函数。在Platform Builder 4.0及其后续版本中提供了Pm.dll的源代码,OEM厂商可以根据其设备修改Pm.dll。
电源管理器担任设备、应用程序及预定义的操作系统电源状态的仲裁者。电源管理器定义了下列规则,使上述三部分以这些规则进行通讯:
l         系统电源状态限定了所有设备的最大功耗;
l         应用程序以最小功耗来获取指定设备的最低性能等级。
l         当设备功耗在其最大功耗与最小功耗范围内时,电源管理器允许设备自行管理其电源。
l         如果最小功耗高于最大功耗,那么,在应用程序请求设备运行期间,设备电源将持续提升。
l         设备可以在一个或多个电源状态下运行。电源状态以有限的数字表示。详见设备电源状态章节。
l         系统转为挂起状态后,对应用程序有用的最小功耗将被取消。
l         系统电源状态是描述所有设备中最大的设备电源状态。系统电源状态由OEM厂商定义,并在注册表中描述,同时,在电源管理器中可以加入部分支持代码。OEM厂商可以定义任意数量的系统电源状态。详见系统电源状态章节。
在电源管理器框架内部,OEM厂商可以定义系统电源状态来设定最大设备电源状态。设备调用DevicePowerNotify来控制其电源等级,应用程序调用SetPowerRequirement来确认它们需要使用的设备是否正在合适的性能等级运行。
4.7.1.1              电源管理器和ACPI/APM
电源管理器并不涉及高级配置与电源接口(ACPI)或高级电源管理(APM)。ACPI规范将系统电源状态定义为一个从高功率/高性能到低功率/低性能的线性集。Windows CE电源管理器允许OEM厂商定义任意数目的系统电源状态,但并不要求定义的系统电源状态是线性的。
我们鼓励开发者根据情况定义操作系统电源状态,并根据设备定位或环境控制设备电源。例如:开发者可以定义系统电源状态,据此可以做到在装置不在支架(cradle)中时可以关闭某些设备,或者当系统使用外接交流电源时允许设备运行在高功耗电源等级。同样的,开发者可以根据系统环境定义不同的空闲、挂起状态。开发者需要定制电源管理器并保证在适当或必须的时候在各种电源状态间切换。
系统电源状态与ACPI模式有显著的区别。然而,设备电源状态表面上看起来与ACPI规范中的设备电源状态类似,但实际上,他们仍有细微的区别。例如:在Windows CE中D3电源状态被设定为在操作系统挂起时可使指定设备担任唤醒源的功能。
4.7.1.2              电源挂起、恢复回调函数
挂起和恢复电源事件的回调函数与电源管理器无关。当CPU被停止,操作系统将进入挂起状态,这时回调函数会被系统调用。并在OEMPowerOff被调用前立即执行。在电源管理器请求关闭系统电源并进入挂起状态之前,电源管理器会时常对设备驱动进行IOCTL调用。当然,情况并不总是这样。电源管理器框架允许设备在系统运行时被关闭,也允许设备在系统挂起时处于开启状态。
当设备电源状态为D0,D1或D2,如果掉电事件发生时,开发者可以自行决定进行何种处理。此时,通常关闭设备电源,并在加电事件发生时恢复供电。如果设备可以不依赖CPU即可运行,在挂起状态时或许可以使此设备运行。如果设备在挂起期间一直处于供电状态,那可能是电源管理器配置错误,或者是应用程序使用POWER_FORCE标记对此设备进行了SetPowerRequirement调用。
4.7.1.3              其他电源管理API
电源管理器创建于标准的Windows CE电源体系结构的上层。所以,不管电源管理器如何运行,流接口设备驱动程序在系统挂起或恢复时总是通过XXX_PowerUp和XXX_PowerDown获取通知。下表列出了与电源管理相关的API。
函数名
功能描述
GetSystemPowerStatusEx2
获取电池状态信息。
PowerPolicyNotify
以事件的形式通知电源管理器,以便执行必要的处理,从而实现OEM创建的电源策略。
OEMIdle
被系统内核调用。在没有线程需要运行时将处理器置为空闲状态。
OEMPowerOff
当关机按钮被按下,或图形、窗体、事件子系统(GWES)超时时被调用。使处理器进入挂起状态。
XXX_PowerDown (Device Manager)
挂起设备电源。仅用于能被软件控制关闭的设备。
XXX_PowerUp (Device Manager)
恢复设备电源。
Windows CE设备驱动开发之电源管理      第二部分
4.7.2、电源状态
电源管理器期望所有被管理的设备能支持一个或多个设备电源状态。设备电源状态的数量是有限的。设备必须通知电源管理器其功耗特性。设备常以功耗换取性能。
电源管理器在OEM定义的系统电源状态下管理设备电源状态。系统电源状态在注册表中定义,可以用任意数字定义。系统电源状态会给设备电源状态设置一个上限。
某些应用程序可能需要特定设备保持运行在指定的设备功率等级上。例如:当一个音频播放程序在播放音乐时,可能需要网卡及音频解码器保持运行在高功率等级。视频播放程序可能需要网络、音频,同时可能要使显示设备在进入屏幕保护模式后一直显示,并保持背光常亮。应用程序可以请求电源管理器设置最小设备电源状态,电源管理器会调用SetPowerRequirement和ReleasePowerRequirement系统API来进行设置。
4.7.2.1              设备电源状态
设备电源状态是预定义的静态值。电源管理器将设备状态传给驱动程序,驱动程序负责将其映射为自身的设备性能,然后在物理设备上进行状态转换。
下表是对各种设备电源状态的描述。
设备电源状态
注册表键值
描述
Full on
D0
此状态表示设备已开启或正在运行。设备将以系统允许的最大功耗及最高性能运行。
Low on
D1
此状态表示设备已开启或正在运行,但以低于D0状态的功耗及性能运行。D1状态适用于设备已经被使用,但以较低的性能运行即可,没有必要以最大性能运行,会产生额外的功率消耗。
Standby
D2
此状态表示设备被部分供电,保证设备在需要时能自动唤醒。
Sleep
D3
睡眠状态。保证唤醒的最小供电,在需要时能自动唤醒并初始化。
Off
D4
关闭状态,不供电。
一种物理设备并不能支持上述所有的设备电源状态。但是,所有的设备都必须支持D0设备电源状态。如果驱动程序收到请求,要求其将设备进入它不支持的电源状态,驱动程序应使设备进入下一个支持的电源状态。例如:电源管理器请求设备进入D2电源状态,但设备并不支持D2状态,这时如果设备支持D3或D4状态,驱动程序应使设备进入D3或D4状态。如果某一设备需要进入D3状态,但是此设备却不能唤醒系统,那么应使此设备进入D4状态。上述这些规则可以使驱动程序的执行简单化。
电源管理器有选择的将系统电源状态映射为对应的设备电源状态。例如:如果设备仅支持D0及D4电源状态,那么,电源管理器不会直接请求设备进入D4电源状态。如果D3或D4被设为此设备的最小电源状态,电源管理器会一直等待直到系统进入D3或D4状态时,再将设备设为D4状态。如果此设备的最小电源状态被设为D0、D1或D2,电源管理器将使设备一直运行于D0状态。
当设备驱动程序被加载时,应将设备设为D0状态。在驱动程序被卸载时,应将设备设为D4状态。如果在启动时设备进入了D0外的其他设备电源状态,那么可以在处理IOCTL_POWER_CAPABILITIES时发出一个DevicePowerNotify请求。
4.7.2.2              系统电源状态
系统电源状态由OEM定义,并由OEM引用。OEM可以将其命名为像On,SystemIdle,OnBattery,InCradle,OutOfCradle等名称。这些名称并没有被系统预定义,也不要求将其定义为线性序列。系统电源状态在系统配置注册表键中定义。Windows CE并没有限制可以定义多少种系统电源状态。
当然,也可以创建系统电源状态与预定义的设备电源状态的显式映射。显式映射需要在注册表中定义。系统电源状态明确的制定系统中所有设备的最大设备电源状态。
电源管理器示例定义了On,UserIdle,SystemIdle及Suspend四种系统电源状态。当用户使用系统时,电源状态设为On。如果用户停止使用,电源状态被设为UserIdle。当用户在一定的周期内(如30s)不使用系统,则进入SystemIdle状态;只要设备驱动程序处于活动状态,系统将一直保持在SystemIdle状态。如果设备驱动程序停止活动,系统进入Suspend状态。
UserIdle状态用于用户正在使用设备,但却没有操作设备。例如,用户一直观看屏幕显示,但没有手动操作。SystemIdle状态被用于用户没有直接使用设备,但处理器仍在继续运行。例如,在传输文件期间,用户可能人为设备已处于空闲状态,但实际上处理器依旧在持续运行,直到文件传输完成。
电源管理器示例实现了根据UserActivity和SystemActivity定时器对用户及系统活动进行判断。在定时器超时后,根据当前系统供电状况(使用外接电源或电池)进行不同的系统电源状态切换。
Platform Builder提供的Windows CE运行时image示例均使用外接电源供电模式。你可以选择实现一套在使用电池供电时的电源状态。复制电源管理器示例代码的PDD目录,并对其做适当的修改即可。
4.7.2.2.1   将系统电源状态映射为设备电源状态
在注册表系统配置中明确定义系统电源状态名称。系统电源状态到设备电源状态的映射在注册表的每一个电源状态名称键值下被枚举。如下示例代码:
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/Example]    Default=dword:0; D0    Flags=dword:10000; POWER_STATE_ON    COM1:=dword1; D1上面的注册表片段定义了名为Example的系统电源状态,并设置了除COM1:被限制为最高运行于D1设备电源状态外,其他的所有设备最高均可运行于D0设备电源状态。其中Flags列是一个标识码,用于表示Pm.h头文件中定义的POWER_STATE_ON标记。如果需要,OEM可以定义自己的电源状态标记。
下表列出了键值名称及其描述。
键名
描述
Name
系统电源状态名称
Flags
标识码。用于表示在Pm.h头文件中预定义的类似于POWER_STATE_ON的标记。
Default
表示在此系统电源状态下时,所有设备的默认设备电源状态。此键值用数字表示,0代表D0,1代表D1,以此类推。
DeviceName
设置在此系统电源状态下指定设备的最大设备电源状态。可以对任意数目的设备进行定义。
电源管理器支持多种设备类型的映射。例如:NDIS迷你接口及块设备驱动器设备类型在Pm.h中会被指定为其自身的GUID类型。其他类型被管理设备的默认值也可以在注册表中指定。例如:
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/Example/{98C5250D-C29A-4985-AE5F-AFE5367E5006}]    Default=dword:1; D1    "CISCO1"=dword:0; D0上面注册表片段设置电源管理器限值所有NDIS迷你接口设备在Example系统电源状态下时均运行于D1设备电源状态,只有名为CISCO1的设备最高可运行于D0状态。
4.7.2.2.2   系统电源状态切换
电源管理器在下列情况下进行系统电源状态切换:
l         OEM定义的状态切换事件发生。
l         应用程序调用SetSystemPowerState。
OEM定义的事件可能包含设备供电从外接电源切换为使用电池供电,延长系统空闲周期,将设备插入底座(Cradle),电池电量低等。OEM需要根据情况修改电源管理器,以便判断两种系统电源状态间的切换是否合理,并在必要时切换系统电源状态。Platform Builder提供的电源管理器源代码仅支持在设备从外接电源切换为使用电池供电时进行系统电源状态切换。
应用程序可以使用系统电源状态名或表示系统电源状态的数值为参数调用SetSystemPowerState函数。如果应用程序了解OEM定义的系统电源状态,那么可以选择使用电源状态名进行显式调用。对于独立于平台的应用程序,则设置数值进行调用,并允许电源管理器决定如何进行电源状态映射。电源管理器可对应用程序能请求的状态进行限制。
4.7.2.2.3   系统电源状态示例
下面的注册表片段是表示系统电源状态到设备电源状态映射的示例。
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/On]    "Default"=dword:0           ; D0    "Flags"=dword:10000         ; POWER_STATE_ON[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/UserIdle]    "Default"=dword:1           ; D1    "Flags"=dword:0[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/SystemIdle]    "Default"=dword:2           ; D2    "Flags"=dword:0[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/Suspend]    "Default"=dword:3           ; D3    "Flags"=dword:200000        ; POWER_STATE_SUSPEND; @CESYSGEN IF CE_MODULES_NDIS[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/State/Suspend/{98C5250D-C29A-4985-AE5F-AFE5367E5006}]    "Default"=dword:4           ; D4; @CESYSGEN ENDIF CE_MODULES_NDIS下表描述了上面注册表片段的映射方式。
系统电源状态
设备电源状态
On
D0
UserIdle
D1
SystemIdle
D2
Suspend
D3。NDIS迷你接口单独被映射为D4。
当系统使用上面的注册表配置,并进入Suspend状态,除了NDIS迷你接口会被关闭外,其他可唤醒源都将处于可激活状态。如果有设备不支持D3状态,它将自动进入D4状态。
应用程序可以使用SetPowerRequirement创建设备电源要求。也可以使用电源管理器控制面板程序创建附加的设备电源要求。
4.7.2.3              设备及系统电源状态名称
电源管理器要求使用小写字母命名设备及系统电源状态名称。一些类似于wsprintf(buf, "%u", n)或不区分大小写的比较这样的操作,会涉及区位表(Locale table)查询。区位表(Locale table)在Wince.nls内存映射文件中被实现。在挂起期间,电源管理器不能使用FileSystemPowerFunction访问文件系统。从挂起的线程中访问文件系统可能造成操作系统死锁。如果Wince.nls中必须的页面无法在内存中找到,就会产生死锁。
在处理API调用时,电源管理器将名称转换为小写字母。然而,在挂起及恢复状态时,电源管理器在文件系统操作被禁止后访问注册表。这时不能将注册表设置项转换为小写。所以必须将系统电源状态注册表设置改为小写字母。例如:WAV1:应被描述为wav1:。其他类似于注册表HKLM/Drivers/Builtin下的用于控制设备驱动加载的设置项不用修改。
Windows CE设备驱动开发之电源管理 第三部分
4.7.3、电源管理器接口
电源管理器有三种不同的使用者。
l         电源管理器能识别的设备的驱动程序。
l         可能需要更改系统电源状态或设备性能的应用程序。
l         需要电源事件通知的应用程序。
电源管理器使用不同的编程接口与这些使用者进行通讯。
4.7.3.1              设备驱动接口
电源管理器使用两种不同的机制与支持电源管理的设备驱动进行通讯。电源管理器向下调用设备驱动确定其设备性能,并更新其设备电源状态。设备向上调用电源管理器请求进行设备电源状态更改。向下调用在系统中以IOCTL方式实现。设备通过DevicePowerNotify API函数向上调用电源管理器。
由于电源管理器使用DeviceIoControl与支持电源管理的设备进行通讯,所以设备需要实现一个外部(expose)流接口。在某些情况下,可以用电源管理代理来实现外部流接口。网络驱动接口规约(NDIS)中实现了一个外部流接口,从而能使用RegisterPowerRelationship API函数进行对NDIS迷你接口的代理管理。电源管理器同时提供了一种与非流接口设备的通讯机制。这一方法由具有打开设备句柄、发送请求等功能的抽象层组成。例如:位于Public/Common/Oak/Drivers/Pm/Mdd/Pmdisplay.cpp的驱动程序实现了一个基于ExtEscape函数的通讯接口。
打开名称格式为COM1:、并实现了外部流接口的标准设备,可以对其进行读写。但是,电源管理器并不要求支持电源管理的设备必须使用这种命名格式;设备名称可以是任意唯一的字符串。例如:NDIS迷你接口可以被命名为VMINI1。
尽管Platform Builder提供的电源管理器仅支持流接口驱动,但OEM可以自由的实现其他的设备接口。可以为设备定义一个新的唯一类型全局标识符(GUID)来实现新的接口。不过,驱动程序在使用新接口时必须遵循标准电源管理设备驱动准则。
默认情况下,电源管理器可以发现下列GUID表示的设备类型:
l         {A32942B7-920C-486b-B0E6-92A702A99B35} 此GUID类型为普通被管理设备。
l         {8DD679CE-8AB4-43c8-A14A-EA4963FAA715} 此GUID类型为块设备。
l         {98C5250D-C29A-4985-AE5F-AFE5367E5006} 此GUID类型为NDIS设备。
应用程序可以从HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Power /Interfaces注册表键中获取可被管理的设备类型的列表。
当应用程序调用一个引用了指定设备的电源管理器API时,应用程序必须指定设备的GUID类型名。如果没有指定设备的GUID类型名,电源管理器会假定此设备为普通被管理设备类型。
有效的设备类型名需要有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修改显示驱动。
4.7.3.1.1     IOCTL设备控制符
电源管理器使用下列IOCTL码与设备通讯:
IOCTL
功能
IOCTL_POWER_CAPABILITIES
要求设备通知电源管理器它所支持的电源状态及其特性。
IOCTL_POWER_SET
要求设备更新其设备电源状态。
IOCTL_POWER_QUERY
询问设备是否准备好可以进入另外一个设备电源状态。
IOCTL_POWER_GET
要求设备通知电源管理器它现在的设备电源状态。
IOCTL_REGISTER_POWER_RELATIONSHIP
通知父设备登记它所控制的所有设备。
4.7.3.1.2     驱动到电源管理器的API函数
电源管理器为被管理设备提供下列函数,设备可以通过调用下列函数相电源管理器请求服务。
函数名
功能
DevicePowerNotify
设备驱动调用此函数请求电源管理器更新其设备电源状态。
RegisterPowerRelationship
总线驱动及其他代理电源管理器在需要拦截所有设备的电源IOCTL时调用此函数。
ReleasePowerRelationship
结束由RegisterPowerRelationship调用创建的代理关系。
4.7.3.2              应用程序接口
电源管理器提供了一些函数,使应用程序可以使用这些函数进行设备电源管理。下表中的API函数中,只有GetSystemPowerState、SetPowerRequirement及ReleasePowerRequirement是普通应用程序可以直接执行的。例如:应用程序可以调用SetSystemPowerState来挂起系统,但是电源管理器可以限制应用程序可以请求进入的系统电源状态。其他的API函数是为像控制面板这样的OEM应用程序准备的。下表是这些函数的说明。
函数名
功能
GetSystemPowerState
返回当前系统电源状态的名称。
SetSystemPowerState
请求电源管理器更改当前系统电源状态。
SetPowerRequirement
请求电源管理器将指定设备的电源状态维持在最小等级。
ReleasePowerRequirement
释放SetPowerRequirement设置的电源状态.将设备电源状态恢复到调用SetPowerRequirement之前的状态。
GetDevicePower
返回指定设备的当前电源状态。
SetDevicePower
请求电源管理器更改指定设备的当前电源状态。
4.7.3.2.1   系统电源状态设置
某些情况下,应用程序需要更改系统电源状态。在特定的Windows CE设备上,应用程序并不知道哪些电源状态可用,也不期望知道这些电源状态的特性。对应用程序而言,最好使用描述电源状态的掩码来调用SetSystemPowerState进行电源状态切换,而不要使用明确的状态名调用。电源管理器会将此掩码转换为对应的电源状态。例如:应用程序可以使用POWER_STATE_SUSPEND位元请求进行系统电源状态切换。根据在请求时系统是否在支架(cradle)中,电源管理器随后会切换到Suspend或SuspendCradle状态。如果设备被从支架中取下,电源管理器会将设备切换到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请求进入一个新的电源状态,电源管理器将进行以下处理:
l         广播PBT_TRANSITION通知。
l         如果需要更新所有设备的电源状态。如果设备已处于一个可被新的电源状态接受的电源状态下,电源管理器就不会进行IOCTL_POWER_SET请求。
l         如果设备从挂起状态恢复,电源管理器广播PBT_RESUME通知。
4.7.3.2.2   设备电源需求
在某些情况下应用程序需要改变电源管理器对系统电源状态的管理。例如:某页面调度程序需要使COM3:保持运行在D3或更高的状态,即使在挂起时也以此电源状态运行,从而在COM3:收到一个输入页时能唤醒系统。或者,例如一个流音频程序可能需要网卡及音频系统即便在系统使用电池供电,并以及空闲了一段时间的情况下也能保持在全功耗(Full Power)运行。电源管理器提供SetPowerRequirement API函数为有特定电源管理需求的应用程序提供支持。
SetPowerRequirement API函数允许应用程序请求电源管理器在设备电源状态上设置一个较低的下限。如果电源要求有效,电源管理器则不允许设备将自己的电源状态设为低于要求的下限值。当电源管理器更改系统电源状态时,如果设备需要维持在高于系统电源状态所允许的设备电源状态,电源管理器通常会使设备保持此电源状态。
当系统挂起时设备的电源需求通常会被取消。当系统处于挂起状态时,CPU将停止运行,中断服务也将停止。如果应用程序需要设备在挂起状态时能继续运行,可以在调用SetPowerRequirement时设置POWER_FORCE标记。进行此操作需要对应的设备驱动程序支持在系统挂起时自行停用。
电源管理器可能取消其他环境下的设备电源需求。例如,OEM厂商可能会重新解释系统电源状态POWER_STATE_CRITICAL标记,以便指示系统在使用电池供电,且电池处于低电量临界时,应关闭所有设备。
4.7.3.3              通知接口
电源管理器提供了一组API函数,从而允许应用程序获取电源相关事件的通知,并参与决策系统电源状态的切换。下表列出了相关的API函数。
函数
描述
RequestPowerNotifications
请求电源管理器发送电源事件通知。
StopPowerNotifications
取消由RequestPowerNotifications发出的通知请求。
通知信息通过消息队列传递。为了使用通知,应用程序需要创建一个消息队列,并通过RequestPowerNotifications API函数将消息队列句柄传递给电源管理器。通常将创建一个线程来监控消息队列,等待消息产生。
电源管理器定义了以下几种通知类型。
通知
描述
PBT_RESUME
当系统从挂起状态恢复时产生。
PBT_POWERSTATUSCHANGE
当系统在AC供电及其他供电方式(如电池)间切换时产生。
PBT_TRANSITION
当电源管理器进行系统电源状态变更时产生。
Windows CE设备驱动开发之电源管理 第四部分
4.7.4、设备电源管理指南
电源管理器对设备功耗、性能及响应时间并没有进行严格的限制。只是在用户角度而言D0及D1状态下是可操作的,而更高编号的电源状态比D0及D1消耗更少的电源。
本指南的目的是为了使OEM厂商能更容易的定义有意义的系统电源状态,而不用了解特定设备的详细功耗要求。
4.7.4.1              设备电源自管理(Device Power Self-Management)
一些设备自行管理其电源的过程可能比较复杂。当设备处于休止状态时,驱动程序开发人员希望能降低它们的功耗。降低功耗一般会同时降低设备性能,所以当这些设备被使用时,也需要提升其性能等级。提升性能的同时也会增大设备功耗。
这些设备往往根据其被使用频繁程度来动态的提升或降低其设备电源状态。但电压自管理的实际算法根据设备特性的不同而不同。
电源管理器的DevicePowerNotify API函数允许驱动开发人员请求电源管理器调整设备的电源状态。如果所请求的设备电源状态在允许的范围内(即最大及最小值之间),电源管理器将允许对设备电源状态的调整。最大值为系统电源状态要求的值,最小值由应用程序调用SetPowerRequirement API设定。
如果电源管理器设备请求的电源状态调整,电源管理器将调用对应的设备API更新设备电源状态,如:使用设备的IOCTL_POWER_SET函数。在调用DevicePowerNotify函数时,需要遵循以下要求:
l         当DevicePowerNotify调用成功后设备不能立即更新其电源状态,直到IOCTL_POWER_SET被引发时才能更新。
l         驱动开发人员不能认为DevicePowerNotify调用成功就意味着电源管理器一定会引发IOCTL_POWER_SET。
l         驱动开发人员不能认为IOCTL_POWER_SET会被作为DevicePowerNotify调用的结果而被立即引发。
l         当能够唤醒系统的设备进入D3状态后,不应再使用DevicePowerNotify来请求D3状态。
一些设备能够支持D0到D4设备电源状态以外的其他电源等级。如果需要,驱动开发人员可以将此类设备的多个电源等级映射到电源管理器所能识别的某一设备电源状态。设备可以不依赖电源管理器在每个设备电源状态的允许范围内自由的进行电源自管理。但是,设备仍然需要使用DevicePowerNotify进行设备电源状态切换。
自管理示例
对于一个实现了所有五种电源状态的设备,如果在一定的时间周期内无活动,需要动态的从D0降到D1状态,或从D1降到D2状态。这是因为D2状态的耗电量更少,而且设备很少需要响应。如果设备发觉需要活动,但其不在D0状态,设备将尝试进入D0状态。
这样一个设备的中断服务线程可能与下面的示例代码类似。
while(!fDone) {
dwStatus = WaitForSingleObject(hInterruptEvent, dwTimeout);
switch(dwStatus) {
case WAIT_OBJECT_0: // device activity
// service device
...
if(deviceDx != D0 && !fBoostRequested) {
fBoostRequested = TRUE;
DevicePowerNotify(pszDeviceName, D0, POWER_DRIVER | POWER_NAME);
}
dwTimeout = INACTIVITY_TIMEOUT;
break;
case WAIT_TIMEOUT:  // device inactive
if(deviceDx < D2 && !fReductionRequested) {
fReductionRequested = TRUE;
DevicePowerNotify(pszDeviceName, deviceDx + 1, POWER_DRIVER | POWER_NAME);
}
if(deviceDx >= D2) {
dwTimeout = INFINITE;
}
default:            // error handling
break;
}
}
设备的DeviceIoControl处理程序可能包含下列示例代码。
case IOCTL_POWER_SET:
// update device registers
...
deviceDx = *(PCEDEVICE_POWER_STATE) pOutBuf;
fBoostRequested = FALSE;
fReductionRequested = FALSE;
break;
上面驱动程序代码仅表明了是否请求了状态切换,而不是是否已经切换。这一点非常重要,因为设备可能在D2状态时请求进入D0状态,但是由于当前的电源情况,电源管理器可能仅将其设为D1状态。在下一次设备活动时,设备会再次请求进入D0状态,而电源管理器可能只允许其运行在D1状态。明白了状态切换请求的过程,能够避免在设备进入活动状态前进行额外的电源管理API调用。同样的处理逻辑也用于当设备非活动超时时电源状态降低的过程。
设备的中断服务程序在调用DevicePowerNotify函数前设置fBoostRequested和fReductionRequested标记。这是因为DevicePowerNotify调用可能导致调用IOCTL_POWER_SET而在同一线程中再次进入驱动程序。DeviceIoControl调用会清除标记,从而使驱动程序在之后能进一步调整设备电源状态。
4.7.4.2              如何为驱动程序添加电源管理(How to Add Power Management to a Device Driver)
开发者可以为驱动程序添加电源管理支持,以便能够降低目标设备的功耗。为此,驱动程序必须导出流接口。如果已经实现了流接口,那么可以开始添加电源管理支持。
硬件及软件假定
你掌握了如何从命令行创建WinCE运行时镜像。详见Build Tool
步骤
相关主题
1. 创建一个流接口驱动。
How to Create a Device Driver
2. 为流接口驱动添加IOCTLs。关于电源管理IOCTLs的更多信息,见Power Management IOCTLs.
Power-Manageable Device Drivers
3. 通知电源管理器,驱动程序支持电源管理。见Power Management Functions.

4. 在驱动程序中实现设备电源状态。关于设备电源状态的更多信息,见Device Power States.
Power Management Implementation in Drivers
5. 编译驱动程序。如果编译无错,那么你已成功为流接口驱动添加了电源管理。详见Troubleshooting: Building a Driver.
Building a Device Driver from the Command Line
6. 调试驱动程序.
How to Debug a Device Driver
4.7.4.3              电源可管理设备驱动(Power-Manageable Device Drivers)
为了创建一个支持电源管理的设备驱动程序,必须先定义一个non-COM-related设备接口。non-COM-related设备接口表示设备支持电源管理。可以使用以下方式定义这一设备接口:
l         可以在用于激活设备的注册表键的IClass值中定义接口。
l         可以使用驱动程序的Init函数在活动注册表中定义IClass值。
l         可以调用ActivateDeviceEx函数并使用REGINI参数来定义IClass值。
l         可以在驱动程序中显式的调用AdvertiseInterface。
关于为电源管理定义non-COM-related接口的更多信息,参见设备接口通知。可以通过调用RequestPowerNotifications函数为电源管理通知注册设备驱动程序,同时将句柄传递给电源管理通知专用的消息队列。如果驱动程序需要响应电源通知并进行相关处理,就必须这么做。通常情况下,一旦驱动程序实现了电源管理支持,那么此驱动只需要处理电源管理器的DeviceIoControl调用。
电源管理器通过IOCTL码与设备通讯。下表列出了电源管理器与设备通讯时使用的IOCTL码:
Function
Description
IOCTL_POWER_CAPABILITIES
请求设备驱动返回设备支持的电源状态及相关特征
IOCTL_POWER_SET
请求驱动更新设备的电源状态
IOCTL_POWER_QUERY
电源管理器询问设备是否准备好进行状态切换
IOCTL_POWER_GET
请求驱动返回当前设备的电源状态
IOCTL_REGISTER_POWER_RELATIONSHIP
通知父设备注册所有它所控制的设备
你可以实现并使用可选的IOCTL_POWER_QUERY控制码,以便在驱动程序还没有准备好改变电源状态时,延迟电源切换。你可以通过修改MDD层来支持IOCTL_POWER_QUERY,虽然这样修改可能会导致MDD层与电源管理器的未来版本不兼容。
4.7.4.4              在驱动程序中实现电源管理(Power Management Implementation in Drivers)
在配置驱动程序支持电源管理时,要确定驱动程序每个入口点的电源状态。如果确定电源状态正确无误,那么驱动程序会根据目标设备的当前电源状态以适当的方式运行。
确保在XXX_PowerUp被调用时驱动程序不会给目标设备加电。而应该恢复电源管理器设置的电源状态,很可能是D3或D4这样的状态值。同样,在XXX_PowerDown被调用时不会关闭目标设备电源。
注意:如果在挂起前目标设备一直没有加电,电源管理器也没有向其发送请求。这种情况下,驱动程序没有正确配置,所以要在驱动程序中重新配置。
4.7.4.5              在流接口驱动中实现电源管理(Power Management Implementation in Stream Interface Drivers)
在驱动程序能够支持电源管理之前,必须先导出一个流接口。导出的流接口会提供一组入口点以便实现标准文件I/O函数,这些函数会被kernel使用。
关于导出流接口的更多信息,见流接口驱动实现(Stream Interface Driver Implementation)。
除流接口函数外,驱动程序还必须支持IOCTL_POWER_CAPABILITIES和IOCTL_POWER_SET这两个IOCTL。
关于IOCTL_POWER_SET的更多信息,见IOCTL_POWER_SET请求处理(IOCTL_POWER_SET Request Processing)。
关于IOCTL_POWER_CAPABILITIE的更多信息,见设备电源特性(Device Power Capabilities)。
一旦配置了流接口,就可以进一步配置驱动程序来支持电源管理。更多信息参见 4.4在驱动程序中实现电源管理。
4.7.4.6              设备类型名(Class-Qualified Device Names)
自Windows CE .NET 4.10起,支持电源管理的设备可分属于不同的设备类型。这些设备类型由预定义类型和自定义类型组成。电源管理器API函数可以接受设备名称,也可以接受有效地设备类型名称(class-qualified device names)。例如,下面列出的每一名称都是有效的设备名称:
l         COM1:
l         {A32942B7-920C-486b-B0E6-92A702A99B35}/COM1:
l         {98C5250D-C29A-4985-AE5F-AFE5367E5006}/CISCO1
l         {8DD679CE-8AB4-43c8-A14A-EA4963FAA715}/DSK1:
如果某个设备的类型无效,那么此设备将被假定属于默认设备类型。例如,上面COM1:和{A32942B7-920C-486b-B0E6-92A702A99B35}/COM1:是等效的。
4.7.4.7              设备初始化(Device Initialization Responsibilities)
在初始化期间,设备驱动程序应将设备置为D0状态,同时在电源管理器通过IOCTL_POWER_CAPABILITIES询问时应尽可能准确的汇报设备特性。
4.7.4.8              IOCTL_POWER_SET请求处理(IOCTL_POWER_SET Request Processing)
电源管理器使用IOCTL_POWER_SET(设备的IOCTL码)来调整设备的电源状态。在实现此IOCTL码时,驱动程序开发人员应了解下列内容:
l         设备并不一定需要支持所有五种设备电源状态,但至少必须支持D0状态;如果设备仅支持D0状态,那么它也不需要处理IOCTL_POWER_SET。
l         电源管理器可能会要求设备进入任何设备电源状态,并不仅仅是设备声明支持的几个。
l         如果一个设备被要求进入一个它并不支持的电源状态,它就会进入另一个它支持的更高功耗的状态。例如,一个设备并不支持D2,它会被要求进入D1。
l         电源管理器可能会通过发出IOCTL_POWER_SET,使设备再次进入它已经处于的当前状态。在这种情况下,设备驱动程序简单的返回成功即可。
l         设备的电源状态不一定与系统的电源状态同步,因为它可能受到应用程序需求的限制。
4.7.4.9              挂起及恢复处理(Suspend and Resume Handling)
支持电源管理的流设备驱动程序通过XXX_PowerDown及XXX_PowerUp不断接收系统挂起/恢复状态通知。这些通知在内核调用OEMPowerOff之前的中断处理中发出。PowerDown/PowerUp回调机制与电源管理器无关,----。
Power managed stream device drivers will continue to receive notifications of system suspend and resume states through theirXXX_PowerDown (Device Manager) andXXX_PowerUp (Device Manager). These notifications are sent in an interrupt context just before the kernel calls OEMPowerOff. The PowerDown/PowerUp callback mechanism is independent of the Power Manager and allows legacy device drivers to function under Microsoft? Windows? CE .NET 4.0 and later.
驱动开发人员应该知道,当系统进入挂起状态,处理器将不再运行。理论上,电源管理器会根据电源状态映射,使设备进入对应的设备电源状态。然而,挂起系统电源状态或应用程序的设备电源需求可能不适合某些设备。例如,多媒体应用程序可能要求音频设备保持运行在D0状态。如果音频芯片需要频繁使用处理器设置DMA缓存,驱动开发人员可判定此设备在系统挂起状态不适合运行于D0状态,并关闭设备电源。
驱动开发者必须知道在系统处于挂起状态时设备适合使用哪些电源状态,从而依此实现其驱动程序。这一方法适合保守的驱动开发人员在系统挂起期间进行电源管理决策。但是,在系统挂起时并不是所有的设备都必须被关闭。例如,如果音频设备可以不依赖处理器播放音乐,那么它可以在系统挂起期间保持供电。
如果驱动开发人员在挂起期间改变了设备的电源状态,就必须在系统恢复的同时恢复设备的电源状态。在系统挂起期间,这些设备应尽量保证其实际行为对电源管理器而言是透明的。
当支持电源管理的流设备通过ActivateDeviceEx被加载时,可以自动通知电源管理器。在注册表HKEY_LOCAL_MACHINE/CurrentControlSet/Control/Power/Interfaces键值下的所有设备在加载时都需要通知电源管理器。如果这些设备的注册表IClass键值(REG_MULTI_SZ类型)中包含类似"{A32942B7-920C-486b-B0E6-92A702A99B35}"的GUID,那么在其被加载时电源管理器会收到通知。
设备在收到IOCTL_POWER_CAPABILITIES控制码后,可以通过调用DevicePowerNotify函数管理其自身电源。在设备处理IOCTL期间,电源管理器允许设备自行管理电源。
如果OEM厂商选择实现非流接口的设备API,就需要定制电源管理器,使其使用新的机制与设备通讯。
4.7.4.10          D3设备状态和系统唤醒(Device State D3 and System Wakeup)
D3设备电源状态需要特殊考虑,因为它并不是仅仅用于限定设备的功耗等级。设备可以运行与D3状态,从而在挂起状态时唤醒系统,但者并不是必须的。
下列指南说明了如何在驱动程序中添加D3状态支持:
l         可以从挂起状态唤醒系统的设备不应通过DevicePowerNotify请求进入D3状态。这是因为在系统进入挂起状态前,不应存在唤醒源。----。
Devices that can wake the system from a suspend state should not request the D3 state throughDevicePowerNotify. This is because enabling a device as a wake source is not always appropriate, unless the system is going to enter a suspend state. The driver cannot distinguishIOCTL_POWER_SET requests for D3 that it has initiated itself from those initiated by the Power Manager as part of a system power state transition.
l         可以将支持唤醒的设备的D2与D3状态定义为相同的电压等级,当然D2状态不支持唤醒功能。
l         不能从挂起状态唤醒系统,但是具有一个能保持设备运行最低功耗模式的设备,在电源自管理过程中可以使用D3状态。
l         如果一个非唤醒源设备运行在D3状态,并且系统挂起,那么它应在XXX_PowerDown处理过程切换到D4状态;同时在XXX_PowerUp处理中恢复到D3状态。如果做不到,就不能支持D3状态,而应在请求进入D3状态时直接切换到D4状态。
l         上述指南隐含说明了支持D3状态的设备不一定能在挂起状态唤醒系统。
总之,OEM厂商设计系统电源状态时,应用程序开发者调用SetPowerRequirement时都需要考虑系统挂起期间D3状态的特殊性。上述指南同时描述了OEM厂商和应用程序开发者可以在挂起期间要求设备进入D3状态,而不用考虑设备是否支持唤醒功能。
4.7.4.11          设备电源特性(Device Power Capabilities)
IOCTL_POWER_CAPABILITIES在即插即用设备枚举时从驱动程序中查询设备的具体特性,包括潜伏周期(latency)、功耗、系统唤醒及启动功率(Inrush)。在驱动程序响应此IOCTL时也同时汇报他所支持的设备电源状态。电源管理器一般不会要求设备进入它所不支持的电源状态。但是,驱动开发人员不能认为这种情况不会产生。因为设备制造商可以定制电源管理器,设备制造商可能会忽略POWER_CAPABILITIES结构的DeviceDx字段。
Windows CE设备驱动开发之电源管理 第五部分
4.7.1、活动定时器(Activity Timers)
在初始化时,电源管理器从注册表中读取活动定时器名称列表。对于每个定时器,电源管理器都会检查其超时时间(以秒为单位)以及可选的唤醒源列表。然后创建下列事件:
l         定时器重置事件
l         活动状态手动重置事件
l         手动重置事件
如果超时与不产生重置事件的定时器到期关联,电源管理器将重置活动事件并设置非活动事件。如果重置事件产生,电源管理器重置非活动事件并设置活动事件。
下列示例代码是配置一个活动计时器的注册表设置: [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/ActivityTimers/SystemActivity]
"Timeout"=dword:A
"WakeSources"=multi_sz:"0x20"
上面注册表设置会引发电源管理器创建三个事件,分别名为:PowerManager/ActivityTimer/SystemActivity、PowerManager/SystemActivity_Active及 PowerManager/SystemActivity_Inactive。第一个事件是一个自动重置事件,任何驱动程序都可能通过发送信号表明系统处于活动状态。支持重置活动定时器的驱动程序应从注册表中读取定时器的重置事件名称。其他两个是手动重置事件,这两个事件在同一时刻只会产生一个,而不会同时发生。驱动程序、应用程序或电源管理器自身都可能打开这些事件的句柄,以便确定定时器是否到期。这些事件表明了活动定时器的状态。重置事件是活动定时器的输入,状态事件是其对应的输出。
除了创建事件,这一注册表设置项还将一个唤醒源与此活动定时器关联。如果系统恢复,并且电源管理器确定系统是由此活动定时器对应的唤醒源所唤醒,那么此活动定时器将被置为活动。电源管理器使用IOCTL_HAL_GET_WAKE_SOURCE内核IOCTL来确定是什么设备唤醒了系统。----。。
In addition to creating events, this set of registry entries associates a wake source identifier with the activity timer. If the OS resumes and the Power Manager determines that the wake source corresponding to this ID caused the system to resume, it will set the associated activity timer to active. The Power Manager uses the IOCTL_HAL_GET_WAKE_SOURCE kernel IOCTL to determine what woke the system. The active timer allows the development workstation that is in finite state to manage OS power state transitions to use the activity timer as input. It then uses that input to make a decision as to which system power state is the most appropriate to enter during the resume process. For example, the Power Manager might enter an OS power state in which the display and backlight are off. The Power Manager enters this state so that network synchronization can occur without disturbing the user.
驱动程序可以在适当的时候重置活动定时器,而在同一时刻可能有多个驱动打开句柄来重置活动定时器事件。驱动在重置活动定时器时需要从注册表读取事件名称。OEM厂商可以对注册表进行定制,通过定制注册表,OEM厂商可以决定电源管理器如何理解驱动程序的活动。潜在的活动源包含打开句柄重置活动定时器事件的所有驱动。
会有多个线程打开句柄手动重置活动/非活动事件并等待其确定系统状态。例如,屏幕背光驱动可以使用为活动定时器创建的一对事件来判断如何控制背光的电源及亮度。
当系统挂起时,电源管理器重置正在活动的与活动定时器关联的手动重置事件。在系统恢复时,电源管理器会检测所有活动定时器,来判断是否是由与活动定时器关联的唤醒源引发了系统恢复。如果找到匹配项,就表明系统恢复是由其对应的唤醒源产生的活动事件引发的。
4.7.5.1              活动定时器行为(Activity Timer Behavior)
各种驱动程序都可以重置活动定时器,但是重置活动定时器会导致电源管理器产生一个定时器管理线程。这会给目标设备CPU造成额外负担。为了解决这个问题,当活动事件从非活动状态变位活动状态时,电源管理器在定时器超时前不会再检测重置事件。如果在此期间产生了活动事件,电源管理器不会处理而会持续等待。如果直到定时器超时都没有重置事件,那么活动定时器会到期,同时手动重置事件的状态会改变。
4.7.5.2              活动定时器超时及控制面板的电源选项(Activity Timer Time-outs and the Power Control Panel Utility)
活动定时器超时表示电源管理器在等待多长时间后可以判定某一活动源是非活动的。这会引发一个非活动事件。控制面板中的设置工具可以确定在保持非活动状态多长时间后,电源管理器会进行系统电源状态切换。
活动定时器超时时间应小于系统电源状态超时时间,但应大于预期的活动时间间隔。例如,系统状态超时可能是几分钟,而用户活动定时器可能是10秒。这样可以预防在正常操作时频繁的进行活动定时器状态切换。
控制面板的电源选项工具中列出的超时时间是累加的。也就是说,如果每个超时时间都设置为1分钟,系统会在3分钟后挂起。因为每个超时时间表示一次系统电源状态切换,而系统直到挂起会进行3次状态切换。
4.7.5.3              活动定时器事件(Activity Timer Events)
开发者可以设置在驱动程序中活动定时器事件。电源管理器在等待定时器到期期间不会等待定时器重置事件。在活动定时器超时后,电源管理器会检测在此期间是否有重置事件被设置。如果没有设置重置事件,定时器会被认为已经到期。如果有重置事件被设置,电源管理器将在此等待定时器。电源管理器仅在定时器到期且在此期间没有产生重置事件,或在非活动期间第一次产生重置事件时更新手动重置定时器事件。
如果驱动程序线程运行在较高优先级时,电源管理器的活动定时器线程不会运行,即使电源管理器正在等待定时器重置事件。默认情况下,活动定时器线程运行在THREAD_PRIORITY_ABOVE_NORMAL优先级,而大多数驱动程序运行在THREAD_PRIORITY_HIGHEST或更高优先级。这将导致活动定时器线程不能抢占驱动程序线程。
4.7.5.4              活动定时器重置(Activity Timer Resets)
可以设置电源管理器来监测哪些应用程序正在使用socket,这比仅监测socket是否连接要好。网络协议栈并没有直接支持此功能。当然,你可以创建一个线程,周期性的循环调用GetTcpStatistics和GetUdpStatistics函数来确定是否有TCP或UDP报文收发操作。如果收到或发送了报文,线程可以重置活动定时器。此线程可以实现为作为电源管理器一部分的可安装设备驱动程序;或作为某应用程序的一部分来实现。
注意:如果本地应用程序使用socket进行进程间通讯(IPC)时,GetTcpStatistics和GetUdpStatistics函数可能会返回环回通讯数据。
4.7.2、            挂起超时支持(Suspend Time-out Support)
你可能需要使WindowsCE设备处于非活动状态一段时间后进入挂起状态。可以使用以下方式进入挂起状态:
l         GWES会维持一个依据用户输入的空闲定时器(Idle timer),并在其处于非活动状态一段时间后挂起系统。这种方法用于Windows CE .NET 4.1 之前版本。
l         电源管理器可以根据活动定时器、输入电源及其他输入来管理系统电源状态。开发者可以定制电源管理器,使其能在你选择挂起(如开始菜单的挂起按钮)时挂起系统。
l         可以编写一个独立的应用程序来决定什么时候挂起系统。这种情况下,GWES和电源管理器都必须配置为不对挂起状态进行管理。
上述三种情况下,都是通过调用PowerOffSystem从而使电源管理器来挂起系统。三种情况的不同之处在于如何使系统进入挂起状态。开发者应只使用其中一种方法,以便避免GWES、电源管理器及应用程序间的冲突。
如果电源管理器正在管理系统超时,SystemIdleTimerReset函数会通知GWES不应出现屏幕保护程序。
4.7.6.1              GWES挂起超时(GWES Suspend Time-outs)
下表列出控制系统进入挂起状态的注册表键值。这些值以DWORD类型保存在注册表HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power键下。如果值为0,表示禁用此功能。
注册表值名称
默认值
描述
BattPowerOff
300 (5分钟)
表示当系统使用电池供电时,在多少秒无用户输入后会挂起系统。
ExtPowerOff
0 (禁用)
表示当系统使用外接电源供电时,在多少秒无用户输入后会挂起系统。
WakeupPowerOff
60 (1分钟)
表示当系统被非用户输入事件唤醒后(例如闹钟),在多少秒无活动时会挂起系统。
ScreenPowerOff
0 (禁用)
在GWES发送APM_POWERBROADCAST, PBT_APMUSERIDLE消息给任务栏前,多少秒无用户输入。
为了使GWES控制挂起超时,必须使用这些注册表设置。同时必须防止电源管理器控制系统挂起状态。在示例电源管理器实现中,可以通过从注册表中移除电源管理器超时定义来实现此功能。当GWES管理系统挂起超时时,它通过调用SetSystemPowerState函数使电源管理器将系统切换到挂起状态。
4.7.6.2              电源管理器挂起超时(Power Manager Suspend Time-outs)
示例电源管理器的实现依据系统电源、用户活动及系统活动进行挂起超时管理。示例电源管理器实现了超时可配置。由于电源管理器可以被OEM厂商定制,所以下列描述并不适用于所有Windows CE设备。OEM控制电源管理器如何、在什么时候改变系统电源状态。
下面列出了控制电源管理器进行系统电源状态切换的注册表值:
ACUserIdle
ACSystemIdle
ACSuspend
BattUserIdle
BattSystemIdle
BattSuspend
BatteryPoll
这些DWORD值保存在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Timeouts注册表键下。0值表示不会产生超时。示例电源管理器并没有提供忽略系统电源状态的方法,OEM可以选择实现此类方法。
为了使电源管理器能更好的管理系统电源状态,这些设置必须在注册表中出现。示例电源管理器是根据ACUserIdle进行电源管理的。
注意:为了防止GWES与电源管理器间的冲突,应禁用GWES电源管理。在电源管理器管理系统电源时,可能会限制应用程序不能进入某些系统电源状态。
Note   To prevent conflicts between GWES and the Power Manager, you need to disable GWES power management as described previously. When the Power Manager is actively managing system power, it may restrict applications from entering arbitrary system power states.
如果要刷新系统状态切换定时器,应创建一个名为PowerManager/ReloadActivityTimeouts的自动重置事件,并在此事件的处理过程中调用SetEvent。这样可以使电源管理器再次从注册表中读取状态切换定时器设置。
注册表设置:
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Timeouts]
"ACUserIdle"=dword:3c; 以秒为单位
"ACSystemIdle"=dword:12c; 以秒为单位
"ACSuspend"=dword:0; 以秒为单位
"BattUserIdle"=dword:3c; 以秒为单位
"BattSystemIdle"=dword:b4; 以秒为单位
"BattSuspend"=dword:12c; 以秒为单位
"BatteryPoll"=dword:1f4; 电池轮询间隔时间,以毫秒为单位
4.7.6.3              应用程序挂起超时(Application Suspend Time-outs)
OEM厂商有可能会编写应用程序直接对系统电源状态进行管理,而这样就不需要定制电源管理器。为此,应用程序必须禁用GWES及电源管理器的电源管理功能,并自行处理电源状态切换。禁用电源管理器及GWES电源管理功能的更多信息,参见6.2 电源管理器挂起超时。
电源管理器可能不能确定从挂起状态恢复时,应恢复到哪个电源状态。如果OEM厂商允许系统在挂起后完全恢复,那么可以不考虑这个问题。但是,如果OEM厂商需要部分唤醒系统,就可能需要修改电源管理器。