Ejemplo n.º 1
0
// This routine calculates the next timeout interval for the various 
// activity timers.  This routine doesn't sort timers, on the assumption
// that a given system will have relatively few inactivity timers.
DWORD
GetNextInactivityTimeout(DWORD dwElapsed)
{
    DWORD dwTimeout = INFINITE;
    DWORD dwIndex;
    PACTIVITY_TIMER pat;

    PMLOCK();
    for(dwIndex = 0; (pat = gppActivityTimers[dwIndex]) != NULL; dwIndex++) {
        DWORD dwTimeLeft = pat->dwTimeLeft;
        if(dwTimeLeft != INFINITE) {
            // subtract elapsed time
            if(dwTimeLeft < dwElapsed) {
                dwTimeLeft = 0;
            } else {
                dwTimeLeft -= dwElapsed;
            }

            // update the timeout value
            if(dwTimeout == INFINITE || dwTimeLeft < dwTimeout) {
                dwTimeout = dwTimeLeft;
            }

            // update the timer
            pat->dwTimeLeft = dwTimeLeft;
        }
    }
    PMUNLOCK();

    return dwTimeout;
}
Ejemplo n.º 2
0
// This routine initializes the list of activity timers.  It returns ERROR_SUCCESS 
// if successful or a Win32 error code otherwise.
DWORD
ActivityTimerInitList(VOID)
{
    DWORD dwStatus;
    HKEY hk = NULL;
    TCHAR szSources[1024];
    DWORD dwNumTimers = 0;
    PPACTIVITY_TIMER ppatList = NULL;

#ifndef SHIP_BUILD
    SETFNAME(_T("ActivityTimerInitList"));
#endif

    wsprintf(szSources, _T("%s\\ActivityTimers"), PWRMGR_REG_KEY);
    dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSources, 0, 0, &hk);
    if(dwStatus == ERROR_SUCCESS) {
        // figure out how many values are associated with the key
        dwStatus = RegQueryInfoKey(hk, NULL, NULL, NULL, &dwNumTimers, NULL, NULL, NULL,
            NULL, NULL, NULL, NULL);
    } else {
        // no timers configured in the registry
        dwNumTimers = 0;
        dwStatus = ERROR_SUCCESS;
    }

    // if there are any values, allocate an array to hold them
    if(dwStatus == ERROR_SUCCESS) {
        ppatList = (PPACTIVITY_TIMER) PmAlloc((dwNumTimers + 1) * sizeof(PACTIVITY_TIMER));
        if(ppatList == NULL) {
            PMLOGMSG(ZONE_WARN, (_T("%s: couldn't allocate %d timers\r\n"), pszFname,
                dwNumTimers));
            dwStatus = ERROR_NOT_ENOUGH_MEMORY;
        } else {
            memset(ppatList, 0, (dwNumTimers + 1) * sizeof(PACTIVITY_TIMER));
            ppatList[dwNumTimers] = NULL;
        }
    }

    // read list of timers
    if(dwStatus == ERROR_SUCCESS && dwNumTimers != 0) {
        DWORD dwIndex = 0;
        do {
            TCHAR szName[256];
            DWORD cbValueName = dim(szName);
            
            dwStatus = RegEnumKeyEx(hk, dwIndex, szName, &cbValueName, NULL,
                NULL, NULL, NULL);
            if(dwStatus == ERROR_SUCCESS) {
                HKEY hkSubKey = NULL;
                
                // open the subkey
                dwStatus = RegOpenKeyEx(hk, szName, 0, 0, &hkSubKey);
                if(dwStatus == ERROR_SUCCESS) {
                    DWORD dwSize, dwType, dwTimeout;
                    LPTSTR pszValueName;

                    // read the timeout, expressed in seconds
                    dwSize = sizeof(dwTimeout);
                    pszValueName = _T("Timeout");
                    dwStatus = RegQueryValueEx(hkSubKey, pszValueName, NULL, &dwType, (LPBYTE) &dwTimeout, 
                        &dwSize);
                    if(dwStatus == ERROR_SUCCESS) {
                        if(dwType != REG_DWORD || dwTimeout > MAXTIMERINTERVAL) {
                            PMLOGMSG(ZONE_WARN, 
                                (_T("%s: RegQueryValueEx('%s'\'%s') or returned invalid type %d or invalid value %d\r\n"),
                                pszFname, szName, pszValueName, dwType, dwTimeout));
                            dwStatus = ERROR_INVALID_DATA;
                        }

                        // convert timeout to milliseconds
                        dwTimeout *= 1000;
                    } else {
                        // no timeout in seconds, try milliseconds
                        dwSize = sizeof(dwTimeout);
                        pszValueName = _T("TimeoutMs");
                        dwStatus = RegQueryValueEx(hkSubKey, pszValueName, NULL, &dwType, (LPBYTE) &dwTimeout, 
                            &dwSize);
                        if(dwStatus != ERROR_SUCCESS || dwType != REG_DWORD || dwTimeout > (MAXTIMERINTERVAL * 1000)) {
                            PMLOGMSG(ZONE_WARN, 
                                (_T("%s: RegQueryValueEx('%s'\'%s') failed %d (or returned invalid type %d or invalid value %d)\r\n"),
                                pszFname, szName, pszValueName, dwStatus, dwType, dwTimeout));
                            dwStatus = ERROR_INVALID_DATA;
                        }
                    }

                    if(dwStatus == ERROR_SUCCESS) {
                        // get wake sources
                        dwSize = sizeof(szSources);
                        pszValueName = _T("WakeSources");
                        dwStatus = RegQueryValueEx(hkSubKey, pszValueName, NULL, &dwType, (LPBYTE) szSources, 
                            &dwSize);
                        if(dwStatus != ERROR_SUCCESS) {
                            // no wake sources
                            szSources[0] = 0;
                            szSources[1] = 0;
                            dwStatus = ERROR_SUCCESS;
                        } else if(dwType != REG_MULTI_SZ) {
                            PMLOGMSG(ZONE_WARN, (_T("%s: invalid type %d for '%s'\'%s'\r\n"), pszFname, dwType,
                                szName, pszValueName));
                            dwStatus = ERROR_INVALID_DATATYPE;
                        } else {
                            szSources[dim(szSources) -1] = szSources[dim(szSources) -2] = 0; // Terminate MultiSZ
                        }
                    }
                    
                    // did we get the parameters?
                    if(dwStatus == ERROR_SUCCESS) {
                        ppatList[dwIndex] = ActivityTimerCreate(szName, dwTimeout, szSources);
                        if(ppatList[dwIndex] == NULL) {
                            dwStatus = ERROR_NOT_ENOUGH_MEMORY;
                        }
                    }
                }
                
                // release the registry key
                RegCloseKey(hkSubKey);
            }
            
            // update the index
            dwIndex++;
        } while(dwStatus == ERROR_SUCCESS && dwIndex < dwNumTimers);

        // did we read all items ok?
        if(dwStatus == ERROR_NO_MORE_ITEMS) {
            dwStatus = ERROR_SUCCESS;
        }

        // terminate the list with a NULL
        ppatList[dwIndex] = NULL;
    }

    // did we succeed?
    if(dwStatus == ERROR_SUCCESS) {
        PMLOCK();
        gppActivityTimers = ppatList;
        PMUNLOCK();
    } else {
        DWORD dwIndex;
        if(ppatList != NULL) {
            for(dwIndex = 0; dwIndex < dwNumTimers; dwIndex++) {
                if(ppatList[dwIndex] != NULL) {
                    ActivityTimerDestroy(ppatList[dwIndex]);
                }
            }
            PmFree(ppatList);
        }
    }

    // release resources
    if(hk != NULL) RegCloseKey(hk);

    PMLOGMSG(dwStatus != ERROR_SUCCESS && ZONE_WARN,
        (_T("%s: returning %d\r\n"), pszFname, dwStatus));
    return dwStatus;
}
Ejemplo n.º 3
0
// this thread handles activity timer events
DWORD WINAPI 
ActivityTimersThreadProc(LPVOID lpvParam)
{
    DWORD dwStatus, dwNumEvents, dwWaitInterval;
    HANDLE hevReady = (HANDLE) lpvParam;
    HANDLE hEvents[MAXIMUM_WAIT_OBJECTS];
    BOOL fDone = FALSE;
    HANDLE hevDummy = NULL;
    INT iPriority;
    const DWORD cdwTimerBaseIndex = 2;

#ifndef SHIP_BUILD
    SETFNAME(_T("ActivityTimersThreadProc"));
#endif

    PMLOGMSG(ZONE_INIT, (_T("+%s: thread 0x%08x\r\n"), pszFname, GetCurrentThreadId()));

    // set the thread priority
    if(!GetPMThreadPriority(_T("TimerPriority256"), &iPriority)) {
        iPriority = DEF_ACTIVITY_TIMER_THREAD_PRIORITY;
    }
    CeSetThreadPriority(GetCurrentThread(), iPriority);

    // initialize the list of activity timers
    if(ActivityTimerInitList() != ERROR_SUCCESS) {
        PMLOGMSG(ZONE_WARN, (_T("%s: ActivityTimerInitList() failed\r\n"), pszFname));
        goto done;
    }

    // create a dummy event that's never signaled
    hevDummy = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(hevDummy == NULL) {
        PMLOGMSG(ZONE_WARN, (_T("%s: Couldn't create dummy event\r\n"), pszFname));
        goto done;
    }

    // set up the list of events
    dwNumEvents = 0;
    hEvents[dwNumEvents++] = ghevPmShutdown;
    hEvents[dwNumEvents++] = ghevTimerResume;
    PMLOCK();
    if(gppActivityTimers[0] == NULL) {
        // no activity timers defined
        PmFree(gppActivityTimers);
        gppActivityTimers = NULL;
    } else {
        // copy activity timer events into the event list
        while(dwNumEvents < dim(hEvents) && gppActivityTimers[dwNumEvents - cdwTimerBaseIndex] != NULL) {
            hEvents[dwNumEvents] = gppActivityTimers[dwNumEvents - cdwTimerBaseIndex]->hevReset;
            dwNumEvents++;
        }
    }
    PMUNLOCK();

    // we're up and running
    SetEvent(hevReady);

    // are there actually any timers to wait on?
    if(dwNumEvents <= cdwTimerBaseIndex) {
        // no timers defined, so we don't need this thread to wait on them.
        PMLOGMSG(ZONE_INIT || ZONE_WARN, (_T("%s: no activity timers defined, exiting\r\n"), pszFname));
        Sleep(1000);            // don't want PM initialization to fail when we exit
        goto done;
    }

    // wait for these events to get signaled
    PMLOGMSG(ZONE_TIMERS, (_T("%s: entering wait loop, %d timers total\r\n"),
        pszFname, dwNumEvents - cdwTimerBaseIndex));
    dwWaitInterval = 0;
    while(!fDone) {
        DWORD dwTimeout = GetNextInactivityTimeout(dwWaitInterval);
        DWORD dwWaitStart = GetTickCount();

        PMLOGMSG(ZONE_TIMERS, 
            (_T("%s: waiting %u (0x%08x) ms for next event, wait interval was %d\r\n"), pszFname,
            dwTimeout, dwTimeout, dwWaitInterval));
        dwStatus = WaitForMultipleObjects(dwNumEvents, hEvents, FALSE, dwTimeout);
        dwWaitInterval = GetTickCount() - dwWaitStart;

        // figure out what caused the wakeup
        if(dwStatus == (WAIT_OBJECT_0 + 0)) {
            PMLOGMSG(ZONE_WARN, (_T("%s: shutdown event set\r\n"), pszFname));
            fDone = TRUE;
        } else if(dwStatus == (WAIT_OBJECT_0 + 1)) {
            DWORD dwIndex;
            PACTIVITY_TIMER pat;

            // we've resumed, so re-enable all activity timers that can be reset
            PMLOGMSG(ZONE_TIMERS, (_T("%s: resume event set\r\n"), pszFname));
            PMLOCK();
            for(dwIndex = 0; (pat = gppActivityTimers[dwIndex]) != NULL; dwIndex++) {
                DWORD dwEventIndex = dwIndex + cdwTimerBaseIndex;
                if(hEvents[dwEventIndex] == hevDummy) {
                    hEvents[dwEventIndex] = pat->hevReset;
                }
                pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval;
            }
            PMUNLOCK();
        } else if(dwStatus == WAIT_TIMEOUT) {
            DWORD dwIndex;
            PACTIVITY_TIMER pat;

            // figure out which event(s) timed out
            PMLOCK();
            for(dwIndex = 0; (pat = gppActivityTimers[dwIndex]) != NULL; dwIndex++) {
                if(pat->dwTimeLeft <= dwWaitInterval  && pat->dwTimeLeft != INFINITE) {
                    // has the timer really expired?
                    if(WaitForSingleObject(pat->hevReset, 0) == WAIT_OBJECT_0) {
                        // The timer was reset while we weren't looking at it, so we'll look
                        // at it again later.  Calculate the new timeout, compensating for the update
                        // that will occur in GetNextInactivityTimeout().
                        PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' reset after timeout\r\n"), pszFname,
                            pat->pszName));
                        pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval;
                        pat->dwResetCount++;
                    } else {
                        // the timer has really expired, update events appropriately
                        PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' has expired\r\n"), pszFname,
                            pat->pszName));
                        ResetEvent(pat->hevActive);
                        SetEvent(pat->hevInactive);

                        // start looking at the reset event for this timer again
                        hEvents[dwIndex + cdwTimerBaseIndex] = pat->hevReset;

                        // update counts
                        pat->dwTimeLeft = INFINITE;
                        pat->dwExpiredCount++;
                    }
                }
            }
            PMUNLOCK();
        } else if(dwStatus > (WAIT_OBJECT_0 + 0) && dwStatus < (WAIT_OBJECT_0 + dwNumEvents)) {
            PACTIVITY_TIMER pat;
            DWORD dwEventIndex = dwStatus - WAIT_OBJECT_0;

            PMLOCK();
            
            // get a pointer to the timer
            pat = gppActivityTimers[dwEventIndex - cdwTimerBaseIndex];

            // handle its events
            DEBUGCHK(pat != NULL);
            if(pat->dwTimeout == 0) {
                // we're not using the event, so ignore it
                pat->dwTimeLeft = INFINITE;
            } else {
                PMLOGMSG(ZONE_TIMERS, (_T("%s: timer '%s' reset\r\n"), pszFname, pat->pszName));

                // set events appropriately
                ResetEvent(pat->hevInactive);
                SetEvent(pat->hevActive);

                // don't look at this event again until it's about ready to time out
                hEvents[dwEventIndex] = hevDummy;

                // update time left on the timer, compensating for the update
                // that will occur in GetNextInactivityTimeout().
                pat->dwTimeLeft = pat->dwTimeout + dwWaitInterval;
            }
            pat->dwResetCount++;
            PMUNLOCK();
        } else {
            PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d, status is %d\r\n"),
                pszFname, dwStatus, GetLastError())); 
            fDone = TRUE;
        }
    }

done:
    // release resources
    if(hevDummy != NULL) CloseHandle(hevDummy);
    PMLOCK();
    if(gppActivityTimers != NULL) {
        DWORD dwIndex = 0;
        while(gppActivityTimers[dwIndex] != NULL) {
            ActivityTimerDestroy(gppActivityTimers[dwIndex]);
            dwIndex++;
        }
        PmFree(gppActivityTimers);
        gppActivityTimers = NULL;
    }
    PMUNLOCK();

    PMLOGMSG(ZONE_INIT | ZONE_WARN, (_T("-%s: exiting\r\n"), pszFname));
    return 0;
}
Ejemplo n.º 4
0
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;
		static BOOL fWantStartupScreen = FALSE;
		DWORD dwNewStateFlags = pNewSystemPowerState->dwFlags;

		// 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;
		}

		// 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_s (pbb.SystemPowerState, _countof (pbb.SystemPowerState),
						pNewSystemPowerState->pszName, pbb.Length);
			pbb.Length *= sizeof (pbb.SystemPowerState[0]);	           // Convert to byte count
			GenerateNotifications ((PPOWER_BROADCAST) & pbb);

			// Is GWES ready?
			if (!gfGwesReady)
			{
				if (WaitForAPIReady (SH_GDI, 0) == WAIT_OBJECT_0)
				{
					gfGwesReady = TRUE;
				}
			}

			// Are we suspending?
			if (fSuspendSystem && gpfnGwesPowerDown != 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 Power Manager, 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);
				}

                // Discard code pages from drivers.  This is a diagnostic tool to
                // forcibly expose paging-related bugs that could cause apparently
                // random system crashes or hangs.  Optionally, OEMs can disable this
                // for production systems to speed up resume times.  We have to call
                // PageOutMode before FileSys Shutdown. Otherwise, it cause dead lock
                // between filesystem and loader.

				if (gfPageOutAllModules)
				{
					ForcePageout ();
				}

				if (g_pSysRegistryAccess)
					g_pSysRegistryAccess->EnterLock ();
				gfFileSystemsAvailable = FALSE;

				if ((dwNewStateFlags & POWER_STATE_RESET) != 0)
				{
					// Is this to be a cold boot?
					if (_tcscmp (pszName, _T ("coldreboot")) == 0)
					{
						SetCleanRebootFlag ();
					}
				}

				FileSystemPowerFunction (FSNOTIFY_POWER_OFF);

				// 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)
				{
					// Should not return from this call, but if we do just suspend the system:
					KernelLibIoControl ((HANDLE) KMOD_OAL, 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;
				if (g_pSysRegistryAccess)
					g_pSysRegistryAccess->LeaveLock ();

				// 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);
					}
				}

				// Tell GWES to wake up:
				if (gpfnGwesPowerUp != NULL && gfGwesReady)
				{
					gpfnGwesPowerUp (fWantStartupScreen);
					fWantStartupScreen = FALSE;
				}

				// Send out resume notification:
				pbb.Message = PBT_RESUME;
				pbb.Flags = 0;
				pbb.Length = 0;
				pbb.SystemPowerState[0] = 0;
				GenerateNotifications ((PPOWER_BROADCAST) & pbb);
			}
			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;
			}

			// Are we suspending?
			if (fSuspendSystem)
			{
				// 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);	            // Force the scheduler to run.
				PMLOGMSG (ZONE_PLATFORM
						  || ZONE_RESUME, (_T ("%s: back from PowerOffSystem()\r\n"), pszFname));

				// Clear the suspend flag:
				gfSystemSuspended = FALSE;
			}
		}
		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);
	}

	return dwStatus;
}