在wince6.0里有一个电源控制模块驱动(Power Controller Driver),该模块主要是反映和控制系统电源状态,以及控制系统硬件模块的电源状态。该驱动也是典型的流式驱动,提供以下接口:
其中主要的是PWC_Init和PWC_IOControl,其余的那些函数都是空函数,仅仅提供接口而已。那接下来我们就来分析PWC_Init和PWC_IOControl.
1.PWC_Init
if (AllocResources() == FALSE)
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->AllocResources() Failed /n"), _T(__FUNCTION__)));
goto CleanUp;
}
PwrCon_initialize_register_address((void *)g_pPmConReg, (void *)g_pSysConOthersReg);
// Create power Monitor Thread, Singleton
g_hThreadPowerMon = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) PowerMonitorThread, NULL, 0, NULL);
if (g_hThreadPowerMon == NULL )
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->CreateThread() Power Monitor Failed /n"), _T(__FUNCTION__)));
goto CleanUp;
}
#ifdef DVFS
if (!(DVFS_Init()))
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->DVFS_Init() Failed /n"), _T(__FUNCTION__)));
goto CleanUp;
}
g_pDVFSArgs = (volatile S5PC100_DVFS_ARGS *)IMAGE_SHARE_DVFS_ARGS_UA_START;
#endif // DVFS
DEBUGMSG(PWC_ZONE_INIT,(_T("[PWRCON:INF] --%s()/n"), _T(__FUNCTION__)));
return TRUE;
CleanUp:
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] --%s : Failed/n"), _T(__FUNCTION__)));
PWC_Deinit(0);
return FALSE;
}
该函数主要是做一些初始化操作,包括初始化电源控制寄存器和硬件模块控制寄存器(包括摄像头、JPEG解码器、TVOUT、IP电话等)。
寄存器的初始化主要是通过MmMapIoSpace将寄存器的地址映射到虚拟地址空间。接着创建系统电源监视线程:
g_hThreadPowerMon = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) PowerMonitorThread, NULL, 0, NULL);
if (g_hThreadPowerMon == NULL )
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->CreateThread() Power Monitor Failed /n"), _T(__FUNCTION__)));
goto CleanUp;
}
也就是说系统电源状态的监视和设置是在该线程中完成的,PowerMonitorThread函数具体代码如下:
RETAILMSG(PWC_ZONE_ENTER, (_T("[PWRCON:INF] ++%s/n"), _T(__FUNCTION__)));
eRstStat = PwrCon_get_reset_status();
//-------------------------------------------------
// Set Power Monitor Thread Priority
//-------------------------------------------------
CeSetThreadPriority(g_hThreadPowerMon, POWER_MONITOR_THREAD_PRIODITY);
//-------------------------------------------------
// Create a message queue for Power Manager notifications.
//-------------------------------------------------
memset((void *)&msgOptions, 0x0, sizeof(msgOptions));
msgOptions.dwSize = sizeof(MSGQUEUEOPTIONS);
msgOptions.dwFlags = 0;
msgOptions.dwMaxMessages = QUEUE_ENTRIES;
msgOptions.cbMaxMessage = sizeof(POWER_BROADCAST) + MAX_NAMELEN;
msgOptions.bReadAccess = TRUE;
g_hMsgQueue = CreateMsgQueue(NULL, &msgOptions);
if (g_hMsgQueue == NULL )
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->CreateMsgQueue() Failed : Err %d/n"), _T(__FUNCTION__), GetLastError()));
goto Thread_CleanUp;
}
// Request Power notifications
hPowerNotification = RequestPowerNotifications(g_hMsgQueue, POWER_NOTIFY_ALL);
if (!hPowerNotification)
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->RequestPowerNotifications() Failed : Err %d/n"), _T(__FUNCTION__), GetLastError()));
goto Thread_CleanUp;
}
memset(msgBuf, 0x0, QUEUE_SIZE);
pB = (PPOWER_BROADCAST)msgBuf;
while(!g_bExitThread)
{
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWR:INF] PowerMonitorThread() : Wait for PM Notification/n")));
// Read message from queue.
bRet = ReadMsgQueue(g_hMsgQueue, msgBuf, QUEUE_SIZE, &iBytesInQueue, INFINITE, &dwFlags);
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWR:INF] %s() : Read Size:%d/r/n"), _T(__FUNCTION__), iBytesInQueue));
if (!bRet)
{
if (g_bExitThread)
{
break;
}
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s->ReadMsgQueue() Failed : Err %d/n"), _T(__FUNCTION__), GetLastError()));
}
else if (iBytesInQueue < sizeof(POWER_BROADCAST))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s->Receive Insufficient Message (Size is %d, Expected %d)/n"), _T(__FUNCTION__), iBytesInQueue, sizeof(POWER_BROADCAST)));
}
else
{
switch (pB->Message)
{
//-----------------------
// Notified State Transition
//-----------------------
case PBT_TRANSITION:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_TRANSITION : %s (0x%08x)]/n"), pB->SystemPowerState, pB->Flags));
break;
//-----------------------
// Notified Resume State
//-----------------------
case PBT_RESUME:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_RESUME]/n")));
{
DWORD dwWakeSrc = SYSWAKE_UNKNOWN;
DWORD dwBytesRet = 0;
if (KernelIoControl(IOCTL_HAL_GET_WAKE_SOURCE, NULL, 0, &dwWakeSrc, sizeof(dwWakeSrc), &dwBytesRet)
&& (dwBytesRet == sizeof(dwWakeSrc)))
{
switch(dwWakeSrc)
{
case SYSWAKE_POWER_BUTTON: // Power Button
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Power Button/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_RTC_ALARM:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by RTC Alarm/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
// Do not change Power State to POWER_STATE_ON
break;
case OEMWAKE_RTC_TICK:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by RTC Tick/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_KEYPAD:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Keypad/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_MSM:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by MSM I/F/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_BATTERY_FAULT:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Battery Fault/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_WARM_RESET:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Warm Reset/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_HSI:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by HSI I/F/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] WakeUp Source = 0x%08x/n"), dwWakeSrc));
break;
}
}
else
{
NKDbgPrintfW(L"PWRCON: Error getting wake source/n");
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] IOCTL_HAL_GET_WAKE_SOURCE Failed/n")));
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] System is Still in [PBT_RESUME] State/n")));
}
}
break;
//-----------------------------------
// Notified Power Supply changed (AC/DC)
//-----------------------------------
case PBT_POWERSTATUSCHANGE:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_POWERSTATUSCHANGE]/n")));
break;
//---------------------------------
// Notified Power Information changed
//---------------------------------
case PBT_POWERINFOCHANGE:
{
PPOWER_BROADCAST_POWER_INFO ppbpi;
ppbpi = (PPOWER_BROADCAST_POWER_INFO)pB->SystemPowerState;
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Notified [PBT_POWERINFOCHANGE]/n")));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] ACLine Status : %d/n"), ppbpi->bACLineStatus));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Battery Flag : %d/n"), ppbpi->bBatteryFlag));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Backup Flag : %d/n"), ppbpi->bBackupBatteryFlag));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Level : %d/n"), ppbpi->dwNumLevels));
break;
}
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] Notified Unknown Message [0x%08x]/n"), pB->Message));
break;
}
}
}
Thread_CleanUp:
if (hPowerNotification)
{
StopPowerNotifications(hPowerNotification);
hPowerNotification = NULL;
}
if (g_hMsgQueue)
{
CloseMsgQueue(g_hMsgQueue);
g_hMsgQueue = NULL;
}
RETAILMSG(PWC_ZONE_ENTER, (_T("[PWRCON:INF] --%s/n"), _T(__FUNCTION__)));
return 0;
}
该函数看起来虽然复杂,但结构和流程上去不复杂。首先要明白一点,系统电源的变化是通过消息事件机制通信的,因此必须要创建一个消息队列: g_hMsgQueue = CreateMsgQueue(NULL, &msgOptions);其中的参数msgOptions是一个消息队列结构体,它定义了该队列的属性:
typedef MSGQUEUEOPTIONS_OS{
DWORD dwSize;
DWORD dwFlags;
DWORD dwMaxMessages;
DWORD cbMaxMessage;
BOOL bReadAccess;
} MSGQUEUEOPTIONS, FAR* LPMSGQUEUEOPTIONS, *PMSGQUEUEOPTIONS;
消息通信机制在wince中是很重要的一点,通过它可以实现驱动程序之间,驱动程序与应用程序之间的通信。
接着又是一个很重要的函数:
// Request Power notifications
hPowerNotification = RequestPowerNotifications(g_hMsgQueue, POWER_NOTIFY_ALL);
if (!hPowerNotification)
{
RETAILMSG(PWC_ZONE_ERROR,(_T("[PWRCON:ERR] %s->RequestPowerNotifications() Failed : Err %d/n"), _T(__FUNCTION__), GetLastError()));
goto Thread_CleanUp;
}
函数equestPowerNotifications使电源管理器在发现系统电源状态变化时向它发出通知,即电源状态变化了!它的第一个参数就是上面创建消息队列时得到的句柄,第二个参数POWER_NOTIFY_ALL意思是获取电源任何变化的通知。
到这里基本工作已经完成,即创建了消息队列,也告诉了电源管理器当系统电源状态改变时发出通知。那么接下来要做的就是接受这些通知并进行相应的操作。这部分主要代码如下:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_TRANSITION : %s (0x%08x)]/n"), pB->SystemPowerState, pB->Flags));
break;
//-----------------------
// Notified Resume State
//-----------------------
case PBT_RESUME:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_RESUME]/n")));
{
DWORD dwWakeSrc = SYSWAKE_UNKNOWN;
DWORD dwBytesRet = 0;
if (KernelIoControl(IOCTL_HAL_GET_WAKE_SOURCE, NULL, 0, &dwWakeSrc, sizeof(dwWakeSrc), &dwBytesRet)
&& (dwBytesRet == sizeof(dwWakeSrc)))
{
switch(dwWakeSrc)
{
case SYSWAKE_POWER_BUTTON: // Power Button
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Power Button/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_RTC_ALARM:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by RTC Alarm/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
// Do not change Power State to POWER_STATE_ON
break;
case OEMWAKE_RTC_TICK:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by RTC Tick/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_KEYPAD:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Keypad/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_MSM:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by MSM I/F/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_BATTERY_FAULT:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Battery Fault/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_WARM_RESET:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by Warm Reset/n")));
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/n")));
SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
case OEMWAKE_HSI:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Wake Up by HSI I/F/n")));
//PWRCON_INF((_T("[PWRCON:INF] SetSystemPowerState(POWER_STATE_ON)/r/n")));
//SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
break;
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] WakeUp Source = 0x%08x/n"), dwWakeSrc));
break;
}
}
else
{
NKDbgPrintfW(L"PWRCON: Error getting wake source/n");
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] IOCTL_HAL_GET_WAKE_SOURCE Failed/n")));
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] System is Still in [PBT_RESUME] State/n")));
}
}
break;
//-----------------------------------
// Notified Power Supply changed (AC/DC)
//-----------------------------------
case PBT_POWERSTATUSCHANGE:
RETAILMSG(PWC_ZONE_TEMP, (_T("[PWRCON:INF] Notified [PBT_POWERSTATUSCHANGE]/n")));
break;
//---------------------------------
// Notified Power Information changed
//---------------------------------
case PBT_POWERINFOCHANGE:
{
PPOWER_BROADCAST_POWER_INFO ppbpi;
ppbpi = (PPOWER_BROADCAST_POWER_INFO)pB->SystemPowerState;
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Notified [PBT_POWERINFOCHANGE]/n")));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] ACLine Status : %d/n"), ppbpi->bACLineStatus));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Battery Flag : %d/n"), ppbpi->bBatteryFlag));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Backup Flag : %d/n"), ppbpi->bBackupBatteryFlag));
RETAILMSG(PWC_ZONE_TEMP,(_T("[PWRCON:INF] Level : %d/n"), ppbpi->dwNumLevels));
break;
}
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] Notified Unknown Message [0x%08x]/n"), pB->Message));
break;
这里是通过轮询的方式去查看是否有电源状态改变的消息,该函数是:ReadMsgQueue(g_hMsgQueue, msgBuf, QUEUE_SIZE, &iBytesInQueue, INFINITE, &dwFlags);如果读到了消息就返回相应的值,否则返回NULL.
得到相应的消息后就要进行处理了,这里采用的是结构清晰的switch-case语句,即不同的消息进行不同的处理或打印出提示信息这部分比较简单,这里就不在多少。有一点要提醒,当推出线程的时候记得停止接受电源管理器的消息和关闭消息队列的句柄:
StopPowerNotifications(hPowerNotification);
CloseMsgQueue(g_hMsgQueue);
当该驱动程序被加载以后上述监视线程就开始工作了,直到被关闭。从其代码可以看出,该监视线程只能监视系统电源状态的变化并不能进行控制。那么如何去控制系统的电源状态和系统硬件模块的电源状态呢?很显然要用到PWC_IOControl了。
2。PWC_IOControl
PWC_IOControl就是驱动程序提供给上层应用程序的接口用来控制系统和硬件模块的的电源状态。怎么控制呢?发命令!详细大家对XXX_IOControl的结构十分清晰,我也列出器代码:
if ( !( (dwCode == IOCTL_PWRCON_SET_POWER_ON)
|| (dwCode == IOCTL_PWRCON_SET_POWER_OFF)
#ifdef DVFS
|| (dwCode == IOCTL_DVFS_SET_LEVEL_FIX)
|| (dwCode == IOCTL_DVFS_CLEAR_LEVEL_FIX)
|| (dwCode == IOCTL_DVFS_SET_PROFILE)
|| (dwCode == IOCTL_DVFS_CLEAR_PROFILE)
#endif // DVFS
))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s : Unknown IOCTL [0x%08x]/n"), _T(__FUNCTION__), dwCode));
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
switch(dwCode)
{
case IOCTL_PWRCON_SET_POWER_ON:
if ((dwLenIn < sizeof(DWORD)) || (NULL == pBufIn))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_PWRCON_SET_POWER_ON) : Invalid Parameter/n"),_T(__FUNCTION__)));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
break;
}
dwIndex = (DWORD)(*pBufIn);
EnterCriticalSection(&csPowerCon);
switch(dwIndex)
{
case PWR_IP_MIPICSI:
case PWR_IP_MIPIDSI:
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : MIPI DPhy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_MIPI_Dphy(TRUE, dwIndex);
// intentionally go through
case PWR_IP_ROTATOR: // LCD Sub system
case PWR_IP_JPEG:
case PWR_IP_CAMIF0:
case PWR_IP_CAMIF1:
case PWR_IP_CAMIF2:
case PWR_IP_DISPCON:
case PWR_IP_G2D:
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_ON,(_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : LCD Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_on(BLKPWR_DOMAIN_LCD);
break;
case PWR_IP_VP:
case PWR_IP_HDMI:
case PWR_IP_MIXER:
case PWR_IP_TVENC:
case PWR_IP_TVSC:
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_ON,(_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : TV Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_on(BLKPWR_DOMAIN_TV);
break;
case PWR_IP_MFC: // Domain MFC
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_ON,(_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : MFC Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_on(BLKPWR_DOMAIN_MFC);
break;
case PWR_IP_G3D: // Domain G3D
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_ON,(_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : G3D Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_on(BLKPWR_DOMAIN_G3D);
break;
case PWR_IP_USBPHY:
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : USB Phy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_USB_phy(TRUE);
break;
case PWR_IP_MIPIDPHY:
g_aIPPowerStatus[dwIndex] = TRUE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_ON, %d) : MIPI DPhy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_MIPI_Dphy(TRUE, dwIndex);
break;
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_PWRCON_SET_POWER_ON, %d) : Invalid Parameter/n"), _T(__FUNCTION__), dwIndex));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
}
LeaveCriticalSection(&csPowerCon);
break;
case IOCTL_PWRCON_SET_POWER_OFF:
if ((dwLenIn < sizeof(DWORD)) || (NULL == pBufIn))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_PWRCON_SET_POWER_OFF) : Invalid Parameter/n"), _T(__FUNCTION__)));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
break;
}
dwIndex = (DWORD)(*pBufIn);
EnterCriticalSection(&csPowerCon);
switch(dwIndex)
{
case PWR_IP_MIPICSI:
case PWR_IP_MIPIDSI:
g_aIPPowerStatus[dwIndex] = FALSE;
if((g_aIPPowerStatus[PWR_IP_MIPICSI] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_MIPIDSI] == FALSE))
{
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : MIPI DPhy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_MIPI_Dphy(FALSE, dwIndex);
}
// intentionally go through
case PWR_IP_ROTATOR: // LCD Sub system
case PWR_IP_JPEG:
case PWR_IP_CAMIF0:
case PWR_IP_CAMIF1:
case PWR_IP_CAMIF2:
case PWR_IP_DISPCON:
case PWR_IP_G2D:
g_aIPPowerStatus[dwIndex] = FALSE;
if ( (g_aIPPowerStatus[PWR_IP_ROTATOR] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_JPEG] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_CAMIF0] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_CAMIF1] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_CAMIF2] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_MIPICSI] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_MIPIDSI] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_DISPCON] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_G2D] == FALSE)
)
{
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : LCD Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_off(BLKPWR_DOMAIN_LCD);
}
break;
case PWR_IP_VP:
case PWR_IP_HDMI:
case PWR_IP_MIXER:
case PWR_IP_TVENC:
case PWR_IP_TVSC:
g_aIPPowerStatus[dwIndex] = FALSE;
if ( (g_aIPPowerStatus[PWR_IP_VP] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_HDMI] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_MIXER] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_TVENC] == FALSE)
&& (g_aIPPowerStatus[PWR_IP_TVSC] == FALSE) )
{
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : TV Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_off(BLKPWR_DOMAIN_TV);
}
break;
case PWR_IP_MFC: // Domain MFC
g_aIPPowerStatus[dwIndex] = FALSE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : MFC Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_off(BLKPWR_DOMAIN_MFC);
break;
case PWR_IP_G3D: // Domain G3D
g_aIPPowerStatus[dwIndex] = FALSE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : G3D Subsystem/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_block_power_off(BLKPWR_DOMAIN_G3D);
break;
case PWR_IP_USBPHY:
g_aIPPowerStatus[dwIndex] = FALSE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : USB Phy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_USB_phy(FALSE);
break;
case PWR_IP_MIPIDPHY:
g_aIPPowerStatus[dwIndex] = FALSE;
RETAILMSG(PWC_ZONE_BLK_PWR_OFF, (_T("[PWRCON:INF] %s(SET_POWER_OFF, %d) : MIPI DPhy/n"), _T(__FUNCTION__), dwIndex));
PwrCon_set_MIPI_Dphy(FALSE, dwIndex);
break;
default:
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(SET_POWER_OFF, %d) : Invalid Parameter/n"), _T(__FUNCTION__), dwIndex));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
}
LeaveCriticalSection(&csPowerCon);
break;
#ifdef DVFS
case IOCTL_DVFS_SET_LEVEL_FIX:
if ((dwLenIn < sizeof(DWORD)) || (NULL == pBufIn))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_DVFS_SET_LEVEL_FIX) : Invalid Parameter/n"),_T(__FUNCTION__)));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
break;
}
dwIndex = (DWORD)(*pBufIn);
EnterCriticalSection(&csPowerCon);
#if (TARGET_ARM_CLK == CLK_834MHz)
if((dwIndex <= SYS_L4) && (dwIndex >= SYS_L0))
#else
if((dwIndex <= SYS_L3) && (dwIndex >= SYS_L0))
#endif
{
PWC_DVFSSetTransitLock(dwIndex);
}
LeaveCriticalSection(&csPowerCon);
break;
case IOCTL_DVFS_CLEAR_LEVEL_FIX:
EnterCriticalSection(&csPowerCon);
PWC_DVFSSetTransitUnlock();
LeaveCriticalSection(&csPowerCon);
break;
case IOCTL_DVFS_SET_PROFILE:
if ((dwLenIn < sizeof(DWORD)) || (NULL == pBufIn))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_PWRCON_SET_POWER_ON) : Invalid Parameter/n"),_T(__FUNCTION__)));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
break;
}
dwIndex = (DWORD)(*pBufIn);
EnterCriticalSection(&csPowerCon);
PWC_PofileHandler(dwIndex, TRUE);
LeaveCriticalSection(&csPowerCon);
break;
case IOCTL_DVFS_CLEAR_PROFILE:
if ((dwLenIn < sizeof(DWORD)) || (NULL == pBufIn))
{
RETAILMSG(PWC_ZONE_ERROR, (_T("[PWRCON:ERR] %s(IOCTL_PWRCON_SET_POWER_ON) : Invalid Parameter/n"),_T(__FUNCTION__)));
SetLastError (ERROR_INVALID_PARAMETER);
bRet = FALSE;
break;
}
dwIndex = (DWORD)(*pBufIn);
EnterCriticalSection(&csPowerCon);
PWC_PofileHandler(dwIndex, FALSE);
LeaveCriticalSection(&csPowerCon);
break;
#endif // DVFS
代码虽然长,但并不复杂,逻辑上还是很简单的。从其代码可以看出它的控制操作主要分为两种:IOCTL_PWRCON_SET_POWER_ON,IOCTL_PWRCON_SET_POWER_OFF,即关闭电源和打开电源。这两种操作是针对所以硬件模块来做的,没有具体到控制其中的一个硬件模块,如摄像头。当然我们可以添加自己的命令进行更为灵活的电源控制。
整体来看该驱动比较简单,难点就是怎么把它用活,用巧。