WinCE6.0 DEVICEEMULATOR BSP的BackLight驱动简析

来源:互联网 发布:php导出excel乱码问题 编辑:程序博客网 时间:2024/06/07 06:03

     这里就WinCE6.0 DEVICEEMULATOR BSP的BackLight驱动做下分析, 更多关于电源管理的内容可以参考其他资料.一篇不错的文章是:
http://www.cnblogs.com/we-hjb/archive/2010/01/27/1657973.html

 

    这是一个名称为BKL的流接口驱动,实际上流接口函数,如BKL_Open, BKL_Read, BKL_Read,BKL_Write等都未实现,只有一个空函数框架,因为背光驱动并没有数据的输入输出,而是具体的功能设置.
因此实现的就是BKL_IOControl函数,有4种IOCTL Code:IOCTL_POWER_CAPABILITIES, IOCTL_POWER_QUERY, IOCTL_POWER_SET, IOCTL_POWER_GET.
整个函数代码如下:

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("BKL: Received 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;}


   1. IOCTL_POWER_CAPABILITIES(查看背光设备支持的电源状态):
     首先检查了输出参数,然后定义了一个PPOWER_CAPABILITIES结构的指针变量PowerCaps,赋值为实际的输出buffer
PPOWER_CAPABILITIES PowerCaps = (PPOWER_CAPABILITIES)pBufOut;
PPOWER_CAPABILITIES的原型是:

typedef struct _POWER_CAPABILITIES {  UCHAR DeviceDx;  UCHAR WakeFromDx;  UCHAR InrushDx;  DWORD Power[5];  DWORD Latency[5];  DWORD Flags;} POWER_CAPABILITIES, *PPOWER_CAPABILITIES;


其中DeviceDx代表的是设备支持的电源状态位, 其他具体的成员含义可参考帮助.

memset(PowerCaps, 0, sizeof(*PowerCaps));//初始化为0PowerCaps->DeviceDx = 0x11; //support D0(on), D4(off),这里只支持这两种状态*pdwActualOut = sizeof(*PowerCaps);//实际输出数据的大小

2. IOCTL_POWER_QUERY(检查背光设备电源状态是否可查询)
通过CEDEVICE_POWER_STATE枚举类型的变量ReqDx来检查状态是否有效,其中CEDEVICE_POWER_STATE原型为:
即电源状态的定义.

typedef enum _CEDEVICE_POWER_STATE {  PwrDeviceUnspecified = -1,  D0 = 0,  D1,  D2,  D3,  D4,  PwrDeviceMaximum} CEDEVICE_POWER_STATE, *PCEDEVICE_POWER_STATE;

 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;
}

3. IOCTL_POWER_SET(改变背光电源状态)
(1) 首先获得当前的电源状态:
CEDEVICE_POWER_STATE ReqDx = *(PCEDEVICE_POWER_STATE)pBufOut;
(2) VALID_DX验证ReqDx 有效后,如果状态为D1,D2,D3则一律修改为D4(因为只支持D0,D4)
 if(ReqDx == D1 ||ReqDx == D2 || ReqDx == D3)
{
    ReqDx = D4;
}
(3) 调用SetBackLightState修改背光状态,根据ReqDx是D0与否打开或者关闭背光,并更新相应输出参数状态.
 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));
}

4.IOCTL_POWER_GET(获取背光电源状态)
参数检查后调用GetBackLightState将当前背光状态赋值给输出pBufOut
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));
}

5. SetBackLightStateGetBackLightState
接着看看SetBackLightState和GetBackLightState的具体实现.
(1) SetBackLightState
首先创建HDC句柄,然后可以通过这个句柄来访问LCD驱动, 这里调用的是ExtEscape函数来设置背光电源状态.最后删除释放该句柄.其中第二个参数为SETBACKLIGHT还是GETBACKLIGHT表示是设置还是获取背光状态.

BOOLSetBackLightState(BOOL fBacklightOn){    // Call the display driver to change the backlight state    HDC hdc = CreateDC(NULL, NULL, NULL, NULL);  // This gets us a HDC to the screen.    if (hdc == NULL)     {        return FALSE;    }    int iRet = ExtEscape(hdc, SETBACKLIGHT, sizeof(fBacklightOn), (LPCSTR)&fBacklightOn, 0, NULL);    DeleteDC(hdc);    return (iRet > 0) ? TRUE : FALSE;}


2)GetBackLightState
和SetBackLightState,通过ExtEscape来获得当前背光状态.

BOOLGetBackLightState(PCEDEVICE_POWER_STATE pState){    // Call the display driver to change the backlight state    HDC hdc = CreateDC(NULL, NULL, NULL, NULL);  // This gets us a HDC to the screen.    if (hdc == NULL)     {        return FALSE;    }    BOOL fBacklightOn;    int iRet = ExtEscape(hdc, GETBACKLIGHT, 0, NULL, sizeof(fBacklightOn), (LPSTR)&fBacklightOn);    DeleteDC(hdc);    if (iRet > 0)     {        *pState = (fBacklightOn) ? D0 : D4;        return TRUE;    }    return FALSE;}


(3)LCD驱动DrvEscape函数
调用了ExtEscape实际上调用的就是LCD驱动中的DrvEscape函数,在LCD驱动s3c2410x_lcd.cpp中可以看到,根据输入参数是SETBACKLIGHT还是GETBACKLIGHT来设置LCD寄存器来打开或者关闭背光电源.通过设置LCDCON3寄存器的第28位来设置,从而实现对背光的切换操作.

    if (iEsc == SETBACKLIGHT)    {        if (cjIn == sizeof(BOOL) && pvIn != NULL)        {            if (*(BOOL*)pvIn)            {                // Switch backlight on by clearing bit 28                m_s2410LCD->LCDCON3 &= 0xefffffff;            }            else            {                // Switch backlight off by setting bit 28                m_s2410LCD->LCDCON3 |= 0x10000000;            }            return 1;        }        return -1;    }    else if (iEsc == GETBACKLIGHT)    {        if (cjOut == sizeof(BOOL) && pvOut != NULL)        {            if (m_s2410LCD->LCDCON3 & 0x10000000) // Examine bit 28 - backlight            {                *(BOOL*)pvOut = FALSE; // bit is set:  backlight is off            }            else            {                *(BOOL*)pvOut = TRUE;  // bit is clear: backlight is on            }            return 1;        }        return -1;    }


6.注册表
在platform.reg中和BackLight相关的注册表项为:
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 !

其中 "IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"这个GUID表示的是Generic power-manageable devices
这样PM就知道该驱动是支持电源管理的了,还有几个其他类型可以在common.reg中找到.
ControlPanel/Backlight中的设置只针对控制面板中的设置,这里的背光驱动并未实现这个功能.可以在驱动中创建线程等待事件的方式来实现.这个BackLight非常简单,只实现了一个基本框架,




 




 

 



 

原创粉丝点击