Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1262 lines
39 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: power.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the code to implement power management.
  7. *
  8. * History:
  9. * 02-Dec-1996 JerrySh Created.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <ntcsrmsg.h>
  14. #include "csrmsg.h"
  15. #include "ntddvdeo.h"
  16. #pragma alloc_text(INIT, InitializePowerRequestList)
  17. BOOL IsSessionSwitchBlocked();
  18. NTSTATUS UserSessionSwitchBlock_Start();
  19. void UserSessionSwitchBlock_End();
  20. extern BOOL gbUserInitialized;
  21. #define SWITCHACTION_RESETMODE 0x1
  22. #define SWITCHACTION_REENUMERATE 0x2
  23. LIST_ENTRY gPowerRequestList;
  24. PFAST_MUTEX gpPowerRequestMutex;
  25. PKEVENT gpEventPowerRequest;
  26. ULONG gulDelayedSwitchAction = 0;
  27. typedef struct tagPOWERREQUEST {
  28. LIST_ENTRY PowerRequestLink;
  29. union {
  30. KEVENT Event;
  31. WIN32_POWEREVENT_PARAMETERS CapturedParms;
  32. };
  33. NTSTATUS Status;
  34. PKWIN32_POWEREVENT_PARAMETERS Parms;
  35. } POWERREQUEST, *PPOWERREQUEST;
  36. PPOWERREQUEST gpPowerRequestCurrent;
  37. __inline VOID EnterPowerCrit(
  38. VOID)
  39. {
  40. KeEnterCriticalRegion();
  41. ExAcquireFastMutexUnsafe(gpPowerRequestMutex);
  42. }
  43. __inline VOID LeavePowerCrit(
  44. VOID)
  45. {
  46. ExReleaseFastMutexUnsafe(gpPowerRequestMutex);
  47. KeLeaveCriticalRegion();
  48. }
  49. /***************************************************************************\
  50. * CancelPowerRequest
  51. *
  52. * The power request can't be satisfied because the worker thread is gone.
  53. *
  54. * History:
  55. * 20-Oct-1998 JerrySh Created.
  56. \***************************************************************************/
  57. VOID
  58. CancelPowerRequest(
  59. PPOWERREQUEST pPowerRequest)
  60. {
  61. UserAssert(pPowerRequest != gpPowerRequestCurrent);
  62. pPowerRequest->Status = STATUS_UNSUCCESSFUL;
  63. /*
  64. * If it was a callout, tell the waiting thread to proceed.
  65. * If it was an event, there is no waiting thread but we need to
  66. * free the pool
  67. */
  68. if (pPowerRequest->Parms) {
  69. UserFreePool(pPowerRequest);
  70. } else {
  71. KeSetEvent(&pPowerRequest->Event, EVENT_INCREMENT, FALSE);
  72. }
  73. }
  74. /***************************************************************************\
  75. * QueuePowerRequest
  76. *
  77. * Insert a power request into the list and wakeup CSRSS to process it.
  78. *
  79. * History:
  80. * 20-Oct-1998 JerrySh Created.
  81. \***************************************************************************/
  82. NTSTATUS
  83. QueuePowerRequest(
  84. PKWIN32_POWEREVENT_PARAMETERS Parms)
  85. {
  86. NTSTATUS Status = STATUS_SUCCESS;
  87. PPOWERREQUEST pPowerRequest;
  88. TL tlPool;
  89. UserAssert(gpEventPowerRequest != NULL);
  90. UserAssert(gpPowerRequestMutex != NULL);
  91. /*
  92. * Allocate and initialize the power request.
  93. */
  94. pPowerRequest = UserAllocPoolNonPagedNS(sizeof(POWERREQUEST), TAG_POWER);
  95. if (pPowerRequest == NULL) {
  96. return STATUS_NO_MEMORY;
  97. }
  98. /*
  99. * If this is a callout, there are no paramaters. Initialize the event to wait on.
  100. * If this is an event, capture the parameters to be freed after the event
  101. * is dispatched.
  102. */
  103. if (Parms) {
  104. pPowerRequest->CapturedParms = *Parms;
  105. pPowerRequest->Parms = &pPowerRequest->CapturedParms;
  106. } else {
  107. KeInitializeEvent(&pPowerRequest->Event, SynchronizationEvent, FALSE);
  108. pPowerRequest->Parms = NULL;
  109. }
  110. /*
  111. * Insert the power request into the list.
  112. */
  113. EnterPowerCrit();
  114. if (gbNoMorePowerCallouts) {
  115. Status = STATUS_UNSUCCESSFUL;
  116. } else {
  117. InsertHeadList(&gPowerRequestList, &pPowerRequest->PowerRequestLink);
  118. }
  119. LeavePowerCrit();
  120. /*
  121. * if this thread is gone through attach process, or
  122. * If this is a system thread or a non-GUI thread, tell CSRSS to do the
  123. * work and wait for it to finish. Otherwise, we'll do the work ourselves.
  124. */
  125. if (NT_SUCCESS(Status)) {
  126. if (PsIsSystemThread(PsGetCurrentThread()) ||
  127. KeIsAttachedProcess() ||
  128. W32GetCurrentThread() == NULL) {
  129. KeSetEvent(gpEventPowerRequest, EVENT_INCREMENT, FALSE);
  130. } else {
  131. EnterCrit();
  132. ThreadLockPool(PtiCurrent(), pPowerRequest, &tlPool);
  133. xxxUserPowerCalloutWorker();
  134. ThreadUnlockPool(PtiCurrent(), &tlPool);
  135. LeaveCrit();
  136. }
  137. /*
  138. * If this is a callout, wait for it and then free the request.
  139. * Otherwise, it is an event, and we do not need to wait for it
  140. * to complete. The request will be freed after it is dequeued.
  141. */
  142. if (Parms) {
  143. return(STATUS_SUCCESS);
  144. } else {
  145. Status = KeWaitForSingleObject(&pPowerRequest->Event,
  146. WrUserRequest,
  147. KernelMode,
  148. FALSE,
  149. NULL);
  150. if (NT_SUCCESS(Status)) {
  151. Status = pPowerRequest->Status;
  152. }
  153. }
  154. }
  155. /*
  156. * Free the power request.
  157. */
  158. UserAssert(pPowerRequest != gpPowerRequestCurrent);
  159. UserFreePool(pPowerRequest);
  160. return Status;
  161. }
  162. /***************************************************************************\
  163. * UnqueuePowerRequest
  164. *
  165. * Remove a power request from the list.
  166. *
  167. * History:
  168. * 20-Oct-1998 JerrySh Created.
  169. \***************************************************************************/
  170. PPOWERREQUEST
  171. UnqueuePowerRequest(
  172. VOID)
  173. {
  174. PLIST_ENTRY pEntry;
  175. PPOWERREQUEST pPowerRequest = NULL;
  176. /*
  177. * Remove a power request from the list.
  178. */
  179. EnterPowerCrit();
  180. if (!IsListEmpty(&gPowerRequestList)) {
  181. pEntry = RemoveTailList(&gPowerRequestList);
  182. pPowerRequest = CONTAINING_RECORD(pEntry, POWERREQUEST, PowerRequestLink);
  183. }
  184. LeavePowerCrit();
  185. return pPowerRequest;
  186. }
  187. /***************************************************************************\
  188. * InitializePowerRequestList
  189. *
  190. * Initialize global power request list state.
  191. *
  192. * History:
  193. * 20-Oct-1998 JerrySh Created.
  194. \***************************************************************************/
  195. NTSTATUS
  196. InitializePowerRequestList(
  197. HANDLE hPowerRequestEvent)
  198. {
  199. NTSTATUS Status;
  200. InitializeListHead(&gPowerRequestList);
  201. Status = ObReferenceObjectByHandle(hPowerRequestEvent,
  202. EVENT_ALL_ACCESS,
  203. *ExEventObjectType,
  204. KernelMode,
  205. &gpEventPowerRequest,
  206. NULL);
  207. if (!NT_SUCCESS(Status)) {
  208. return Status;
  209. }
  210. gpPowerRequestMutex = UserAllocPoolNonPagedNS(sizeof(FAST_MUTEX), TAG_POWER);
  211. if (gpPowerRequestMutex == NULL) {
  212. return STATUS_NO_MEMORY;
  213. }
  214. ExInitializeFastMutex(gpPowerRequestMutex);
  215. return STATUS_SUCCESS;
  216. }
  217. /***************************************************************************\
  218. * CleanupPowerRequestList
  219. *
  220. * Cancel any pending power requests.
  221. *
  222. * History:
  223. * 20-Oct-1998 JerrySh Created.
  224. \***************************************************************************/
  225. VOID
  226. CleanupPowerRequestList(
  227. VOID)
  228. {
  229. PPOWERREQUEST pPowerRequest;
  230. /*
  231. * Make sure no new power requests come in.
  232. */
  233. gbNoMorePowerCallouts = TRUE;
  234. /*
  235. * If we never allocated anything, there's nothing to clean up.
  236. */
  237. if (gpPowerRequestMutex == NULL) {
  238. return;
  239. }
  240. /*
  241. * Mark any pending power requests as cacelled.
  242. */
  243. while ((pPowerRequest = UnqueuePowerRequest()) != NULL) {
  244. CancelPowerRequest(pPowerRequest);
  245. }
  246. }
  247. /***************************************************************************\
  248. * DeletePowerRequestList
  249. *
  250. * Clean up any global power request state.
  251. *
  252. * History:
  253. * 20-Oct-1998 JerrySh Created.
  254. \***************************************************************************/
  255. VOID
  256. DeletePowerRequestList(
  257. VOID)
  258. {
  259. if (gpPowerRequestMutex) {
  260. /*
  261. * Make sure there are no pending power requests.
  262. */
  263. UserAssert(IsListEmpty(&gPowerRequestList));
  264. /*
  265. * Free the power request structures.
  266. */
  267. UserFreePool(gpPowerRequestMutex);
  268. gpPowerRequestMutex = NULL;
  269. }
  270. }
  271. /***************************************************************************\
  272. * UserPowerEventCalloutWorker
  273. *
  274. * History:
  275. * 02-Dec-1996 JerrySh Created.
  276. \***************************************************************************/
  277. NTSTATUS xxxUserPowerEventCalloutWorker(
  278. PKWIN32_POWEREVENT_PARAMETERS Parms)
  279. {
  280. BROADCASTSYSTEMMSGPARAMS bsmParams;
  281. NTSTATUS Status = STATUS_SUCCESS;
  282. PSPOWEREVENTTYPE EventNumber = Parms->EventNumber;
  283. ULONG_PTR Code = Parms->Code;
  284. BOOL bCurrentPowerOn;
  285. ULONGLONG ullLastSleepTime;
  286. BOOL bGotLastSleepTime;
  287. /*
  288. * Make sure CSRSS is still running.
  289. */
  290. if (gbNoMorePowerCallouts) {
  291. return STATUS_UNSUCCESSFUL;
  292. }
  293. switch (EventNumber) {
  294. case PsW32FullWake:
  295. if (!gbRemoteSession) {
  296. /*
  297. * Let all the services know that they can resume operation.
  298. * There is no corresponding POWER_ACTION for this, but since this
  299. * is a non-query event, PowerActionNone is as good as any.
  300. */
  301. LeaveCrit();
  302. IoPnPDeliverServicePowerNotification(PowerActionNone,
  303. PBT_APMRESUMESUSPEND,
  304. 0,
  305. FALSE);
  306. EnterCrit();
  307. }
  308. /*
  309. * Let all the applications know that they can resume operation.
  310. * We must not send this message to a session, if it was created after machine went into sleep
  311. */
  312. /*
  313. * One of the side effects of NtPowerInformation is that it will
  314. * dispatch pending power events. So we cannot call it with the user
  315. * critsec held.
  316. *
  317. * Note: Same thing is done for IoPnPDeliverServicePowerNotification.
  318. */
  319. LeaveCrit();
  320. bGotLastSleepTime = ZwPowerInformation(LastSleepTime, NULL, 0, &ullLastSleepTime, sizeof(ULONGLONG)) == STATUS_SUCCESS;
  321. EnterCrit();
  322. if (!bGotLastSleepTime || gSessionCreationTime < ullLastSleepTime) {
  323. bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  324. bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE;
  325. xxxSendMessageBSM(NULL,
  326. WM_POWERBROADCAST,
  327. PBT_APMRESUMESUSPEND,
  328. 0,
  329. &bsmParams);
  330. }
  331. break;
  332. case PsW32EventCode:
  333. /*
  334. * Post a message to winlogon, and let them put up a message box
  335. * or play a sound.
  336. */
  337. if (gspwndLogonNotify) {
  338. glinp.ptiLastWoken = GETPTI(gspwndLogonNotify);
  339. _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY, LOGON_POWEREVENT, (ULONG)Code);
  340. Status = STATUS_SUCCESS;
  341. } else {
  342. Status = STATUS_UNSUCCESSFUL;
  343. }
  344. break;
  345. case PsW32PowerPolicyChanged:
  346. /*
  347. * Set video timeout value.
  348. */
  349. xxxSystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, (ULONG)Code, 0, 0);
  350. xxxSystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, (ULONG)Code, 0, 0);
  351. break;
  352. case PsW32SystemPowerState:
  353. if (!gbRemoteSession) {
  354. /*
  355. * Let all the services know that the power status has changed.
  356. * There is no corresponding POWER_ACTION for this, but since this
  357. * is a non-query event, PowerActionNone is as good as any.
  358. */
  359. LeaveCrit();
  360. IoPnPDeliverServicePowerNotification(PowerActionNone,
  361. PBT_APMPOWERSTATUSCHANGE,
  362. 0,
  363. FALSE);
  364. EnterCrit();
  365. }
  366. /*
  367. * Let all the applications know that the power status has changed.
  368. */
  369. bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  370. bsmParams.dwFlags = BSF_POSTMESSAGE;
  371. xxxSendMessageBSM(NULL,
  372. WM_POWERBROADCAST,
  373. PBT_APMPOWERSTATUSCHANGE,
  374. 0,
  375. &bsmParams);
  376. break;
  377. case PsW32SystemTime:
  378. /*
  379. * Let all the applications know that the system time has changed.
  380. */
  381. bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  382. bsmParams.dwFlags = BSF_POSTMESSAGE;
  383. xxxSendMessageBSM(NULL,
  384. WM_TIMECHANGE,
  385. 0,
  386. 0,
  387. &bsmParams);
  388. break;
  389. case PsW32DisplayState:
  390. /*
  391. * Set video timeout active status.
  392. */
  393. xxxSystemParametersInfo(SPI_SETLOWPOWERACTIVE, !Code, 0, 0);
  394. xxxSystemParametersInfo(SPI_SETPOWEROFFACTIVE, !Code, 0, 0);
  395. break;
  396. case PsW32GdiOff:
  397. /*
  398. * At this point we will disable the display device, if no protocol switch is in progress.
  399. */
  400. if (!gfSwitchInProgress) {
  401. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3);
  402. bCurrentPowerOn = DrvQueryMDEVPowerState(gpDispInfo->pmdev);
  403. if (bCurrentPowerOn) {
  404. SafeDisableMDEV();
  405. }
  406. DrvSetMDEVPowerState(gpDispInfo->pmdev, FALSE);
  407. } else {
  408. Status = STATUS_UNSUCCESSFUL;
  409. }
  410. break;
  411. case PsW32GdiOn:
  412. /*
  413. * Call video driver to turn the display back on, if no protocol
  414. * switch is in progress.
  415. */
  416. if (!gfSwitchInProgress) {
  417. bCurrentPowerOn = DrvQueryMDEVPowerState(gpDispInfo->pmdev);
  418. if (!bCurrentPowerOn) {
  419. SafeEnableMDEV();
  420. }
  421. DrvSetMDEVPowerState(gpDispInfo->pmdev, TRUE);
  422. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  423. } else {
  424. Status = STATUS_UNSUCCESSFUL;
  425. break;
  426. }
  427. /*
  428. * Repaint the whole screen.
  429. */
  430. xxxUserResetDisplayDevice();
  431. if (gulDelayedSwitchAction) {
  432. HANDLE pdo;
  433. //
  434. // The first ACPI device is the one respond to hotkey.
  435. //
  436. PVOID PhysDisp = DrvWakeupHandler(&pdo);
  437. if (PhysDisp && (gulDelayedSwitchAction & SWITCHACTION_RESETMODE)) {
  438. UNICODE_STRING strDeviceName;
  439. DEVMODEW NewMode;
  440. ULONG bPrune;
  441. if (DrvDisplaySwitchHandler(PhysDisp, &strDeviceName, &NewMode, &bPrune)) {
  442. /*
  443. * CSRSS is not the only process to deliver power callouts.
  444. */
  445. bPrune = (bPrune ? 0 : CDS_RAWMODE) | CDS_TRYCLOSEST | CDS_RESET;
  446. if (!ISCSRSS()) {
  447. xxxUserChangeDisplaySettings(NULL,
  448. NULL,
  449. grpdeskRitInput,
  450. bPrune,
  451. 0,
  452. KernelMode);
  453. } else {
  454. xxxUserChangeDisplaySettings(NULL,
  455. NULL,
  456. NULL,
  457. bPrune,
  458. 0,
  459. KernelMode);
  460. }
  461. }
  462. //
  463. // If there is a requirement to reenumerate sub-devices.
  464. //
  465. if (pdo && (gulDelayedSwitchAction & SWITCHACTION_REENUMERATE)) {
  466. IoInvalidateDeviceRelations((PDEVICE_OBJECT)pdo, BusRelations);
  467. }
  468. }
  469. }
  470. gulDelayedSwitchAction = 0;
  471. break;
  472. default:
  473. Status = STATUS_NOT_IMPLEMENTED;
  474. break;
  475. }
  476. return Status;
  477. }
  478. /***************************************************************************\
  479. * UserPowerEventCallout
  480. *
  481. * History:
  482. * 02-Dec-1996 JerrySh Created.
  483. \***************************************************************************/
  484. NTSTATUS UserPowerEventCallout(
  485. PKWIN32_POWEREVENT_PARAMETERS Parms)
  486. {
  487. /*
  488. * Make sure CSRSS is running.
  489. */
  490. if (!gbVideoInitialized || gbNoMorePowerCallouts) {
  491. return STATUS_UNSUCCESSFUL;
  492. }
  493. UserAssert(gpepCSRSS != NULL);
  494. /*
  495. * Process the power request.
  496. */
  497. return QueuePowerRequest(Parms);
  498. }
  499. /***************************************************************************\
  500. * UserPowerStateCalloutWorker
  501. *
  502. * History:
  503. * 02-Dec-1996 JerrySh Created.
  504. \***************************************************************************/
  505. NTSTATUS xxxUserPowerStateCalloutWorker(
  506. VOID)
  507. {
  508. BOOL fContinue;
  509. BROADCASTSYSTEMMSGPARAMS bsmParams;
  510. POWER_ACTION powerOperation;
  511. NTSTATUS Status = STATUS_SUCCESS;
  512. TL tlpwnd;
  513. POWERSTATETASK Task = gPowerState.PowerStateTask;
  514. ULONGLONG ullLastSleepTime;
  515. BOOL bGotLastSleepTime;
  516. /*
  517. * By now we must have alrady blocked session switch, it's blocked only
  518. * for win32k belonging to active console session.
  519. */
  520. UserAssert(SharedUserData->ActiveConsoleId != gSessionId || IsSessionSwitchBlocked());
  521. /*
  522. * Make sure CSRSS is still running.
  523. */
  524. if (gbNoMorePowerCallouts) {
  525. return STATUS_UNSUCCESSFUL;
  526. }
  527. switch (Task) {
  528. case PowerState_Init:
  529. /*
  530. * Store the event so this thread can be promoted later.
  531. */
  532. EnterPowerCrit();
  533. gPowerState.pEvent = PtiCurrent()->pEventQueueServer;
  534. LeavePowerCrit();
  535. break;
  536. case PowerState_QueryApps:
  537. if (!gPowerState.fCritical) {
  538. /*
  539. * Ask the applications if we can suspend operation.
  540. */
  541. if (gPowerState.fQueryAllowed) {
  542. gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  543. gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG;
  544. if (gPowerState.fUIAllowed) {
  545. gPowerState.bsmParams.dwFlags |= BSF_ALLOWSFW;
  546. }
  547. if (gPowerState.fOverrideApps == FALSE) {
  548. gPowerState.bsmParams.dwFlags |= (BSF_QUERY | BSF_NOTIMEOUTIFNOTHUNG);
  549. }
  550. fContinue = xxxSendMessageBSM(NULL,
  551. WM_POWERBROADCAST,
  552. PBT_APMQUERYSUSPEND,
  553. gPowerState.fUIAllowed,
  554. &gPowerState.bsmParams);
  555. if (fContinue && !gbRemoteSession) {
  556. /*
  557. * Ask the services if we can suspend operation.
  558. * Map the power action event as needed.
  559. */
  560. if (gPowerState.psParams.MinSystemState == PowerSystemHibernate) {
  561. powerOperation = PowerActionHibernate;
  562. } else {
  563. powerOperation = gPowerState.psParams.SystemAction;
  564. }
  565. LeaveCrit();
  566. fContinue = IoPnPDeliverServicePowerNotification(
  567. powerOperation,
  568. PBT_APMQUERYSUSPEND,
  569. gPowerState.fUIAllowed,
  570. TRUE); // synchronous query
  571. EnterCrit();
  572. }
  573. /*
  574. * If an app or service says to abort and we're not in
  575. * override apps or critical mode, return query failed.
  576. */
  577. if (!(fContinue || gPowerState.fOverrideApps || gPowerState.fCritical)) {
  578. Status = STATUS_CANCELLED;
  579. }
  580. }
  581. }
  582. break;
  583. case PowerState_QueryFailed:
  584. /*
  585. * Only send a suspend failed message to the applications, since pnp
  586. * will already have delivered the suspend failed message to services if
  587. * one of those aborted the query.
  588. */
  589. gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  590. gPowerState.bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE;
  591. xxxSendMessageBSM(NULL,
  592. WM_POWERBROADCAST,
  593. PBT_APMQUERYSUSPENDFAILED,
  594. 0,
  595. &gPowerState.bsmParams);
  596. EnterPowerCrit();
  597. gPowerState.pEvent = NULL;
  598. gPowerState.fInProgress = FALSE;
  599. LeavePowerCrit();
  600. break;
  601. case PowerState_SuspendApps:
  602. if (!gPowerState.fCritical) {
  603. if (!gbRemoteSession) {
  604. /*
  605. * Map the power action event as needed.
  606. */
  607. if (gPowerState.psParams.MinSystemState == PowerSystemHibernate) {
  608. powerOperation = PowerActionHibernate;
  609. } else {
  610. powerOperation = gPowerState.psParams.SystemAction;
  611. }
  612. LeaveCrit();
  613. IoPnPDeliverServicePowerNotification(powerOperation,
  614. PBT_APMSUSPEND,
  615. 0,
  616. FALSE);
  617. EnterCrit();
  618. }
  619. gPowerState.bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  620. gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG;
  621. xxxSendMessageBSM(NULL,
  622. WM_POWERBROADCAST,
  623. PBT_APMSUSPEND,
  624. 0,
  625. &gPowerState.bsmParams);
  626. }
  627. /*
  628. * Clear the event so the thread won't wake up prematurely.
  629. */
  630. EnterPowerCrit();
  631. gPowerState.pEvent = NULL;
  632. LeavePowerCrit();
  633. break;
  634. case PowerState_ShowUI:
  635. /*
  636. * if this is not session 0 show ui for sessions.
  637. * we shall take this ui off when we resume apps
  638. * For session 0 we call PowerState_NotifyWL which takes care of it.
  639. */
  640. if ((gSessionId != 0 ) && (gspwndLogonNotify != NULL)) {
  641. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  642. Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify,
  643. WM_LOGONNOTIFY,
  644. LOGON_SHOW_POWER_MESSAGE,
  645. (LPARAM)&gPowerState.psParams);
  646. ThreadUnlock(&tlpwnd);
  647. }
  648. break;
  649. case PowerState_NotifyWL:
  650. if (gspwndLogonNotify != NULL) {
  651. PWND pwndActive;
  652. if (gpqForeground && (pwndActive = gpqForeground->spwndActive) &&
  653. (GetFullScreen(pwndActive) == FULLSCREEN ||
  654. GetFullScreen(pwndActive) == FULLSCREENMIN)) {
  655. gPowerState.psParams.FullScreenMode = TRUE;
  656. } else {
  657. gPowerState.psParams.FullScreenMode = FALSE;
  658. }
  659. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  660. Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify,
  661. WM_LOGONNOTIFY,
  662. LOGON_POWERSTATE,
  663. (LPARAM)&gPowerState.psParams);
  664. ThreadUnlock(&tlpwnd);
  665. if (!NT_SUCCESS(Status)) {
  666. /*
  667. * If we failed to to this power operation, don't lock the
  668. * console.
  669. */
  670. gPowerState.psParams.Flags &= ~POWER_ACTION_LOCK_CONSOLE;
  671. }
  672. }
  673. break;
  674. case PowerState_ResumeApps:
  675. /*
  676. * If this is active console we need to lock it.
  677. */
  678. if ((gPowerState.psParams.Flags & POWER_ACTION_LOCK_CONSOLE) &&
  679. (gSessionId == SharedUserData->ActiveConsoleId) &&
  680. (gspwndLogonNotify != NULL)) {
  681. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  682. _PostMessage(gspwndLogonNotify,
  683. WM_LOGONNOTIFY,
  684. LOGON_LOCKWORKSTATION,
  685. LOCK_RESUMEHIBERNATE);
  686. ThreadUnlock(&tlpwnd);
  687. }
  688. //
  689. // We dont need to remove power message, if we did not post one.
  690. //
  691. /*
  692. * One of the side effects of NtPowerInformation is that it will
  693. * dispatch pending power events. So we can not call it with the
  694. * user critsec held.
  695. *
  696. * Note: The same thing is done for IoPnPDeliverServicePowerNotification.
  697. */
  698. LeaveCrit();
  699. bGotLastSleepTime = ZwPowerInformation(LastSleepTime, NULL, 0, &ullLastSleepTime, sizeof(ULONGLONG)) == STATUS_SUCCESS;
  700. EnterCrit();
  701. if (!bGotLastSleepTime || gSessionCreationTime < ullLastSleepTime) {
  702. if (gSessionId != 0 && gspwndLogonNotify != NULL) {
  703. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  704. Status = (NTSTATUS)xxxSendMessage(gspwndLogonNotify,
  705. WM_LOGONNOTIFY,
  706. LOGON_REMOVE_POWER_MESSAGE,
  707. (LPARAM)&gPowerState.psParams);
  708. ThreadUnlock(&tlpwnd);
  709. }
  710. }
  711. /*
  712. * The power state broadcast is over.
  713. */
  714. EnterPowerCrit();
  715. gPowerState.fInProgress = FALSE;
  716. LeavePowerCrit();
  717. /*
  718. * Tickle the input time so we don't fire up a screen saver right away
  719. * and remember that the monitor is on.
  720. */
  721. glinp.timeLastInputMessage = NtGetTickCount();
  722. glinp.dwFlags &= ~LINP_POWEROFF;
  723. if (!gbRemoteSession) {
  724. /*
  725. * Re-init the keyboard state.
  726. */
  727. InitKeyboardState();
  728. /*
  729. * Let all the services know that we're waking up. There is no
  730. * corresponding POWER_ACTION for this, but since this is a
  731. * non-query event, PowerActionNone is as good as any.
  732. */
  733. LeaveCrit();
  734. IoPnPDeliverServicePowerNotification(PowerActionNone,
  735. PBT_APMRESUMEAUTOMATIC,
  736. 0,
  737. FALSE);
  738. EnterCrit();
  739. }
  740. /*
  741. * Let all the applications know that we're waking up.
  742. */
  743. bsmParams.dwRecipients = BSM_ALLDESKTOPS;
  744. bsmParams.dwFlags = BSF_QUEUENOTIFYMESSAGE;
  745. xxxSendMessageBSM(NULL,
  746. WM_POWERBROADCAST,
  747. PBT_APMRESUMEAUTOMATIC,
  748. 0,
  749. &bsmParams);
  750. break;
  751. default:
  752. RIPMSG1(RIP_ERROR, "Unknown task 0x%x", Task);
  753. break;
  754. }
  755. return Status;
  756. }
  757. /***************************************************************************\
  758. * UserPowerStateCallout
  759. *
  760. * History:
  761. * 02-Dec-1996 JerrySh Created.
  762. \***************************************************************************/
  763. NTSTATUS UserPowerStateCallout(
  764. PKWIN32_POWERSTATE_PARAMETERS Parms)
  765. {
  766. POWERSTATETASK Task = Parms->PowerStateTask;
  767. BOOLEAN Promotion = Parms->Promotion;
  768. POWER_ACTION SystemAction = Parms->SystemAction;
  769. SYSTEM_POWER_STATE MinSystemState = Parms->MinSystemState;
  770. ULONG Flags = Parms->Flags;
  771. NTSTATUS Status;
  772. if (Task == PowerState_BlockSessionSwitch) {
  773. /*
  774. * Don't allow active console session switch while we are in power
  775. * callouts. First try to block the session switch.
  776. */
  777. return UserSessionSwitchBlock_Start();
  778. }
  779. if (Task == PowerState_UnBlockSessionSwitch) {
  780. UserAssert(IsSessionSwitchBlocked());
  781. UserSessionSwitchBlock_End();
  782. return STATUS_SUCCESS;
  783. }
  784. /*
  785. * Make sure CSRSS is running.
  786. */
  787. if (!gbVideoInitialized || gbNoMorePowerCallouts || !gspwndLogonNotify) {
  788. return STATUS_UNSUCCESSFUL;
  789. }
  790. UserAssert(gpepCSRSS != NULL);
  791. EnterPowerCrit();
  792. if (Task == PowerState_Init) {
  793. /*
  794. * Make sure we're not trying to promote a non-existent request
  795. * or start a new one when we're already doing it.
  796. */
  797. if ((Promotion && !gPowerState.fInProgress) ||
  798. (!Promotion && gPowerState.fInProgress)) {
  799. LeavePowerCrit();
  800. return STATUS_INVALID_PARAMETER;
  801. }
  802. /*
  803. * Save our state.
  804. */
  805. gPowerState.fInProgress = TRUE;
  806. gPowerState.fOverrideApps = (Flags & POWER_ACTION_OVERRIDE_APPS) != 0;
  807. gPowerState.fCritical = (Flags & POWER_ACTION_CRITICAL) != 0;
  808. gPowerState.fQueryAllowed = (Flags & POWER_ACTION_QUERY_ALLOWED) != 0;
  809. gPowerState.fUIAllowed = (Flags & POWER_ACTION_UI_ALLOWED) != 0;
  810. gPowerState.psParams.SystemAction = SystemAction;
  811. gPowerState.psParams.MinSystemState = MinSystemState;
  812. gPowerState.psParams.Flags = Flags;
  813. if (gPowerState.fOverrideApps) {
  814. gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_FORCEIFHUNG;
  815. }
  816. if (gPowerState.fCritical) {
  817. gPowerState.bsmParams.dwFlags = BSF_NOHANG | BSF_QUERY;
  818. }
  819. if (gPowerState.pEvent) {
  820. KeSetEvent(gPowerState.pEvent, EVENT_INCREMENT, FALSE);
  821. }
  822. }
  823. gPowerState.PowerStateTask = Task;
  824. LeavePowerCrit();
  825. /*
  826. * If this is a promotion, we're done.
  827. */
  828. if (Promotion) {
  829. return STATUS_SUCCESS;
  830. }
  831. /*
  832. * Process the power request.
  833. */
  834. Status = QueuePowerRequest(NULL);
  835. if (Task == PowerState_QueryApps && !NT_SUCCESS(Status)) {
  836. /*
  837. * Query was refused.
  838. */
  839. Parms->fQueryDenied = TRUE;
  840. }
  841. return Status;
  842. }
  843. /***************************************************************************\
  844. * UserPowerCalloutWorker
  845. *
  846. * Pull any pending power requests off the list and call the appropriate
  847. * power callout function.
  848. *
  849. * History:
  850. * 02-Dec-1996 JerrySh Created.
  851. \***************************************************************************/
  852. VOID
  853. xxxUserPowerCalloutWorker(
  854. VOID)
  855. {
  856. PPOWERREQUEST pPowerRequest;
  857. TL tlPool;
  858. while ((pPowerRequest = UnqueuePowerRequest()) != NULL) {
  859. /*
  860. * Make sure the event gets signalled even if the thread dies in a
  861. * callback or the waiting thread might get stuck.
  862. */
  863. ThreadLockPoolCleanup(PtiCurrent(), pPowerRequest, &tlPool, CancelPowerRequest);
  864. /*
  865. * Call the appropriate power worker function.
  866. */
  867. gpPowerRequestCurrent = pPowerRequest;
  868. if (pPowerRequest->Parms) {
  869. pPowerRequest->Status = xxxUserPowerEventCalloutWorker(pPowerRequest->Parms);
  870. } else {
  871. pPowerRequest->Status = xxxUserPowerStateCalloutWorker();
  872. }
  873. gpPowerRequestCurrent = NULL;
  874. /*
  875. * If it was a callout, tell the waiting thread to proceed. If it
  876. * was an event, there is no waiting thread but we need to free the
  877. * pool.
  878. */
  879. ThreadUnlockPoolCleanup(PtiCurrent(), &tlPool);
  880. if (pPowerRequest->Parms) {
  881. UserFreePool(pPowerRequest);
  882. } else {
  883. KeSetEvent(&pPowerRequest->Event, EVENT_INCREMENT, FALSE);
  884. }
  885. }
  886. }
  887. /***************************************************************************\
  888. * VideoPortCalloutThread
  889. *
  890. * Call the appropriate power callout function and return.
  891. *
  892. * History:
  893. * 02-Dec-1996 JerrySh Created.
  894. \***************************************************************************/
  895. VOID
  896. VideoPortCalloutThread(
  897. PPOWER_INIT pInitData)
  898. {
  899. NTSTATUS Status;
  900. PVIDEO_WIN32K_CALLBACKS_PARAMS Params = pInitData->Params;
  901. Params->Status = InitSystemThread(NULL);
  902. if (!NT_SUCCESS(Params->Status)) {
  903. goto RetThreadCallOut;
  904. }
  905. while (1) {
  906. EnterCrit();
  907. if (!gfSwitchInProgress) {
  908. break;
  909. } else {
  910. LeaveCrit();
  911. Status = KeWaitForSingleObject(gpevtVideoportCallout, WrUserRequest, KernelMode, FALSE, NULL);
  912. }
  913. }
  914. if (IsRemoteConnection()) {
  915. LeaveCrit();
  916. Params->Status = STATUS_UNSUCCESSFUL;
  917. goto RetThreadCallOut;
  918. }
  919. switch (Params->CalloutType) {
  920. case VideoWakeupCallout:
  921. gulDelayedSwitchAction |= SWITCHACTION_RESETMODE;
  922. break;
  923. case VideoDisplaySwitchCallout:
  924. {
  925. UNICODE_STRING strDeviceName;
  926. DEVMODEW NewMode;
  927. ULONG bPrune;
  928. Params->Status = STATUS_SUCCESS;
  929. if (!DrvQueryMDEVPowerState(gpDispInfo->pmdev)) {
  930. gulDelayedSwitchAction |= ((Params->PhysDisp != NULL) ? SWITCHACTION_RESETMODE : 0) |
  931. ((Params->Param) ? SWITCHACTION_REENUMERATE : 0);
  932. break;
  933. }
  934. gulDelayedSwitchAction = 0;
  935. if (Params->PhysDisp != NULL) {
  936. if (DrvDisplaySwitchHandler(Params->PhysDisp, &strDeviceName, &NewMode, &bPrune)) {
  937. DESKRESTOREDATA drdRestore;
  938. drdRestore.pdeskRestore = NULL;
  939. /*
  940. * CSRSS is not the only process to deliver power callouts.
  941. */
  942. if (!ISCSRSS() ||
  943. NT_SUCCESS(xxxSetCsrssThreadDesktop(grpdeskRitInput, &drdRestore))) {
  944. xxxUserChangeDisplaySettings(NULL, NULL, grpdeskRitInput,
  945. ((bPrune) ? 0 : CDS_RAWMODE) | CDS_TRYCLOSEST | CDS_RESET, 0, KernelMode);
  946. if (ISCSRSS()) {
  947. xxxRestoreCsrssThreadDesktop(&drdRestore);
  948. }
  949. }
  950. }
  951. }
  952. }
  953. /*
  954. * If there is a requirement to reenumerate sub-devices.
  955. */
  956. if (Params->Param) {
  957. IoInvalidateDeviceRelations((PDEVICE_OBJECT)Params->Param, BusRelations);
  958. }
  959. break;
  960. case VideoChangeDisplaySettingsCallout:
  961. {
  962. DEVMODEW Devmode;
  963. DESKRESTOREDATA drdRestore;
  964. memset(&Devmode, 0, sizeof(DEVMODEW));
  965. Devmode.dmSize = sizeof(DEVMODEW);
  966. Devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  967. Devmode.dmBitsPerPel = 4;
  968. Devmode.dmPelsWidth = 640;
  969. Devmode.dmPelsHeight = 480;
  970. drdRestore.pdeskRestore = NULL;
  971. /*
  972. * CSRSS is not the only process to deliver power callouts.
  973. */
  974. if (!ISCSRSS() ||
  975. NT_SUCCESS(xxxSetCsrssThreadDesktop(grpdeskRitInput, &drdRestore))) {
  976. xxxUserChangeDisplaySettings(NULL, &Devmode, grpdeskRitInput, CDS_RESET, NULL, KernelMode);
  977. if (ISCSRSS()) {
  978. xxxRestoreCsrssThreadDesktop(&drdRestore);
  979. }
  980. }
  981. }
  982. break;
  983. case VideoFindAdapterCallout:
  984. if (Params->Param) {
  985. SafeEnableMDEV();
  986. xxxUserResetDisplayDevice();
  987. } else {
  988. SafeDisableMDEV();
  989. }
  990. Params->Status = STATUS_SUCCESS;
  991. break;
  992. default:
  993. RIPMSG1(RIP_ERROR,
  994. "Unknown Params->CalloutType 0x%x",
  995. Params->CalloutType);
  996. Params->Status = STATUS_UNSUCCESSFUL;
  997. }
  998. LeaveCrit();
  999. RetThreadCallOut:
  1000. /*
  1001. * Signal that the Callout has been ended.
  1002. */
  1003. KeSetEvent(pInitData->pPowerReadyEvent, EVENT_INCREMENT, FALSE);
  1004. }
  1005. /***************************************************************************\
  1006. * VideoPortCallout
  1007. *
  1008. * History:
  1009. * 26-Jul-1998 AndreVa Created.
  1010. \***************************************************************************/
  1011. VOID
  1012. VideoPortCallout(
  1013. IN PVOID Params)
  1014. {
  1015. /*
  1016. * To make sure this is a system thread, we create a new thread.
  1017. */
  1018. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1019. BOOL fRet;
  1020. USER_API_MSG m;
  1021. POWER_INIT initData;
  1022. //
  1023. // Make sure video has been initialized.
  1024. //
  1025. if (!gbVideoInitialized) {
  1026. ((PVIDEO_WIN32K_CALLBACKS_PARAMS)Params)->Status = STATUS_UNSUCCESSFUL;
  1027. return;
  1028. }
  1029. //
  1030. // Make sure the CsrApiPort has been initialized
  1031. //
  1032. if (!CsrApiPort) {
  1033. ((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status = STATUS_INVALID_HANDLE;
  1034. return;
  1035. }
  1036. initData.Params = Params;
  1037. initData.pPowerReadyEvent = CreateKernelEvent(SynchronizationEvent, FALSE);
  1038. if (initData.pPowerReadyEvent == NULL) {
  1039. Status = STATUS_NO_MEMORY;
  1040. goto RetCallOut;
  1041. }
  1042. UserAssert(ISCSRSS());
  1043. EnterCrit();
  1044. fRet = InitCreateSystemThreadsMsg(&m, CST_POWER, &initData, 0, FALSE);
  1045. LeaveCrit();
  1046. if (fRet) {
  1047. Status = LpcRequestPort(CsrApiPort, (PPORT_MESSAGE)&m);
  1048. if (NT_SUCCESS(Status)) {
  1049. KeWaitForSingleObject(initData.pPowerReadyEvent, WrUserRequest,
  1050. KernelMode, FALSE, NULL);
  1051. Status = ((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status;
  1052. }
  1053. }
  1054. RetCallOut:
  1055. if (initData.pPowerReadyEvent) {
  1056. FreeKernelEvent(&initData.pPowerReadyEvent);
  1057. }
  1058. ((PVIDEO_WIN32K_CALLBACKS_PARAMS)(Params))->Status = Status;
  1059. }