背光驱动程序设计
1. 这里硬件接口使用S3C2450的GPB1,即定时器1.
定时器的输入频率 = PCLK /{prescaler value + 1} / {divider value}。
首先设置prescaler value:
- static void BAK_SetPrescaleAndMux( DWORD v_Prescale, DWORD v_Mux )
- {
- // Set prescale.
- if(v_Prescale<=255)
- {
- v_pPWMRegs->TCFG0 = v_pPWMRegs->TCFG0 & (~0xff) | v_Prescale;
- }
- // Set divider value.Timer1 is used
- switch(v_Mux)
- {
- case 1:// 1/2
- v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x0<<4);
- break;
- case 2:// 1/4
- v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x1<<4);
- break;
- case 3:// 1/8
- v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x2<<4);
- break;
- case 4:// 1/16
- v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x3<<4);
- break;
- case 5:
- default:// External TCLK0
- v_pPWMRegs->TCFG1 = v_pPWMRegs->TCFG1 & (~0xF0) | (0x4<<4);
- break;
- }
- }
然后设置divider value:
- static void BAK_SetTCNTB( DWORD v_Tcntb)
- {
- if(v_Tcntb<=0xffff)
- {
- v_pPWMRegs->TCNTB1 = v_Tcntb;
- }
- }
2. 接着设置TOUT1的定时器PWM脉宽:
- static void BAK_SetTCMPB( DWORD v_Tcmpb)
- {
- if(v_Tcmpb<=0xffff)
- {
- v_pPWMRegs->TCMPB1 = v_Tcmpb;
- }
- }
3. 设置完这些就可以开启TOUT1了。代码如下:
- static void BAK_StartPwmTimer( void )
- {
- // Set GPB1 to TOUT1.
- v_pIOPregs->GPBCON &= ~(0x03<<2);
- v_pIOPregs->GPBCON |= (0x02<<2);
- // Stop pwm timer 1, first.
- v_pPWMRegs->TCON &= ~(0xF<<8);
- v_pPWMRegs->TCON |= (0x6<<8); // 这里0x2<<8也OK吧!!!!!
- // Start it again.
- v_pPWMRegs->TCON &= ~(0xF<<8);
- v_pPWMRegs->TCON |= (0x9<<8);
- }
4. 背光亮度调节代码如下(将亮度设置为10个级别):
- static void BAK_AdjuctBacklightLevel(DWORD v_Level)
- {
- if((v_Level>=BAK_LEVEL_MIN)&&(v_Level<=BAK_LEVEL_MAX))// v_Level=[1:10]
- {
- l_dwBackLightLevel = v_Level;
- BAK_SetTCMPB((l_dwTcntb * la_dwLevel[v_Level-1])/100);
- }
- }
5.以上事情都做完了后,就可以编写通用的流接口程序了。由于程序比较简单,这里
仅贴上XXX_IOControl的代码如下:
- BOOL BAK_IOControl(
- DWORD hOpenContext,
- DWORD dwCode,
- PBYTE pBufIn,
- DWORD dwLenIn,
- PBYTE pBufOut,
- DWORD dwLenOut,
- PDWORD pdwActualOut
- )
- {
- DWORD dwErr = ERROR_INVALID_PARAMETER;
- BOOL bRc;
- RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL code = %d/r/n"), dwCode));
- switch (dwCode)
- {
- case IOCTL_POWER_CAPABILITIES: // determines device-specific capabilities
- RETAILMSG(DBGBAK, (TEXT("[lqm:BKL] 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 = 0x12; //support D0, D1, D4
- *pdwActualOut = sizeof(*PowerCaps);
- bRc = TRUE;
- dwErr = ERROR_SUCCESS;
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- RETAILMSG(DBGBAK1, (TEXT("<BKL> exception in ioctl/r/n")));
- }
- }
- else
- bRc = FALSE;
- break;
- case IOCTL_POWER_QUERY: // determines whether changing power state is feasible
- RETAILMSG(DBGBAK, (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.
- bRc = TRUE;
- dwErr = ERROR_SUCCESS;
- }
- else
- {
- bRc = FALSE;
- }
- RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_QUERY %s/r/n"), dwErr == ERROR_SUCCESS ? (TEXT("succeeded")) : (TEXT("failed")) ));
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
- }
- }
- else
- bRc = FALSE;
- break;
- case IOCTL_POWER_SET: // requests a change from one device power state to another
- RETAILMSG(lqm_bakdbg, (TEXT("[lqm: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))
- {
- RETAILMSG(lqm_bakdbg,(TEXT("[lqm:BKL] Received IOCTL_POWER_SET=%d/r/n"), ReqDx));
- if( ReqDx == (CEDEVICE_POWER_STATE)D2 || ReqDx == (CEDEVICE_POWER_STATE)D3)
- bklStatus = (CEDEVICE_POWER_STATE)D4;
- else
- bklStatus = ReqDx;
- //SetEvent(g_evtBacklight);
- // 调整亮度值后调用函数执行调整
- BAK_hw_setBL();
- *(PCEDEVICE_POWER_STATE) pBufOut = bklStatus;
- *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
- bRc = TRUE;
- dwErr = ERROR_SUCCESS;
- RETAILMSG(lqm_bakdbg, (TEXT("[lqm:BKL] IOCTL_POWER_SET to D%d /r/n"), ReqDx));
- }
- else
- {
- bRc = FALSE;
- RETAILMSG(DBGBAK1, (TEXT("<BKL> Invalid state request D%d/r/n"), ReqDx));
- }
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
- }
- }
- else
- {
- bRc = FALSE;
- }
- break;
- case IOCTL_POWER_GET: // gets the current device power state
- RETAILMSG(DBGBAK, (TEXT("<BKL> Received IOCTL_POWER_GET/r/n/n")));
- if (pBufOut != NULL && dwLenOut >= sizeof(CEDEVICE_POWER_STATE))
- {
- __try
- {
- *(PCEDEVICE_POWER_STATE)pBufOut = getBacklightStatus();
- bRc = TRUE;
- dwErr = ERROR_SUCCESS;
- RETAILMSG(DBGBAK, (TEXT("<BKL> IOCTL_POWER_GET: passing back %u/r/n"), getBacklightStatus()));
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- RETAILMSG(DBGBAK1, (TEXT("<BKL> Exception in ioctl/r/n")));
- }
- }
- else
- bRc = FALSE;
- break;
- // 背光亮度调节
- case IOCTL_BACKLIGHT_ADJUST:
- if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
- {
- DWORD dwBackLight = *((DWORD*)pBufOut);
- if((BAK_LEVEL_MAX <dwBackLight) || (BAK_LEVEL_MIN > dwBackLight ))
- {
- *(DWORD*)pBufOut = ERROR_INVALID_PARAMETER;
- *pdwActualOut = sizeof(DWORD);
- bRc = FALSE;
- }
- else
- {
- BAK_AdjuctBacklightLevel(*(DWORD*)pBufOut);
- // Adjust backlight level.
- *(DWORD*)pBufOut = ERROR_SUCCESS;
- *pdwActualOut = sizeof(DWORD);
- bRc = TRUE;
- }
- }
- else
- {
- bRc = FALSE;
- }
- break;
- case IOCTL_BACKLIGHT_GETLEVEL:
- if (pBufOut != NULL && (dwLenOut>=sizeof(DWORD)))
- {
- // Return the current backlight level.
- *(DWORD*)pBufOut = l_dwBackLightLevel;
- *pdwActualOut = sizeof(DWORD);
- bRc = TRUE;
- }
- else
- {
- bRc = FALSE;
- }
- break;
- }
- return(bRc);
- }
可以看到有如下几个case:
IOCTL_POWER_CAPABILITIES;
IOCTL_POWER_QUERY;
IOCTL_POWER_SET;
IOCTL_POWER_GET;
IOCTL_BACKLIGHT_ADJUST;
IOCTL_BACKLIGHT_GETLEVEL;
其中
IOCTL_POWER_CAPABILITIES:代表电源管理器请求设备驱动返回设备支持的电源状态及相关特征;
IOCTL_POWER_SET:请求驱动更新设备的电源状态;
IOCTL_POWER_QUERY:电源管理器询问设备是否准备好进行状态切换;
IOCTL_POWER_GET:请求驱动返回当前设备的电源状态;
IOCTL_BACKLIGHT_ADJUST:调节背光亮度的接口;
IOCTL_BACKLIGHT_GETLEVEL:获取背光亮度级别的接口。