📄 platform.cpp
字号:
// 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 may 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);
pOldCeilingDx = pdpr;
}
PMLOCK();
if ( fPasswordOn != gfPasswordOn ) {
if (gfGwesReady && gpfnShowStartupWindow && fPasswordOn )
gpfnShowStartupWindow();
gfPasswordOn = fPasswordOn;
}
PMUNLOCK();
// notify our state machine of this system power state change if this was
// an external request
if(!fInternal) {
PlatformUpdateSystemPowerState(SystemPowerStateChange, INFINITE);
DEBUGCHK(ghevRestartTimers != NULL);
SetEvent(ghevRestartTimers);
}
// are we suspending?
if(fSuspendSystem) {
// clear activity flags
ResetEvent(ghevUserActive);
ResetEvent(ghevSignalUserActivity);
ResetEvent(ghevSystemIdleTimerReset);
// set a flag to notify the resume thread that this was a controlled
// suspend
gfSystemSuspended = TRUE;
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME, (_T("%s: calling PowerOffSystem()\r\n"), pszFname));
PowerOffSystem(); // sets a flag in the kernel for the scheduler
Sleep(0); // so we force the scheduler to run
PMLOGMSG(ZONE_PLATFORM || ZONE_RESUME, (_T("%s: back from PowerOffSystem()\r\n"), pszFname));
// clear the suspend flag
gfSystemSuspended = FALSE;
// resume into an appropriate system power state
PlatformUpdateSystemPowerState(Resume, INFINITE);
DEBUGCHK(ghevRestartTimers != NULL);
SetEvent(ghevRestartTimers);
// tell gwes to wake up
if(gpfnGwesPowerUp != NULL && gfGwesReady) {
gpfnGwesPowerUp(fWantStartupScreen);
}
// send out resume notification
pbb.Message = PBT_RESUME;
pbb.Flags = 0;
pbb.Length = 0;
pbb.SystemPowerState[0] = 0;
GenerateNotifications((PPOWER_BROADCAST) &pbb);
}
} else {
// release the unused new state information
SystemPowerStateDestroy(pNewSystemPowerState);
while(pNewCeilingDx != NULL) {
PDEVICE_POWER_RESTRICTION pdpr = pNewCeilingDx->pNext;
PowerRestrictionDestroy(pNewCeilingDx);
pNewCeilingDx = pdpr;
}
}
}
// restore our priority if we updated it during a suspend transition
if(giSuspendPriority != 0 && iPreSuspendPriority != 0) {
PMLOGMSG(ZONE_PLATFORM, (_T("%s: restoring thread priority to %d\r\n"),
pszFname, iPreSuspendPriority));
CeSetThreadPriority(GetCurrentThread(), iPreSuspendPriority);
}
// if we're initializing, tell the management thread we're done
if(fFirstCall) {
if(ghevReloadActivityTimeouts != NULL) SetEvent(ghevReloadActivityTimeouts);
fFirstCall = FALSE;
}
return dwStatus;
}
// This routine reads a power state timeout value from the registry. The
// timeout value should be expressed in seconds; this routine returns
// the timeout value in milliseconds.
DWORD
RegReadStateTimeout(HKEY hk, LPCTSTR pszName, DWORD dwDefault)
{
DWORD dwValue, dwSize, dwStatus;
dwSize = sizeof(dwValue);
dwStatus = RegQueryTypedValue(hk, pszName, &dwValue, &dwSize, REG_DWORD);
if(dwStatus != ERROR_SUCCESS) {
dwValue = dwDefault;
} else {
if(dwValue == 0) {
dwValue = INFINITE;
} else {
if(dwValue > MAXACTIVITYTIMEOUT) {
dwValue = MAXACTIVITYTIMEOUT;
}
}
}
// convert to milliseconds
if(dwValue != INFINITE) {
dwValue *= 1000;
}
return dwValue;
}
// This routine reads the system's timeout values from the registry. It
// is called at boot time and whenever the reload event is signaled.
VOID
PlatformLoadTimeouts(VOID)
{
DWORD dwStatus;
TCHAR szPath[MAX_PATH];
HKEY hk;
SETFNAME(_T("PlatformLoadTimeouts"));
// assume default values
gdwACSuspendTimeout = DEF_ACSUSPENDTIMEOUT * 1000;
gdwACResumingSuspendTimeout = DEF_ACRESUMINGSUSPENDTIMEOUT * 1000;
gdwBattSuspendTimeout = DEF_BATTSUSPENDTIMEOUT * 1000;
gdwBattResumingSuspendTimeout = DEF_BATTRESUMINGSUSPENDTIMEOUT * 1000;
// get timeout thresholds for transitions between states
wsprintf(szPath, _T("%s\\%s"), PWRMGR_REG_KEY, _T("Timeouts"));
dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, 0, &hk);
if(dwStatus == ERROR_SUCCESS) {
// read system power state timeouts
gdwACSuspendTimeout = RegReadStateTimeout(hk, _T("ACSuspendTimeout"), DEF_ACSUSPENDTIMEOUT);
gdwACResumingSuspendTimeout = RegReadStateTimeout(hk, _T("ACResumingSuspendTimeout"), DEF_ACRESUMINGSUSPENDTIMEOUT);
gdwBattSuspendTimeout = RegReadStateTimeout(hk, _T("BattSuspendTimeout"), DEF_BATTSUSPENDTIMEOUT);
gdwBattResumingSuspendTimeout = RegReadStateTimeout(hk, _T("BattResumingSuspendTimeout"), DEF_BATTRESUMINGSUSPENDTIMEOUT);
// release resources
RegCloseKey(hk);
}
PMLOGMSG(ZONE_INIT || ZONE_PLATFORM,
(_T("%s: ACSuspendTimeout %d, ACResumingSuspendTimeout %d, BattSuspendTimeout %d, BattResumingSuspendTimeout %d\r\n"),
pszFname, gdwACSuspendTimeout, gdwACResumingSuspendTimeout, gdwBattSuspendTimeout,
gdwBattResumingSuspendTimeout));
}
// This routine returns TRUE if the PM will automatically translate POWER_STATE_SUSPEND
// requests into "unattended" mode if there are outstanding requests to enter
// unattended mode when the suspend request is made. If not, it returns FALSE.
BOOL
PlatformSuspendingToUnattendedMode(void)
{
BOOL fSuspendToUnattendedMode = TRUE;
DWORD dwStatus, dwValue, dwSize = sizeof(dwValue);
HKEY hk;
dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PWRMGR_REG_KEY, 0, 0, &hk);
if(dwStatus == ERROR_SUCCESS) {
dwStatus = RegQueryTypedValue(hk, _T("SuspendToUnattendedMode"), &dwValue,
&dwSize, REG_DWORD);
if(dwStatus == ERROR_SUCCESS && dwValue == 0) {
fSuspendToUnattendedMode = FALSE;
}
RegCloseKey(hk);
}
return fSuspendToUnattendedMode;
}
// This routine implements the main power manager event loop. This loop implements
// the power manager's response to external events, such as being docked in a cradle,
// running low on battery power, going on or off AC power, etc. This sample implementation
// simply monitors battery level changes and generates the appropriate notifications.
EXTERN_C VOID WINAPI
PlatformManageSystemPower(HANDLE hevReady)
{
BOOL fDone = FALSE;
HANDLE hEvents[7], hqNotify = NULL;
DWORD dwTimeout, dwStatus, dwNumEvents;
HMODULE hmCoreDll = NULL;
PACTIVITY_TIMER pat;
SETFNAME(_T("PlatformManageSystemPower"));
PMLOGMSG(ZONE_INIT || ZONE_PLATFORM, (_T("+%s\r\n"), pszFname));
// init globals
ghevReloadActivityTimeouts = NULL;
ghevRestartTimers = NULL;
ghevSystemIdleTimerReset = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -