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 their XXX_PowerDown (Device Manager) and XXX_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 through DevicePowerNotify. 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 distinguish IOCTL_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字段。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Fenstein/archive/2009/01/10/3746375.aspx