WINCE电源管理

2019-07-14 01:48发布

********************************LoongEmbedded************************ 作者:LoongEmbedded(kandi) 时间:2011.03.07 类别:WINCE嵌入式系统开发 ********************************LoongEmbedded************************     1.       WINCE电源管理的架构 1 使用电源管理器,设备可以接收电源状态改变的通知,这个通知是以I/O控制的方式(IOCTL控制码)的方式来和设备驱动通信的。因为I/O控制运行在线程上下文环境中,驱动开发者可以很灵活去实现电源状态的改变。使用I/O控制的方式来管理电源也可以让设备电源状态独立于整体的OS电源状态。所以,当OS在运行的时候一些设备可以关闭,而在OS挂起的时候一些设备可以继续保持正常的工作状态。 电源管理器除了管理设备电源之外,它可以通知应用程序相关的电源事件,比如,当OS从挂起的状态恢复的时候,电源管理器会通知感兴趣的应用程序。电源管理器作为设备驱动和应用程序的中间层(传递者),它定义了OS电源状态,并且在这三者之间的通信中实现下面这些功能 OS电源状态决定了所有的设备的最大的电源消耗。 应用程序通过强制限制特定的设备最小的电源功耗来让此设备获得最小的性能水平。 电源管理器允许设备聪明地管理自己的电源,只要设备的电源等级在最大和最小的限制值之间。 如果设置最小的电源功耗大于它本身的最大值,只要应用程序需要设备,那么这个设备就会保持在高的电源功耗状态。 设备可以有一个或者多个设备电源状态,但被限制在D0D4之间。 如果OS转变为挂起的状态,应用程序决定设备的最小功耗的限制。   设备驱动可以调用DevicePowerNotify函数来调整设备自身的功耗水平,并且应用程序可以调用SetPowerRequirement来核实设备需要运行在可以受的性能水平上。   WinCE电源管理器通过一个名为Pm.dll的动态链接库与设备管理器Device.exe链接。Pm.dll动态链接库支持三类接口:一是驱动程序接口:为需要进行电源管理的设备的驱动程序使用;二是应用程序接口:为需要利用电源管理的应用程序使用;三是提醒接口(Notification):为需要接受电源事件提醒的应用程序使用。   2.       系统电源状态 系统电源状态明确指定了系统中所有设备的最大设备电源状态,并且由OEM来定义系统的电源状态,而系统电源状态大概有以下几种 on 用户与系统交互时的状态,在common.reg中的相关信息如下: 2 BacklightOff 在一段时间内,如果一直没有用户操作(比如按下某个键或者触摸屏幕),就关闭背光,这时其他的设备也可以关闭,这需要看设计的需要了,这个timeout值可以通过控制面板进行设置。   UserIdle 在一段时间内,如果一直没有用户操作,LCD屏工作在低功耗模式或者关闭显示 (这取决于OEM的设计了),在common.reg中的相关信息如下: 3 SystemIdle 用户没有直接使用系统,这种状态下认为设备处于空闲的状态,当处理器仍然在工作,比如在进行文件传输,在common.reg中的相关信息如下: 4 Suspended 睡眠状态,没有线程在运行。CPU处于idle的状态,这时候只能通过硬件的唤醒中断才能唤醒系统。 5     3.       设备电源状态 设备电源状态是预先定义的,电源管理器递给一个设备状态给设备驱动,然后这个驱动负责根据设备的能力来映射为相应的电源状态,并且让设备工作在恰当的电源状态下。 Full on D0,此状态表示设备已开启或正在运行,系统要求设备工作在最大功耗和最高性能的状态。   Low on D1,此状态表示设备已开启或正在运行,但以低于D0状态的功耗及性能运行。D1状态适用于设备已经被使用,但以较低的性能运行即可,没有必要以最大性能运行,会产生额外的功率消耗。   Standby D2,此状态表示设备被部分供电,且设备在需要时可以自动唤醒。   Sleep D3,睡眠状态。保证唤醒的最小供电,在需要时能自动唤醒并初始化。   Off D4,关闭状态,不供电。   6       4.       电源管理器接口 4.1    应用程序电源管理接口 应用程序可以利用这些接口来调整系统及设备的电源状态,这些接口中,只有GetSystemPowerState()SetPowerRequirement()ReleasePowerRequirement()函数是为一般的应用程序设计的。比如,应用程序可以调用SetSystemPowerState函数来挂起系统,但电源管理器可以限制应用程序请求系统进入挂起状态的情况,所以其他一些应用程序电源管理接口函数SetSystemPowerState()GetDevicePower   ()SetDevicePower()是为OEM应用来设计的,比如控制面板应用程序,下面来学习这些函数 GetSystemPowerState函数 这个函数用户返回系统电源状态(比如是on),在power按键驱动中加入下面的代码 dwErr = GetSystemPowerState(wPState, 20, &dFlag); 输出的wPState=on”,dFlag=0x12010000,这个dFlag的值表示什么意思呢?见下图 是在pm.h下定义的 7 SetSystemPowerState函数 SetSystemPowerState函数可被OEM程序或者其他应用程序调用,来把系统电源状态设置为需要值,相关描述见VS2005中的相关文档 8 如可以像下面一样来使用 Result = SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);   SetPowerRequirement函数   调用SetSystemPowerState是一个直接改变电源状态的方法。更巧妙的方法是通过调用SetPowerRequirement来请求系统维持应用程序所需最低限度的电源状态。SetSystemPowerState是假定应用程序知道所需状态,而调用SetPowerRequirement是允许系统对电源设定做优化以满足应用程序的需要。一个使用SetPowerRequirement会比较方便的例子是,一个使用串口的应用程序需要串口在进行通信时保持住电源状态。SetPowerRequirement被定义如下 9 第一个参数指定了应用程序需要维护电源状态的设备。DeviceState参数定义了设备的电源状态。CEDEVICE_POWER_STATE指定了状态范围是从D0(意味着设备是处于最大功耗状态)到D4(表示设备被关闭)(译者注:其实D0D4的状态的具体表现,完全是由OEM厂商可自定义的,对应用程序开发者来说,比如是在D1LCD背光还是在D2,都是不确定的,微软只给出标准定义,而不是实际定义)。DeviceFlags参数由两个标志合并而成:POWER_NAME,表示设备名有效;POWER_FORCE,表示设备应当维持当前状态甚至当系统挂起时。如果pvSystemState不为NULL,它表示只有对于在pvSystemState中已命名的电源请求才是有效的。设备可能无法更改请求的状态,应用如下: const WCHAR VideoCallDialog_t::sc_BacklightDeviceName[] = L"bkl1:"; m_BacklightPowerRequirementHandle = SetPowerRequirement(             (PVOID)(sc_BacklightDeviceName),             D0,             POWER_NAME,             NULL, 0             ); 举例来说,假设有一个条形码阅读器连接在COM1端口,并COM1只有在最高电源等级(D0)时才能驱动这个条形码阅读器。为了使其正常工作,应用程序将调用SetPowerRequirementCOM1指定D0状态。假设之后串口驱动自身决定降低一个电源等级,驱动调用DevicePowerNotify通知电源管理器它期望的设备电源状态,驱动程序的这个请求将不起作用,直到应用程序调用ReleasePowerRequirement为止。继续这个例子,假设这时的系统电源状态转换为低能耗等级,虽然与之相关的COM1电源等级为D3,由于应用程序的电源请求,COM1将继续维持在D0状态。 在调用SetPowerRequirement函数时,指定POWER_FORCE标志将强制设备不进入休眠状态,即使这时系统已处于休眠状态。   ReleasePowerRequirement函数 这个函数请求电源管理器释放SetPowerRequirement函数的电源请求,应用程序和驱动应该在停止电源请求的时候明确地释放掉此电源请求。   GetDevicePower函数 返回某个设备当前的电源状态 10   SetDevicePower函数 这个函数用于某个设备为某种电源状态,这个函数使用的时候需要注意下面的原则 If a device is requested to go into a power state that the device does not support, Power Manager sets the device power state to the next highest supported power level, where D0 (full power) is the highest level.   For example, if the D4 state is requested and the device does not support D4, then D4 is mapped to D3. If D3 is not supported, then D3 is mapped to D2 and so on. All devices must at least support D0. For more information about the power states, see CEDEVICE_POWER_STATE. The Power Manager code is located in the public/common/oak/drivers/pm directory.   4.2    设备驱动电源管理接口 电源管理器默认的实现可以检测到下面几种GUIDglobally unique identifier,全球唯一标识符),分别如下: 11 我们的工程中interfacescommon.reg中的注册表项内容如下: ; Power Manager interfaces.  These list the interface classes that the Power ; Manager will monitor for new devices. ; [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Interfaces]     "{A32942B7-920C-486b-B0E6-92A702A99B35}"="Generic power-manageable devices"     "{8DD679CE-8AB4-43c8-A14A-EA4963FAA715}"="Power-manageable block devices" ; @CESYSGEN IF CE_MODULES_NDIS     "{98C5250D-C29A-4985-AE5F-AFE5367E5006}"="Power-manageable NDIS miniports" ; @CESYSGEN ENDIF CE_MODULES_NDIS ; @CESYSGEN IF CE_MODULES_GWES     "{EB91C7C9-8BF6-4a2d-9AB8-69724EED97D1}"="Power-manageable display" ; @CESYSGEN ENDIF CE_MODULES_GWES   电源管理器用两种机制来和支持电源管理的驱动通信: 4.2.1电源管理器调用DeviceIoControl控制设备电源状态 电源管理器通过DeviceIoControl及对应的ControlCode可以查询设备支持电源管理的能力及可以更新设备的电源状态,电源管理器使用下面的控制码来和设备通信 IOCTL_POWER_CAPABILITIES 电源管理器请求设备驱动返回设备支持的电源状态及相关特征. IOCTL_POWER_SET 请求设备驱动更新设备的电源状态。 IOCTL_POWER_QUERY 电源管理器询问设备是否做好状态更新的准备。 IOCTL_POWER_GET 请求驱动返回设备当前的电源状态。 IOCTL_REGISTER_POWER_RELATIONSHIP 通知父设备注册所有它所控制的设备。 4.2.2设备可以请求电源管理器来改变自身的电源状态 电源管理器提供下面的函数用于支持电源管理的设备来向电源管理器请求电源服务: DevicePowerNotify函数 设备驱动通过DevicePowerNotify函数请求系统改变它们的电源状态,这个时候电源管理模块就用调用相应的IOCTL(比如IOCTL_POWER_SET)来实现电源状态的管理,比如camera驱动中的应用如下,在初始化函数CIS_Init中调用: DevicePowerNotify(_T("CIS1:"),(_CEDEVICE_POWER_STATE)D0, POWER_NAME);   RegisterPowerRelationship函数 用于建立动态的父设备及其子设备的关系,或者是总线及客户端驱动的关系,这样设备驱动就可以管理一系列依赖的子和客户端驱动。 12   ReleasePowerRelationship函数 释放RegisterPowerRelationship函数返回的句柄。     5.       电源管理的实现 5.1    电源管理器对应的组件 13 电源管理器对应的代码在/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/PM下面   5.2    在需要的设备驱动中添加电源管理功能 不是所有的设备驱动都需要支持电源管理功能的,这需要根据设备的特性来决定,但是为了让Power Manager知道哪些驱动是支持电源管理功能的,需要在注册表中包含相应的键值(IClass)或者在驱动初始化时调用AdvertiseInterface()。一般来说,流驱动用注册表键值比较方便一些,而显示驱动通常用AdvertiseInterface()来告知。流驱动和显示驱动在实现电源管理的功能上也有所不同。流驱动主要是在XXX_IOControl中,实现IOCTL_POWER_CAPABILITIESIOCTL_POWER_QUERYIOCTL_POWER_SETIOCTL_POWER_GET,而显示驱动主要是在DrvEscape中实现以上几个IoControlCode,另外需要注意在QUERYESCSUPPORT添加相应的IoControlCode,下面是支持电源管理的I2C驱动在platform.reg中的注册表内容 14 我们可以到my device->control panel->power->device status下来查看系统中哪些驱动支持电源管理功能,见下图 15 5.3    在驱动和应用程序中添加相应的支持 在驱动的DeviceIoControl中实现4.2中提到的“设备驱动电源管理接口“,而在应用程序中通过调用电源管理的API,协助系统管理各个设备和整个系统的工作状态。具体的细节可以参考BSP包中的支持电源管理的驱动及微软自带的应用程序了。         WINCE电源管理 http://www.cnblogs.com/we-hjb/archive/2010/01/27/1657973.html   WINCE 电源管理中的应用程序API http://www.xici.net/#d120135354.htm   WINCE 设备驱动中实现电源管理 http://apps.hi.baidu.com/share/detail/5889365     CSDN帖子 http://topic.csdn.net/u/20100123/16/a070bb34-3415-459c-96f4-65250cf87319.html