原文地址::http://www.cnblogs.com/we-hjb/archive/2010/01/27/1657973.html

对于移动设备来说,电源管理是比较重要的。为了让设备有更长的待机和工作时间,实现一个完善的电源管理功能也是必须的。针对移动平台的操作系统WinCE本身包括了一个基本的电源管理子模块"Powe Manager",可以在Catalog中添加至系统。驱动和应用程序将通过它有效的管理各个设备或者整个系统的电源工作状态。最近,在我们TCC8900的平台上实现了简单的电源管理,积累了一些经验,在这里跟大家分享一下。

在WinCE系统中实现电源管理主要有三步,添加"Power Manager"组件,在驱动中实现电源管理的接口,在应用程序中通过调用电源管理的API控制各设备和系统的工作状态。

第一步比较简单,通常只要在Catalog中添加就可以。如果有特殊需求,可以移植C:\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\PM下的代码到BSP,并做相应的修改。

第二步主要是在现有的驱动上添加电源管理的功能。对于驱动来说,并不要求必须包括电源管理的功能,完全可以不实现,具体情况具体分析。为了让Power Manager知道哪些驱动是支持电源管理功能的,需要在注册表中包含相应的键值(IClass)或者在驱动初始化时调用AdvertiseInterface()。一般来说,流驱动用注册表键值比较方便一些,而显示驱动通常用AdvertiseInterface()来告知。流驱动和显示驱动在实现电源管理的功能上也有所不同。流驱动主要是在XXX_IOControl中,实现IOCTL_POWER_CAPABILITIES、IOCTL_POWER_QUERY、IOCTL_POWER_SET和IOCTL_POWER_GET。具体代码可以参考C:\WINCE600\PLATFORM\DEVICEEMULATOR\SRC\DRIVERS\BACKLIGHT,非常好的一个例子。而显示驱动主要是在DrvEscape中实现以上几个IoControlCode,另外需要注意在QUERYESCSUPPORT添加相应的IoControlCode。这个代码可以参考C:\WINCE600\PLATFORM\COMMON\SRC\SOC\PXA27X_MS_V1\DISPLAY\PXA27X_LCD,也是非常好的一个例子。以上这两个参考代码的框架都基本完善,在做移植时根据具体的情况实现相应的功能即可。如果成功实现了这两步,就可以在控制面板的电源属性中看到相应的设备了。如下图所示。

第三步主要就是在应用程序中通过调用电源管理的API,协助系统管理各个设备和整个系统的工作状态。

一般来说,外设的工作状态主要有以下几个Full On 、Low On、Standby、Sleep 和Off,分别对应D0、D1、D2、D3和D4。他们的映射关系和其他一些关于电源管理的配置在注册表[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Power]中定义。这里需要注意的是应用程序如何修改系统的超时时间设置,键值在[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Power\Timeouts]下,仅仅修改注册表中的键值并不能实时生效,应用程序通过注册表读写API修改该键下的DWORD值(十六进制以秒为单位),完成修改后,必须通知PM使用新设置的超时时间,实现的参考代码如下:

    HANDLE hReloadActivityTimeouts ;
    hReloadActivityTimeouts = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("PowerManager/ReloadActivityTimeouts"));
     if (hReloadActivityTimeouts)
    {
        SetEvent(hReloadActivityTimeouts);
        CloseHandle(hReloadActivityTimeouts);
    }

如果实现了HIVE注册表,由于系统启动时PM的启动先于文件系统,所以在PM启动时它还不能读取到文件系统中保存的值,在系统启动完成后也需要通知一下系统重新加载我们设定的值。这个操作可以放在驱动或者应用程序中。

应用程序中常用的几个电源管理API如下:

  • DevicePowerNotify 用于改变设备的电源状态
  • SetPowerRequirement 用于请求保持设备的电源状态
  • ReleasePowerRequirement 释放已请求设备的电源管理
  • SetSystemPowerState 用于设置整个系统的电源状态
  • RequestPowerNotifications 注册一个消息队列接收电源状态变化的通知
  • StopPowerNotifications 停止接收电源变化的通知

需要注意的是,驱动不能擅自改变自己的电源状态,而必须请求PM来处理。

PM中通过Timer进行状态切换的过程如下图所示。

最后附上M8手机的电源属性图,可以看到好的产品对电源管理做得有多细。

电源管理是一个非常复杂也非常重要的内容。以上是我在学习过程中的一些经验,抛砖引玉,希望大家能有更多的讨论。

//==================================================

备注::

1>为了让Power Manager知道哪些驱动是支持电源管理功能的,需要在注册表中包含相应的键值(IClass)或者在驱动初始化时调用AdvertiseInterface()。

2>流驱动主要是在XXX_IOControl中,实现IOCTL_POWER_CAPABILITIES、IOCTL_POWER_QUERY、IOCTL_POWER_SET和IOCTL_POWER_GET。具体代码可以参考C:\WINCE600\PLATFORM\DEVICEEMULATOR\SRC\DRIVERS\BACKLIGHT,非常好的一个例子。而显示驱动主要是在DrvEscape中实现以上几个IoControlCode,另外需要注意在QUERYESCSUPPORT添加相应的IoControlCode。这个代码可以参考C:\WINCE600\PLATFORM\COMMON\SRC\SOC\PXA27X_MS_V1\DISPLAY\PXA27X_LCD,也是非常好的一个例子。以上这两个参考代码的框架都基本完善,在做移植时根据具体的情况实现相应的功能即可。

3>IF BSP_NOBACKLIGHT !
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Backlight]
    "Prefix"="BKL"
    "Dll"="backlight.dll"
    "Index"=dword:1
    "Order"=dword:1
    "IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"

; Backlight tab of Display control panel (timeouts in seconds)
[HKEY_CURRENT_USER\ControlPanel\Backlight]
    "BatteryTimeout"=dword:3c ; 60 seconds
    "BacklightOnTap"=dword:1
    "ACTimeout"=dword:258 ; 600 seconds
    "ACBacklightOnTap"=dword:1
ENDIF BSP_NOBACKLIGHT !

4>extern "C" BOOL BKL_IOControl(
    DWORD hOpenContext,
    DWORD dwCode,
    PBYTE pBufIn,
    DWORD dwLenIn,
    PBYTE pBufOut,
    DWORD dwLenOut,
    PDWORD pdwActualOut )
{
    DWORD dwErr = ERROR_INVALID_PARAMETER;

RETAILMSG(ZONE_BACKLIGHT,(TEXT("BKL_IOControl IOCTL code  = %d\r\n"), dwCode));

switch (dwCode) {
    case IOCTL_POWER_CAPABILITIES:  // determines device-specific capabilities
        RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_CAPABILITIES\r\n")));
        if (pBufOut && dwLenOut >= sizeof (POWER_CAPABILITIES) && pdwActualOut) 
        {
            __try 
            {
                PPOWER_CAPABILITIES PowerCaps = (PPOWER_CAPABILITIES)pBufOut;
 
                // Right now supports D0 (permanently on) and D4(off) only.
 
                memset(PowerCaps, 0, sizeof(*PowerCaps));
                PowerCaps->DeviceDx = 0x11; //support D0, D4
                *pdwActualOut = sizeof(*PowerCaps);
                
                dwErr = ERROR_SUCCESS;
            }
            __except(EXCEPTION_EXECUTE_HANDLER) 
            {
                RETAILMSG(ZONE_BACKLIGHT, (TEXT("exception in ioctl\r\n")));
            }
        }
        break;
 
    case IOCTL_POWER_QUERY: // determines whether changing power state is feasible
            RETAILMSG(ZONE_BACKLIGHT,(TEXT("BKL: Received IOCTL_POWER_QUERY\r\n")));
            if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
                // Return a good status on any valid query, since we are always ready to
                // change power states (if asked for state we don't support, we move to next highest, eg D3->D4).
                __try 
                {
                    CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
 
                    if (VALID_DX(ReqDx)) 
                    {
                        // This is a valid Dx state so return a good status.
                        dwErr = ERROR_SUCCESS;
                    }
 
                    RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_QUERY %s\r\n"), dwErr == ERROR_SUCCESS ? (TEXT("succeeded")) : (TEXT("failed")) ));
                }
                __except(EXCEPTION_EXECUTE_HANDLER) 
                {
                    RETAILMSG(ZONE_BACKLIGHT, (TEXT("Exception in ioctl\r\n")));
                }
            }
            break;
 
        break;
 
    case IOCTL_POWER_SET: // requests a change from one device power state to another
            RETAILMSG(ZONE_BACKLIGHT,(TEXT("BKL: Received IOCTL_POWER_SET\r\n")));
            if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
                __try 
                {
                    CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
 
                    if (VALID_DX(ReqDx)) 
                    {
                        if(ReqDx == D1 ||ReqDx == D2 || ReqDx == D3) 
                        {
                            ReqDx = D4;
                        }
 
                        if (SetBackLightState(D0 == ReqDx ? TRUE : FALSE)) 
                        {
                            *(PCEDEVICE_POWER_STATE) pBufOut = ReqDx;
                            *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
 
                            dwErr = ERROR_SUCCESS;
                            RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_SET to D%u \r\n"), ReqDx));
                        }
                        else
                        {
                            dwErr = GetLastError();
                            RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_SET failed to switch to D%u\r\n"), ReqDx));
                        }
                    }
                    else 
                    {
                        RETAILMSG(ZONE_BACKLIGHT, (TEXT("Invalid state request D%u\r\n"), ReqDx));
                    }
                }
                __except(EXCEPTION_EXECUTE_HANDLER) 
                {
                    RETAILMSG(ZONE_BACKLIGHT, (TEXT("Exception in ioctl\r\n")));
                }
            }
            break;
    
        break;
 
    case IOCTL_POWER_GET: // gets the current device power state
           RETAILMSG(ZONE_BACKLIGHT,(TEXT("BKL: Received IOCTL_POWER_GET\r\n")));
            if (pBufOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
                __try 
                {
                    if (GetBackLightState((PCEDEVICE_POWER_STATE)pBufOut)) 
                    {
                        dwErr = ERROR_SUCCESS;
 
                        RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_GET: passing back %u\r\n"), *(PCEDEVICE_POWER_STATE)pBufOut));
                    }
                    else
                    {
                        dwErr = GetLastError();
                        RETAILMSG(ZONE_BACKLIGHT, (TEXT("IOCTL_POWER_GET: failed to get backlight state\r\n")));
                    }
                }
                __except(EXCEPTION_EXECUTE_HANDLER) 
                {
                    RETAILMSG(ZONE_BACKLIGHT, (TEXT("Exception in ioctl\r\n")));
                }
            }
 
        break;

default:
        break;
    }

if (dwErr) 
    {
        RETAILMSG(ZONE_BACKLIGHT, (TEXT("Ioctl failed - err=%d\r\n"), dwErr));
        return FALSE;
    }
    return TRUE;
}

WinCE电源管理----驱动增加电源管理属性相关推荐

  1. linux驱动编写(电源管理驱动)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 对于嵌入式设备来说,合适的电源管理,不仅可以延长电池的寿命,而且可以省电,延长设备运行时间,在提 ...

  2. 关闭linux服务器电源,linux关闭ACPI电源管理模块

    一.运行环境 # cat /etc/redhat-release CentOS release 6.2 (Final) # uname -a Linux web-server- 2.6.-.el6.x ...

  3. linux 电池管理软件,Linux电源管理(2)_Generic PM之基本概念和软件架构

    Linux电源管理(2)_Generic PM之基本概念和软件架构 作者:wowo 发布于:2014-5-13 19:24 分类:电源管理子系统 1. 前言 这里的Generic PM,是蜗蜗自己起的 ...

  4. SylixOS电源管理之外设功耗管理

    1.前言 在这个世界中,任何系统的运转都需要能量.如树木依靠光能生长,如马儿依靠食物奔跑,如计算机系统依靠电能运行.而能量的获取是有成本的,因此如果能在保证系统运转的基础上,尽量节省对能量的消耗,就会 ...

  5. CC2640R2F学习笔记(四.电源管理:用电源管理开发应用程序)

    文章目录 前言 一.电源管理默认工作情况 1. Power Manager Initialization 2.Driver Initialization, Constraint Management, ...

  6. nxp电源管理芯片:nxp管理芯片的缺货与涨价

    在高能量和周边温度下,热反馈可以控制充电电流,降低芯片温度.nxp电源管理芯片的充电电压限制在4.2V,充电电流由外接电阻调节.达到目标充电电压后,当充电电流下降到设定值的1/10时,nxp管理芯片会 ...

  7. 高性能任务的强大桌面计算机,win7怎么设置电源管理?win7电源高性能设置方法...

    win7怎么设置电源管理?在Windows7系统中功能中, Windows7电源管理比较强大,不过不少网友不知道Windows7电源管理在哪?更不知道怎么设置,这对这些问题,下面,U大侠小编就给大家介 ...

  8. (Mirage系列之五)Mirage经典案例之桌面驱动和基础层管理

    在前面的博客 集中管理桌面 中我们介绍了如何在Mirage环境下集中管理桌面.创建了CVD(Centralized Virtual Desktop,指终端桌面在Mirage服务器上的备份)之后,就应该 ...

  9. IOC操作Bean管理XML方式(外部属性文件)

    目录 IOC操作Bean管理XML方式(外部属性文件) 前情引入: 实验演示: 1.直接配置数据库信息 (1)配置德鲁伊连接池 (2)引入德鲁伊连接池jar包 (3)创建一个bean6.xml配置文件 ...

最新文章

  1. 在 Linux 上模拟系统负载
  2. 用python玩转数据第四周答案_2020大学mooc用Python玩转数据课后答案
  3. JAVA编程经验汇总 (载)
  4. 云计算技术背后的天才程序员:Open VSwitch鼻祖Martin Casado
  5. oracle中的存储过程教程,oracle 存储过程
  6. lxml库的基本使用-etree解析html得到对象的不同方式-0233
  7. php登录后自动退出登录,PHP利用Cookie设置用户30分钟未操作自动退出功能
  8. libevent evbuffer缓冲源码分析
  9. android网络请求分析工具,android网络数据请求
  10. Idea部署web项目 与 eclipse 的不同之处
  11. 在2022年如何将整个维基百科下载到U盘中
  12. 一、Vulkan开发理论基础知识
  13. [技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?
  14. 获取 RRD 文件的信息
  15. openssl1.0.1 完美 升级到 1.0.1g脚本
  16. 利用CSS浮动制作一个简易导航栏
  17. linux系统漏洞测试过程,Linux下bash破壳漏洞检测方法
  18. Popush前端小优化——岳一飞
  19. mac系统常用操作指南
  20. 什么是增值电信业务经营户许可证?

热门文章

  1. oracle创建表,序列,触发器,自动生成唯一主键
  2. G - 锘爷考驾照
  3. [USACO09OCT]木瓜的丛林Papaya Jungle
  4. 第三局 猥琐发育 黑铁晋级赛了 加油
  5. PPAPI插件与Node 插件对比
  6. 3344 数据结构实验之二叉树五:层序遍历
  7. 阿里开出一元店,和名创优品的新零售之战即将落幕?
  8. Wing IDE 解决鼠标悬浮
  9. 惠普服务器怎么挂载虚拟光驱,虚拟光驱怎么用 虚拟光驱的安装步骤和载入镜像的方法...
  10. rabbitmq自动及手动ACK