|
|
/****************************** Module Header ******************************\
* Module Name: power.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains the code to implement power management. * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <ntcsrmsg.h>
#include "csrmsg.h"
#include "ntddvdeo.h"
#pragma alloc_text(INIT, InitializePowerRequestList)
BOOL IsSessionSwitchBlocked(); NTSTATUS UserSessionSwitchBlock_Start(); void UserSessionSwitchBlock_End();
extern BOOL gbUserInitialized;
#define SWITCHACTION_RESETMODE 0x1
#define SWITCHACTION_REENUMERATE 0x2
LIST_ENTRY gPowerRequestList; PFAST_MUTEX gpPowerRequestMutex; PKEVENT gpEventPowerRequest; ULONG gulDelayedSwitchAction = 0;
typedef struct tagPOWERREQUEST { LIST_ENTRY PowerRequestLink; union { KEVENT Event; WIN32_POWEREVENT_PARAMETERS CapturedParms; }; NTSTATUS Status; PKWIN32_POWEREVENT_PARAMETERS Parms; } POWERREQUEST, *PPOWERREQUEST;
PPOWERREQUEST gpPowerRequestCurrent;
__inline VOID EnterPowerCrit( VOID) { KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(gpPowerRequestMutex); }
__inline VOID LeavePowerCrit( VOID) { ExReleaseFastMutexUnsafe(gpPowerRequestMutex); KeLeaveCriticalRegion(); }
/***************************************************************************\
* CancelPowerRequest * * The power request can't be satisfied because the worker thread is gone. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/ VOID CancelPowerRequest( PPOWERREQUEST pPowerRequest) { UserAssert(pPowerRequest != gpPowerRequestCurrent); pPowerRequest->Status = STATUS_UNSUCCESSFUL;
/*
* If it was a callout, tell the waiting thread to proceed. * If it was an event, there is no waiting thread but we need to * free the pool */ if (pPowerRequest->Parms) { UserFreePool(pPowerRequest); } else { KeSetEvent(&pPowerRequest->Event, EVENT_INCREMENT, FALSE); } }
/***************************************************************************\
* QueuePowerRequest * * Insert a power request into the list and wakeup CSRSS to process it. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/
NTSTATUS QueuePowerRequest( PKWIN32_POWEREVENT_PARAMETERS Parms) { NTSTATUS Status = STATUS_SUCCESS; PPOWERREQUEST pPowerRequest; TL tlPool;
UserAssert(gpEventPowerRequest != NULL); UserAssert(gpPowerRequestMutex != NULL);
/*
* Allocate and initialize the power request. */ pPowerRequest = UserAllocPoolNonPagedNS(sizeof(POWERREQUEST), TAG_POWER); if (pPowerRequest == NULL) { return STATUS_NO_MEMORY; }
/*
* If this is a callout, there are no paramaters. Initialize the event to wait on. * If this is an event, capture the parameters to be freed after the event * is dispatched. */ if (Parms) { pPowerRequest->CapturedParms = *Parms; pPowerRequest->Parms = &pPowerRequest->CapturedParms; } else { KeInitializeEvent(&pPowerRequest->Event, SynchronizationEvent, FALSE); pPowerRequest->Parms = NULL; }
/*
* Insert the power request into the list. */ EnterPowerCrit(); if (gbNoMorePowerCallouts) { Status = STATUS_UNSUCCESSFUL; } else { InsertHeadList(&gPowerRequestList, &pPowerRequest->PowerRequestLink); } LeavePowerCrit();
/*
* if this thread is gone through attach process, or * If this is a system thread or a non-GUI thread, tell CSRSS to do the * work and wait for it to finish. Otherwise, we'll do the work ourselves. */ if (NT_SUCCESS(Status)) { if (PsIsSystemThread(PsGetCurrentThread()) || KeIsAttachedProcess() || W32GetCurrentThread() == NULL) { KeSetEvent(gpEventPowerRequest, EVENT_INCREMENT, FALSE); } else { EnterCrit(); ThreadLockPool(PtiCurrent(), pPowerRequest, &tlPool); xxxUserPowerCalloutWorker(); ThreadUnlockPool(PtiCurrent(), &tlPool); LeaveCrit(); }
/*
* If this is a callout, wait for it and then free the request. * Otherwise, it is an event, and we do not need to wait for it * to complete. The request will be freed after it is dequeued. */ if (Parms) { return(STATUS_SUCCESS); } else { Status = KeWaitForSingleObject(&pPowerRequest->Event, WrUserRequest, KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status)) { Status = pPowerRequest->Status; } } }
/*
* Free the power request. */ UserAssert(pPowerRequest != gpPowerRequestCurrent); UserFreePool(pPowerRequest);
return Status; }
/***************************************************************************\
* UnqueuePowerRequest * * Remove a power request from the list. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/ PPOWERREQUEST UnqueuePowerRequest( VOID) { PLIST_ENTRY pEntry; PPOWERREQUEST pPowerRequest = NULL;
/*
* Remove a power request from the list. */ EnterPowerCrit(); if (!IsListEmpty(&gPowerRequestList)) { pEntry = RemoveTailList(&gPowerRequestList); pPowerRequest = CONTAINING_RECORD(pEntry, POWERREQUEST, PowerRequestLink); } LeavePowerCrit();
return pPowerRequest; }
/***************************************************************************\
* InitializePowerRequestList * * Initialize global power request list state. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/ NTSTATUS InitializePowerRequestList( HANDLE hPowerRequestEvent) { NTSTATUS Status;
InitializeListHead(&gPowerRequestList);
Status = ObReferenceObjectByHandle(hPowerRequestEvent, EVENT_ALL_ACCESS, *ExEventObjectType, KernelMode, &gpEventPowerRequest, NULL); if (!NT_SUCCESS(Status)) { return Status; }
gpPowerRequestMutex = UserAllocPoolNonPagedNS(sizeof(FAST_MUTEX), TAG_POWER); if (gpPowerRequestMutex == NULL) { return STATUS_NO_MEMORY; } ExInitializeFastMutex(gpPowerRequestMutex);
return STATUS_SUCCESS; }
/***************************************************************************\
* CleanupPowerRequestList * * Cancel any pending power requests. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/ VOID CleanupPowerRequestList( VOID) { PPOWERREQUEST pPowerRequest;
/*
* Make sure no new power requests come in. */ gbNoMorePowerCallouts = TRUE;
/*
* If we never allocated anything, there's nothing to clean up. */ if (gpPowerRequestMutex == NULL) { return; }
/*
* Mark any pending power requests as cacelled. */ while ((pPowerRequest = UnqueuePowerRequest()) != NULL) { CancelPowerRequest(pPowerRequest); } }
/***************************************************************************\
* DeletePowerRequestList * * Clean up any global power request state. * * History: * 20-Oct-1998 JerrySh Created. \***************************************************************************/ VOID DeletePowerRequestList( VOID) { if (gpPowerRequestMutex) {
/*
* Make sure there are no pending power requests. */ UserAssert(IsListEmpty(&gPowerRequestList));
/*
* Free the power request structures. */ UserFreePool(gpPowerRequestMutex); gpPowerRequestMutex = NULL; } }
/***************************************************************************\
* UserPowerEventCalloutWorker * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ NTSTATUS xxxUserPowerEventCalloutWorker( PKWIN32_POWEREVENT_PARAMETERS Parms) { BROADCASTSYSTEMMSGPARAMS bsmParams; NTSTATUS Status = STATUS_SUCCESS; PSPOWEREVENTTYPE EventNumber = Parms->EventNumber; ULONG_PTR Code = Parms->Code; BOOL bCurrentPowerOn; ULONGLONG ullLastSleepTime; BOOL bGotLastSleepTime;
/*
* Make sure CSRSS is still running. */ if (gbNoMorePowerCallouts) { return STATUS_UNSUCCESSFUL; }
switch (EventNumber) { case PsW32FullWake:
if (!gbRemoteSession) { /*
* Let all the services know that they can resume operation. * There is no corresponding POWER_ACTION for this, but since this * is a non-query event, PowerActionNone is as good as any. */ LeaveCrit(); IoPnPDeliverServicePowerNotification(PowerActionNone, PBT_APMRESUMESUSPEND, 0, FALSE); EnterCrit(); }
/*
* Let all the applications know that they can resume operation. * We must not send this message to a session, if it was created after machine went into sleep */
/*
* One of the side effects of NtPowerInformation is that it will * dispatch pending power events. So we cannot call it with the user * critsec held. * * Note: Same thing is done for IoPnPDeliverServicePowerNotification. */ LeaveCrit(); bGotLastSleepTime = ZwPowerInformation(LastSleepTime, NULL, 0, &ullLastSleepTime, sizeof(ULONGLONG)) == STATUS_SUCCESS; EnterCrit();
if (!bGotLastSleepTime || gSessionCreationTime < ullLastSleepTime) {
bsmParams.dwRecipients = BSM_ALLDESKTOPS; bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE; xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMRESUMESUSPEND, 0, &bsmParams);
} break;
case PsW32EventCode: /*
* Post a message to winlogon, and let them put up a message box * or play a sound. */
if (gspwndLogonNotify) { glinp.ptiLastWoken = GETPTI(gspwndLogonNotify); _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_POWEREVENT, (ULONG)Code); Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; }
break;
case PsW32PowerPolicyChanged: /*
* Set video timeout value. */ xxxSystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, (ULONG)Code, 0, 0); xxxSystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, (ULONG)Code, 0, 0); break;
case PsW32SystemPowerState:
if (!gbRemoteSession) { /*
* Let all the services know that the power status has changed. * There is no corresponding POWER_ACTION for this, but since this * is a non-query event, PowerActionNone is as good as any. */ LeaveCrit(); IoPnPDeliverServicePowerNotification(PowerActionNone, PBT_APMPOWERSTATUSCHANGE, 0, FALSE); EnterCrit(); }
/*
* Let all the applications know that the power status has changed. */ bsmParams.dwRecipients = BSM_ALLDESKTOPS; bsmParams.dwFlags = BSF_POSTMESSAGE; xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMPOWERSTATUSCHANGE, 0, &bsmParams); break;
case PsW32SystemTime: /*
* Let all the applications know that the system time has changed. */ bsmParams.dwRecipients = BSM_ALLDESKTOPS; bsmParams.dwFlags = BSF_POSTMESSAGE; xxxSendMessageBSM(NULL, WM_TIMECHANGE, 0, 0, &bsmParams); break;
case PsW32DisplayState: /*
* Set video timeout active status. */ xxxSystemParametersInfo(SPI_SETLOWPOWERACTIVE, !Code, 0, 0); xxxSystemParametersInfo(SPI_SETPOWEROFFACTIVE, !Code, 0, 0); break;
case PsW32GdiOff: /*
* At this point we will disable the display device, if no protocol switch is in progress. */ if (!gfSwitchInProgress) { DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3);
bCurrentPowerOn = DrvQueryMDEVPowerState(gpDispInfo->pmdev); if (bCurrentPowerOn) { SafeDisableMDEV(); } DrvSetMDEVPowerState(gpDispInfo->pmdev, FALSE); } else { Status = STATUS_UNSUCCESSFUL; }
break;
case PsW32GdiOn: /*
* Call video driver to turn the display back on, if no protocol * switch is in progress. */
if (!gfSwitchInProgress) { bCurrentPowerOn = DrvQueryMDEVPowerState(gpDispInfo->pmdev); if (!bCurrentPowerOn) { SafeEnableMDEV(); } DrvSetMDEVPowerState(gpDispInfo->pmdev, TRUE); DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0); } else { Status = STATUS_UNSUCCESSFUL; break; }
/*
* Repaint the whole screen. */ xxxUserResetDisplayDevice();
if (gulDelayedSwitchAction) { HANDLE pdo;
//
// The first ACPI device is the one respond to hotkey.
//
PVOID PhysDisp = DrvWakeupHandler(&pdo);
if (PhysDisp && (gulDelayedSwitchAction & SWITCHACTION_RESETMODE)) { UNICODE_STRING strDeviceName; DEVMODEW NewMode; ULONG bPrune;
if (DrvDisplaySwitchHandler(PhysDisp, &strDeviceName, &NewMode, &bPrune)) { /*
* CSRSS is not the only process to deliver power callouts. */ bPrune = (bPrune ? 0 : CDS_RAWMODE) | CDS_TRYCLOSEST | CDS_RESET; if (!ISCSRSS()) { xxxUserChangeDisplaySettings(NULL, NULL, grpdeskRitInput, bPrune, 0, KernelMode); } else { xxxUserChangeDisplaySettings(NULL, NULL, NULL, bPrune, 0, KernelMode); } }
//
// If there is a requirement to reenumerate sub-devices.
//
if (pdo && (gulDelayedSwitchAction & SWITCHACTION_REENUMERATE)) { IoInvalidateDeviceRelations((PDEVICE_OBJECT)pdo, BusRelations); } } } gulDelayedSwitchAction = 0;
break;
default: Status = STATUS_NOT_IMPLEMENTED; break; }
return Status; }
/***************************************************************************\
* UserPowerEventCallout * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ NTSTATUS UserPowerEventCallout( PKWIN32_POWEREVENT_PARAMETERS Parms) { /*
* Make sure CSRSS is running. */ if (!gbVideoInitialized || gbNoMorePowerCallouts) { return STATUS_UNSUCCESSFUL; }
UserAssert(gpepCSRSS != NULL);
/*
* Process the power request. */ return QueuePowerRequest(Parms); }
/***************************************************************************\
* UserPowerStateCalloutWorker * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ NTSTATUS xxxUserPowerStateCalloutWorker( VOID) { BOOL fContinue; BROADCASTSYSTEMMSGPARAMS bsmParams; POWER_ACTION powerOperation; NTSTATUS Status = STATUS_SUCCESS; TL tlpwnd; POWERSTATETASK Task = gPowerState.PowerStateTask; ULONGLONG ullLastSleepTime; BOOL bGotLastSleepTime;
/*
* By now we must have alrady blocked session switch, it's blocked only * for win32k belonging to active console session. */ UserAssert(SharedUserData->ActiveConsoleId != gSessionId || IsSessionSwitchBlocked());
/*
* Make sure CSRSS is still running. */ if (gbNoMorePowerCallouts) { return STATUS_UNSUCCESSFUL; }
switch (Task) {
case PowerState_Init:
/*
* Store the event so this thread can be promoted later. */
EnterPowerCrit(); gPowerState.pEvent = PtiCurrent()->pEventQueueServer; LeavePowerCrit();
break;
case PowerState_QueryApps:
if (!gPowerState.fCritical) { /*
* Ask the applications if we can suspend operation. */ if (gPowerState.fQueryAllowed) {
gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS; gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG; if (gPowerState.fUIAllowed) { gPowerState.bsmParams.dwFlags |= BSF_ALLOWSFW; }
if (gPowerState.fOverrideApps == FALSE) { gPowerState.bsmParams.dwFlags |= (BSF_QUERY | BSF_NOTIMEOUTIFNOTHUNG); }
fContinue = xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMQUERYSUSPEND, gPowerState.fUIAllowed, &gPowerState.bsmParams);
if (fContinue && !gbRemoteSession) { /*
* Ask the services if we can suspend operation. * Map the power action event as needed. */ if (gPowerState.psParams.MinSystemState == PowerSystemHibernate) { powerOperation = PowerActionHibernate; } else { powerOperation = gPowerState.psParams.SystemAction; }
LeaveCrit(); fContinue = IoPnPDeliverServicePowerNotification( powerOperation, PBT_APMQUERYSUSPEND, gPowerState.fUIAllowed, TRUE); // synchronous query
EnterCrit(); }
/*
* If an app or service says to abort and we're not in * override apps or critical mode, return query failed. */ if (!(fContinue || gPowerState.fOverrideApps || gPowerState.fCritical)) { Status = STATUS_CANCELLED; } }
}
break;
case PowerState_QueryFailed:
/*
* Only send a suspend failed message to the applications, since pnp * will already have delivered the suspend failed message to services if * one of those aborted the query. */ gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS; gPowerState.bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE; xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMQUERYSUSPENDFAILED, 0, &gPowerState.bsmParams); EnterPowerCrit(); gPowerState.pEvent = NULL; gPowerState.fInProgress = FALSE; LeavePowerCrit();
break;
case PowerState_SuspendApps:
if (!gPowerState.fCritical) {
if (!gbRemoteSession) { /*
* Map the power action event as needed. */ if (gPowerState.psParams.MinSystemState == PowerSystemHibernate) { powerOperation = PowerActionHibernate; } else { powerOperation = gPowerState.psParams.SystemAction; }
LeaveCrit(); IoPnPDeliverServicePowerNotification(powerOperation, PBT_APMSUSPEND, 0, FALSE); EnterCrit(); }
gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS; gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG; xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMSUSPEND, 0, &gPowerState.bsmParams); }
/*
* Clear the event so the thread won't wake up prematurely. */ EnterPowerCrit(); gPowerState.pEvent = NULL; LeavePowerCrit();
break;
case PowerState_ShowUI:
/*
* if this is not session 0 show ui for sessions. * we shall take this ui off when we resume apps * For session 0 we call PowerState_NotifyWL which takes care of it. */
if ((gSessionId != 0 ) && (gspwndLogonNotify != NULL)) {
ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_SHOW_POWER_MESSAGE, (LPARAM)&gPowerState.psParams); ThreadUnlock(&tlpwnd);
}
break;
case PowerState_NotifyWL:
if (gspwndLogonNotify != NULL) { PWND pwndActive;
if (gpqForeground && (pwndActive = gpqForeground->spwndActive) && (GetFullScreen(pwndActive) == FULLSCREEN || GetFullScreen(pwndActive) == FULLSCREENMIN)) { gPowerState.psParams.FullScreenMode = TRUE; } else { gPowerState.psParams.FullScreenMode = FALSE; } ThreadLockAlways(gspwndLogonNotify, &tlpwnd); Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_POWERSTATE, (LPARAM)&gPowerState.psParams);
ThreadUnlock(&tlpwnd);
if (!NT_SUCCESS(Status)) { /*
* If we failed to to this power operation, don't lock the * console. */ gPowerState.psParams.Flags &= ~POWER_ACTION_LOCK_CONSOLE; } }
break;
case PowerState_ResumeApps: /*
* If this is active console we need to lock it. */ if ((gPowerState.psParams.Flags & POWER_ACTION_LOCK_CONSOLE) && (gSessionId == SharedUserData->ActiveConsoleId) && (gspwndLogonNotify != NULL)) {
ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
_PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_LOCKWORKSTATION, LOCK_RESUMEHIBERNATE);
ThreadUnlock(&tlpwnd);
}
//
// We dont need to remove power message, if we did not post one.
//
/*
* One of the side effects of NtPowerInformation is that it will * dispatch pending power events. So we can not call it with the * user critsec held. * * Note: The same thing is done for IoPnPDeliverServicePowerNotification. */
LeaveCrit(); bGotLastSleepTime = ZwPowerInformation(LastSleepTime, NULL, 0, &ullLastSleepTime, sizeof(ULONGLONG)) == STATUS_SUCCESS; EnterCrit();
if (!bGotLastSleepTime || gSessionCreationTime < ullLastSleepTime) { if (gSessionId != 0 && gspwndLogonNotify != NULL) { ThreadLockAlways(gspwndLogonNotify, &tlpwnd); Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_REMOVE_POWER_MESSAGE, (LPARAM)&gPowerState.psParams);
ThreadUnlock(&tlpwnd); } }
/*
* The power state broadcast is over. */ EnterPowerCrit(); gPowerState.fInProgress = FALSE; LeavePowerCrit();
/*
* Tickle the input time so we don't fire up a screen saver right away * and remember that the monitor is on. */ glinp.timeLastInputMessage = NtGetTickCount(); glinp.dwFlags &= ~LINP_POWEROFF;
if (!gbRemoteSession) { /*
* Re-init the keyboard state. */ InitKeyboardState();
/*
* Let all the services know that we're waking up. There is no * corresponding POWER_ACTION for this, but since this is a * non-query event, PowerActionNone is as good as any. */ LeaveCrit(); IoPnPDeliverServicePowerNotification(PowerActionNone, PBT_APMRESUMEAUTOMATIC, 0, FALSE); EnterCrit(); }
/*
* Let all the applications know that we're waking up. */ bsmParams.dwRecipients = BSM_ALLDESKTOPS; bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE; xxxSendMessageBSM(NULL, WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC, 0, &bsmParams);
break;
default: RIPMSG1(RIP_ERROR, "Unknown task 0x%x", Task); break; }
return Status; }
/***************************************************************************\
* UserPowerStateCallout * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ NTSTATUS UserPowerStateCallout( PKWIN32_POWERSTATE_PARAMETERS Parms) { POWERSTATETASK Task = Parms->PowerStateTask; BOOLEAN Promotion = Parms->Promotion; POWER_ACTION SystemAction = Parms->SystemAction; SYSTEM_POWER_STATE MinSystemState = Parms->MinSystemState; ULONG Flags = Parms->Flags; NTSTATUS Status;
if (Task == PowerState_BlockSessionSwitch) { /*
* Don't allow active console session switch while we are in power * callouts. First try to block the session switch. */ return UserSessionSwitchBlock_Start(); }
if (Task == PowerState_UnBlockSessionSwitch) { UserAssert(IsSessionSwitchBlocked()); UserSessionSwitchBlock_End(); return STATUS_SUCCESS; }
/*
* Make sure CSRSS is running. */ if (!gbVideoInitialized || gbNoMorePowerCallouts || !gspwndLogonNotify) { return STATUS_UNSUCCESSFUL; }
UserAssert(gpepCSRSS != NULL);
EnterPowerCrit(); if (Task == PowerState_Init) { /*
* Make sure we're not trying to promote a non-existent request * or start a new one when we're already doing it. */ if ((Promotion && !gPowerState.fInProgress) || (!Promotion && gPowerState.fInProgress)) { LeavePowerCrit();
return STATUS_INVALID_PARAMETER; }
/*
* Save our state. */ gPowerState.fInProgress = TRUE; gPowerState.fOverrideApps = (Flags & POWER_ACTION_OVERRIDE_APPS) != 0; gPowerState.fCritical = (Flags & POWER_ACTION_CRITICAL) != 0; gPowerState.fQueryAllowed = (Flags & POWER_ACTION_QUERY_ALLOWED) != 0; gPowerState.fUIAllowed = (Flags & POWER_ACTION_UI_ALLOWED) != 0; gPowerState.psParams.SystemAction = SystemAction; gPowerState.psParams.MinSystemState = MinSystemState; gPowerState.psParams.Flags = Flags; if (gPowerState.fOverrideApps) { gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG; } if (gPowerState.fCritical) { gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_QUERY; } if (gPowerState.pEvent) { KeSetEvent(gPowerState.pEvent, EVENT_INCREMENT, FALSE); }
}
gPowerState.PowerStateTask = Task;
LeavePowerCrit();
/*
* If this is a promotion, we're done. */ if (Promotion) { return STATUS_SUCCESS; }
/*
* Process the power request. */ Status = QueuePowerRequest(NULL); if (Task == PowerState_QueryApps && !NT_SUCCESS(Status)) { /*
* Query was refused. */ Parms->fQueryDenied = TRUE; }
return Status; }
/***************************************************************************\
* UserPowerCalloutWorker * * Pull any pending power requests off the list and call the appropriate * power callout function. * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ VOID xxxUserPowerCalloutWorker( VOID) { PPOWERREQUEST pPowerRequest; TL tlPool;
while ((pPowerRequest = UnqueuePowerRequest()) != NULL) { /*
* Make sure the event gets signalled even if the thread dies in a * callback or the waiting thread might get stuck. */ ThreadLockPoolCleanup(PtiCurrent(), pPowerRequest, &tlPool, CancelPowerRequest);
/*
* Call the appropriate power worker function. */ gpPowerRequestCurrent = pPowerRequest; if (pPowerRequest->Parms) { pPowerRequest->Status = xxxUserPowerEventCalloutWorker(pPowerRequest->Parms); } else { pPowerRequest->Status = xxxUserPowerStateCalloutWorker(); } gpPowerRequestCurrent = NULL;
/*
* If it was a callout, tell the waiting thread to proceed. If it * was an event, there is no waiting thread but we need to free the * pool. */ ThreadUnlockPoolCleanup(PtiCurrent(), &tlPool); if (pPowerRequest->Parms) { UserFreePool(pPowerRequest); } else { KeSetEvent(&pPowerRequest->Event, EVENT_INCREMENT, FALSE); } } }
/***************************************************************************\
* VideoPortCalloutThread * * Call the appropriate power callout function and return. * * History: * 02-Dec-1996 JerrySh Created. \***************************************************************************/ VOID VideoPortCalloutThread( PPOWER_INIT pInitData) { NTSTATUS Status; PVIDEO_WIN32K_CALLBACKS_PARAMS Params = pInitData->Params;
Params->Status = InitSystemThread(NULL);
if (!NT_SUCCESS(Params->Status)) { goto RetThreadCallOut; }
while (1) { EnterCrit(); if (!gfSwitchInProgress) { break; } else { LeaveCrit(); Status = KeWaitForSingleObject(gpevtVideoportCallout, WrUserRequest, KernelMode, FALSE, NULL); } }
if (IsRemoteConnection()) { LeaveCrit(); Params->Status = STATUS_UNSUCCESSFUL; goto RetThreadCallOut; }
switch (Params->CalloutType) {
case VideoWakeupCallout: gulDelayedSwitchAction |= SWITCHACTION_RESETMODE;
break;
case VideoDisplaySwitchCallout: { UNICODE_STRING strDeviceName; DEVMODEW NewMode; ULONG bPrune;
Params->Status = STATUS_SUCCESS;
if (!DrvQueryMDEVPowerState(gpDispInfo->pmdev)) { gulDelayedSwitchAction |= ((Params->PhysDisp != NULL) ? SWITCHACTION_RESETMODE : 0) | ((Params->Param) ? SWITCHACTION_REENUMERATE : 0); break; }
gulDelayedSwitchAction = 0; if (Params->PhysDisp != NULL) { if (DrvDisplaySwitchHandler(Params->PhysDisp, &strDeviceName, &NewMode, &bPrune)) { DESKRESTOREDATA drdRestore; drdRestore.pdeskRestore = NULL;
/*
* CSRSS is not the only process to deliver power callouts. */ if (!ISCSRSS() || NT_SUCCESS(xxxSetCsrssThreadDesktop(grpdeskRitInput, &drdRestore))) { xxxUserChangeDisplaySettings(NULL, NULL, grpdeskRitInput, ((bPrune) ? 0 : CDS_RAWMODE) | CDS_TRYCLOSEST | CDS_RESET, 0, KernelMode);
if (ISCSRSS()) { xxxRestoreCsrssThreadDesktop(&drdRestore); } } } } }
/*
* If there is a requirement to reenumerate sub-devices. */ if (Params->Param) { IoInvalidateDeviceRelations((PDEVICE_OBJECT)Params->Param, BusRelations); }
break;
case VideoChangeDisplaySettingsCallout: { DEVMODEW Devmode; DESKRESTOREDATA drdRestore;
memset(&Devmode, 0, sizeof(DEVMODEW)); Devmode.dmSize = sizeof(DEVMODEW); Devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; Devmode.dmBitsPerPel = 4; Devmode.dmPelsWidth = 640; Devmode.dmPelsHeight = 480;
drdRestore.pdeskRestore = NULL;
/*
* CSRSS is not the only process to deliver power callouts. */ if (!ISCSRSS() || NT_SUCCESS(xxxSetCsrssThreadDesktop(grpdeskRitInput, &drdRestore))) { xxxUserChangeDisplaySettings(NULL, &Devmode, grpdeskRitInput, CDS_RESET, NULL, KernelMode);
if (ISCSRSS()) { xxxRestoreCsrssThreadDesktop(&drdRestore); } } } break;
case VideoFindAdapterCallout: if (Params->Param) { SafeEnableMDEV(); xxxUserResetDisplayDevice(); } else { SafeDisableMDEV(); }
Params->Status = STATUS_SUCCESS; break;
default: RIPMSG1(RIP_ERROR, "Unknown Params->CalloutType 0x%x", Params->CalloutType); Params->Status = STATUS_UNSUCCESSFUL; }
LeaveCrit();
RetThreadCallOut: /*
* Signal that the Callout has been ended. */ KeSetEvent(pInitData->pPowerReadyEvent, EVENT_INCREMENT, FALSE); }
/***************************************************************************\
* VideoPortCallout * * History: * 26-Jul-1998 AndreVa Created. \***************************************************************************/ VOID VideoPortCallout( IN PVOID Params) { /*
* To make sure this is a system thread, we create a new thread. */ NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOL fRet; USER_API_MSG m; POWER_INIT initData;
//
// Make sure video has been initialized.
//
if (!gbVideoInitialized) { ((PVIDEO_WIN32K_CALLBACKS_PARAMS)Params)->Status = STATUS_UNSUCCESSFUL; return; }
//
// Make sure the CsrApiPort has been initialized
//
if (!CsrApiPort) { ((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status = STATUS_INVALID_HANDLE; return; }
initData.Params = Params; initData.pPowerReadyEvent = CreateKernelEvent(SynchronizationEvent, FALSE); if (initData.pPowerReadyEvent == NULL) { Status = STATUS_NO_MEMORY; goto RetCallOut; }
UserAssert(ISCSRSS());
EnterCrit(); fRet = InitCreateSystemThreadsMsg(&m, CST_POWER, &initData, 0, FALSE); LeaveCrit();
if (fRet) { Status = LpcRequestPort(CsrApiPort, (PPORT_MESSAGE)&m);
if (NT_SUCCESS(Status)) { KeWaitForSingleObject(initData.pPowerReadyEvent, WrUserRequest, KernelMode, FALSE, NULL); Status = ((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status; } }
RetCallOut:
if (initData.pPowerReadyEvent) { FreeKernelEvent(&initData.pPowerReadyEvent); }
((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status = Status; }
|