您的位置:首页 > 其它

WinCE6.0 DEVICEEMULATOR BSP的BackLight驱动简析

2013-04-16 09:53 501 查看
http://blog.csdn.net/shevsten/article/details/6204924

这里就WinCE6.0 DEVICEEMULATOR BSP的BackLight驱动做下分析, 更多关于电源管理的内容可以参考其他资料.一篇不错的文章是:

/article/4741294.html

首先在GEC2410.bat中打开BackLight的支持

set BSP_NOBACKLIGHT=

这是一个名称为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.

整个函数代码如下:

[c-sharp] view
plaincopy

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;

}

函数结构很简单,我们根据IOCTL Code分成4部分来看:

1. IOCTL_POWER_CAPABILITIES(查看背光设备支持的电源状态):

首先检查了输出参数,然后定义了一个PPOWER_CAPABILITIES结构的指针变量PowerCaps,赋值为实际的输出buffer

PPOWER_CAPABILITIES PowerCaps = (PPOWER_CAPABILITIES)pBufOut;

PPOWER_CAPABILITIES的原型是:

[c-sharp] view
plaincopy

typedef struct _POWER_CAPABILITIES {

UCHAR DeviceDx;

UCHAR WakeFromDx;

UCHAR InrushDx;

DWORD Power[5];

DWORD Latency[5];

DWORD Flags;

} POWER_CAPABILITIES, *PPOWER_CAPABILITIES;

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

[c-sharp] view
plaincopy

memset(PowerCaps, 0, sizeof(*PowerCaps));//初始化为0

PowerCaps->DeviceDx = 0x11; //support D0(on), D4(off),这里只支持这两种状态

*pdwActualOut = sizeof(*PowerCaps);//实际输出数据的大小

这个IOCTL会在驱动加载时被PM调用来获取设备驱动支持的电源状态.

2. IOCTL_POWER_QUERY(检查背光设备电源状态是否可查询)

通过CEDEVICE_POWER_STATE枚举类型的变量ReqDx来检查状态是否有效,其中CEDEVICE_POWER_STATE原型为:

即电源状态的定义.

[c-sharp] view
plaincopy

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表示是设置还是获取背光状态.

[c-sharp] view
plaincopy

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来获得当前背光状态.

[c-sharp] view
plaincopy

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位来设置,从而实现对背光的切换操作.

[c-sharp] view
plaincopy

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;

}

代码部分就分析到这里,并不复杂.驱动实际上会被应用程序或者Power Manager调用来进行背光电源管理.

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非常简单,只实现了一个基本框架,一个更复杂的例子可以参考PXA270的BSP(MAINSTONEIII).

7. 应用程序测试

新建一个SubProject,我们用SetDevicePower来设置背光状态,首先设置为D4(off),然后设置为D0(on).

[c-sharp] view
plaincopy

int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])

{

SetDevicePower(TEXT("BKL1:"), POWER_NAME, D4);

Sleep(3000);

SetDevicePower(TEXT("BKL1:"), POWER_NAME, D0);

Sleep(3000);

_tprintf(_T("Hello World!/n"));

return 0;

}

这时可以看到KITL输出的从BackLight驱动和LCD驱动设置的打印信息:



不过WinCE建议用户尽量避免使用SetDevicePower该函数,改为使用SetPowerRequirement,由外设的驱动程序根据实际情况设置外设的设备电源状态.这里仅仅是测试驱动使用.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: