WinCE6.0 DEVICEEMULATOR BSP的BackLight驅動簡析

     這裏就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));//初始化爲0
PowerCaps->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表示是設置還是獲取背光狀態.

BOOL
SetBackLightState(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來獲得當前背光狀態.

BOOL
GetBackLightState(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非常簡單,只實現了一個基本框架,




 




 

 



 

發佈了19 篇原創文章 · 獲贊 3 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章