📄 platform.cpp
字号:
} else {
gdwStateTimeLeft = gdwBattTimeoutToUserIdle;
}
}
break;
case UserIdle:
pszNewState = _T("useridle");
if(fChangingActivityStates) {
if(fOnACPower) {
gdwStateTimeLeft = gdwACTimeoutToSystemIdle;
} else {
gdwStateTimeLeft = gdwBattTimeoutToSystemIdle;
}
}
break;
case SystemActive:
pszNewState = _T("systemidle");
gdwStateTimeLeft = INFINITE;
break;
case SystemInactive:
pszNewState = _T("systemidle");
if(fOnACPower) {
gdwStateTimeLeft = gdwACTimeoutToSuspend;
} else {
gdwStateTimeLeft = gdwBattTimeoutToSuspend;
}
break;
case Suspend:
pszNewState = _T("suspend");
gdwStateTimeLeft = INFINITE;
break;
}
// update elapsed time
if(!fChangingActivityStates && gdwStateTimeLeft != INFINITE) {
if(gdwStateTimeLeft > dwElapsedTime) {
gdwStateTimeLeft -= dwElapsedTime;
} else {
gdwStateTimeLeft = 0;
}
}
// are we changing states or forcing an update?
PMLOGMSG(ZONE_PLATFORM && fChangingActivityStates,
(_T("%s: entering activity state '%s', state time left %d\r\n"), pszFname,
gActivityState == UserActive ? _T("UserActive") :
gActivityState == UserInactive ? _T("UserInactive") :
gActivityState == UserIdle ? _T("UserIdle") :
gActivityState == SystemActive ? _T("SystemActive") :
gActivityState == SystemInactive ? _T("SystemInactive") :
gActivityState == Suspend ? _T("Suspend") : _T("<UNKNOWN>"), gdwStateTimeLeft));
if(dwElapsedTime == INFINITE
|| gpSystemPowerState == NULL
|| _tcscmp(pszNewState, gpSystemPowerState->pszName) != 0) {
PMLOGMSG(ZONE_PLATFORM, (_T("%s: %supdate from activity state %d to activity state %d\r\n"),
pszFname, dwElapsedTime == INFINITE ? _T("forced ") : _T(""),
gActivityState, asNew));
} else {
// no update necessary
pszNewState = NULL;
}
PMUNLOCK();
// update the system power state if necessary
if(pszNewState != NULL) {
PmSetSystemPowerState_I(pszNewState, 0, 0, TRUE);
}
return gdwStateTimeLeft;
}
// This routine reads and verifies system power state information from
// the registry, then updates all devices appropriately. The caller of this
// routine should hold the system power state critical section. The fInternal
// flag indicates whether the call originated within the PM or outside it.
EXTERN_C DWORD WINAPI
PlatformSetSystemPowerState(LPCTSTR pszName, BOOL fForce, BOOL fInternal)
{
DWORD dwStatus = ERROR_SUCCESS;
PSYSTEM_POWER_STATE pNewSystemPowerState = NULL;
PDEVICE_POWER_RESTRICTION pNewCeilingDx = NULL;
BOOL fDoTransition = FALSE;
INT iPreSuspendPriority = 0;
static BOOL fFirstCall = TRUE;
SETFNAME(_T("PlatformSetSystemPowerState"));
// read system power state variables and construct new lists
if (gfFileSystemsAvailable)
PmUpdateSystemPowerStatesIfChanged();
dwStatus = RegReadSystemPowerState(pszName, &pNewSystemPowerState, &pNewCeilingDx);
// did we get registry information about the new power state?
if(dwStatus == ERROR_SUCCESS) {
BOOL fSuspendSystem = FALSE;
BOOL fWantStartupScreen = FALSE;
DWORD dwNewStateFlags = pNewSystemPowerState->dwFlags;
BOOL fPasswordOn = ((dwNewStateFlags & POWER_STATE_PASSWORD)!=0) ;
// assume we will update the system power state
fDoTransition = TRUE;
// Are we going to suspend the system as a whole?
if((dwNewStateFlags & (POWER_STATE_SUSPEND | POWER_STATE_OFF | POWER_STATE_CRITICAL | POWER_STATE_RESET)) != 0) {
fSuspendSystem = TRUE;
}
// A "critical" suspend might mean we have totally lost battery power and need
// to suspend really quickly. Depending on the platform, OEMs may be able
// to bypass driver notification entirely and rely on xxx_PowerDown() notifications
// to suspend gracefully. Or they may be able to implement a critical suspend
// kernel ioctl. This sample implementation is very generic and simply sets the
// POWER_FORCE flag, which is not used.
if(dwNewStateFlags & (POWER_STATE_CRITICAL | POWER_STATE_OFF | POWER_STATE_RESET)) {
fForce = TRUE;
}
// should we allow the transition?
if(gfActiveManagement && !fInternal && !fSuspendSystem) {
// We are actively managing system power, the request update request came
// from outside the PM, and the request is not to suspend the system.
// Only permit this update if it is to set the system power state to its
// current value (for example, to refresh its settings from the registry).
PMLOCK();
if(gpSystemPowerState != NULL
&& _tcscmp(gpSystemPowerState->pszName, pNewSystemPowerState->pszName) != 0) {
fDoTransition = FALSE;
dwStatus = ERROR_ACCESS_DENIED;
}
PMUNLOCK();
}
// if everything seems ok, do the set operation
if(fDoTransition) {
POWER_BROADCAST_BUFFER pbb;
PDEVICE_LIST pdl;
BOOL fResumeSystem = FALSE;
// send out system power state change notifications
pbb.Message = PBT_TRANSITION;
pbb.Flags = pNewSystemPowerState->dwFlags;
pbb.Length = _tcslen(pNewSystemPowerState->pszName) + 1; // char count not byte count for now
if(pbb.Length > MAX_PATH) {
// truncate the system power state name -- note, we actually have MAX_PATH + 1
// characters available.
pbb.Length = MAX_PATH;
}
_tcsncpy(pbb.SystemPowerState, pNewSystemPowerState->pszName, pbb.Length);
pbb.Length *= sizeof(pbb.SystemPowerState[0]); // convert to byte count
GenerateNotifications((PPOWER_BROADCAST) &pbb);
// are we suspending?
if(fSuspendSystem && gpfnGwesPowerDown != NULL) {
// is GWES ready?
if(!gfGwesReady) {
DEBUGCHK(ghevGwesReady != NULL);
if(WaitForSingleObject(ghevGwesReady, 0) == WAIT_OBJECT_0) {
gfGwesReady = TRUE;
CloseHandle(ghevGwesReady);
ghevGwesReady = NULL;
}
}
// Start the process of suspending GWES
if(gfGwesReady) {
fWantStartupScreen = gpfnGwesPowerDown();
}
}
// update global system state variables
PMLOCK();
PSYSTEM_POWER_STATE pOldSystemPowerState = gpSystemPowerState;
PDEVICE_POWER_RESTRICTION pOldCeilingDx = gpCeilingDx;
if(gpSystemPowerState != NULL
&& (gpSystemPowerState->dwFlags & (POWER_STATE_SUSPEND | POWER_STATE_OFF | POWER_STATE_CRITICAL)) != 0) {
// we are exiting a suspended state
fResumeSystem = TRUE;
}
gpSystemPowerState = pNewSystemPowerState;
gpCeilingDx = pNewCeilingDx;
PMUNLOCK();
// are we suspending, resuming, or neither?
if(fSuspendSystem) {
INT iCurrentPriority;
// we're suspending; update all devices other than block devices,
// in case any of them need to access the registry or write files.
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME,
(_T("%s: suspending - notifying non-block drivers\r\n"), pszFname));
for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) {
if(*pdl->pGuid != idBlockDevices) {
UpdateClassDeviceStates(pdl);
}
}
// Notify the kernel that we are about to suspend. This gives the
// kernel an opportunity to clear wake source flags before we initiate
// the suspend process. If we don't do this and a wake source interrupt
// occurs between the time we call PowerOffSystem() and the time
// OEMPowerOff() is invoked it is hard for the kernel to know whether or
// not to suspend.
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME,
(_T("%s: calling KernelIoControl(IOCTL_HAL_PRESUSPEND)\r\n"), pszFname));
KernelIoControl(IOCTL_HAL_PRESUSPEND, NULL, 0, NULL, 0, NULL);
iCurrentPriority = CeGetThreadPriority(GetCurrentThread());
DEBUGCHK(iCurrentPriority != THREAD_PRIORITY_ERROR_RETURN);
if(iCurrentPriority != THREAD_PRIORITY_ERROR_RETURN) {
CeSetThreadPriority(GetCurrentThread(), giPreSuspendPriority);
Sleep(0);
CeSetThreadPriority(GetCurrentThread(), iCurrentPriority);
}
// Notify file systems that their block drivers will soon go away. After making
// this call, this thread is the only one that can access the file system
// (including registry and device drivers) without blocking. Unfortunately,
// this API takes and holds the file system critical section, so other threads
// attempting to access the registry or files may cause priority inversions.
// To avoid priority problem that may starve the PM, we can raise our own priority
// to a high level. Do this if giSuspendPriority is non-zero.
if(giSuspendPriority != 0) {
iPreSuspendPriority = CeGetThreadPriority(GetCurrentThread());
DEBUGCHK(iPreSuspendPriority != THREAD_PRIORITY_ERROR_RETURN);
PMLOGMSG(ZONE_PLATFORM,
(_T("%s: suspending: raising thread priority for 0x%08x from %d to %d\r\n"),
pszFname, GetCurrentThreadId(), iPreSuspendPriority, giSuspendPriority));
CeSetThreadPriority(GetCurrentThread(), giSuspendPriority);
}
FileSystemPowerFunction(FSNOTIFY_POWER_OFF);
gfFileSystemsAvailable = FALSE;
// update block device power states
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME,
(_T("%s: suspending - notifying block drivers\r\n"), pszFname));
pdl = GetDeviceListFromClass(&idBlockDevices);
if(pdl != NULL) {
UpdateClassDeviceStates(pdl);
}
// Handle resets and shutdowns here, after flushing files. Since Windows CE does
// not define a standard mechanism for handling shutdown (via POWER_STATE_OFF),
// OEMs will need to fill in the appropriate code here. Similarly, if an OEM does
// not support IOCTL_HAL_REBOOT, they should not support POWER_STATE_RESET.
if((dwNewStateFlags & POWER_STATE_RESET) != 0) {
// is this to be a cold boot?
if(_tcscmp(pszName, _T("coldreboot")) == 0) {
SetCleanRebootFlag();
}
// should not return from this call, but if we do just suspend the system
KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
RETAILMSG(TRUE, (_T("PM: PlatformSetSystemPowerState: KernelIoControl(IOCTL_HAL_REBOOT) returned!\r\n")));
DEBUGCHK(FALSE); // break into the debugger
}
} else if(fResumeSystem) {
// we're waking up from a resume -- update block device power states
// so we can access the registry and/or files.
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME,
(_T("%s: resuming - notifying block drivers\r\n"), pszFname));
pdl = GetDeviceListFromClass(&idBlockDevices);
if(pdl != NULL) {
UpdateClassDeviceStates(pdl);
}
// Notify file systems that their block drivers are back.
FileSystemPowerFunction(FSNOTIFY_POWER_ON);
gfFileSystemsAvailable = TRUE;
// update all devices other than block devices
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME,
(_T("%s: resuming - notifying block drivers\r\n"), pszFname));
for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) {
if(*pdl->pGuid != idBlockDevices) {
UpdateClassDeviceStates(pdl);
}
}
} else {
// update all devices without any particular ordering
UpdateAllDeviceStates();
}
// release the old state information
SystemPowerStateDestroy(pOldSystemPowerState);
while(pOldCeilingDx != NULL) {
PDEVICE_POWER_RESTRICTION pdpr = pOldCeilingDx->pNext;
PowerRestrictionDestroy(pOldCeilingDx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -