[CMAKE]
[reactos.git] / ntoskrnl / po / power.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/po/power.c
5 * PURPOSE: Power Manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "initguid.h"
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 typedef struct _REQUEST_POWER_ITEM
20 {
21 PREQUEST_POWER_COMPLETE CompletionRoutine;
22 POWER_STATE PowerState;
23 PVOID Context;
24 } REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
25
26 PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
27 BOOLEAN PopAcpiPresent = FALSE;
28 POP_POWER_ACTION PopAction;
29 WORK_QUEUE_ITEM PopShutdownWorkItem;
30
31 /* PRIVATE FUNCTIONS *********************************************************/
32
33 static
34 NTSTATUS
35 NTAPI
36 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
37 IN PIRP Irp,
38 IN PVOID Context)
39 {
40 PIO_STACK_LOCATION Stack;
41 PREQUEST_POWER_ITEM RequestPowerItem;
42
43 Stack = IoGetNextIrpStackLocation(Irp);
44 RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
45
46 RequestPowerItem->CompletionRoutine(DeviceObject,
47 Stack->MinorFunction,
48 RequestPowerItem->PowerState,
49 RequestPowerItem->Context,
50 &Irp->IoStatus);
51
52 ExFreePool(Context);
53
54 IoFreeIrp(Irp);
55
56 return STATUS_MORE_PROCESSING_REQUIRED;
57 }
58
59 VOID
60 NTAPI
61 PopCleanupPowerState(IN PPOWER_STATE PowerState)
62 {
63 //UNIMPLEMENTED;
64 }
65
66 NTSTATUS
67 NTAPI
68 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState)
69 {
70 IO_STATUS_BLOCK IoStatusBlock;
71 PDEVICE_OBJECT DeviceObject;
72 PIO_STACK_LOCATION IrpSp;
73 PDEVICE_OBJECT Fdo;
74 NTSTATUS Status;
75 KEVENT Event;
76 PIRP Irp;
77
78 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
79
80 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
81 if (!NT_SUCCESS(Status))
82 {
83 DPRINT1("No system power driver available\n");
84 return STATUS_UNSUCCESSFUL;
85 }
86
87 Fdo = IoGetAttachedDeviceReference(DeviceObject);
88
89 if (Fdo == DeviceObject)
90 {
91 DPRINT("An FDO was not attached\n");
92 return STATUS_UNSUCCESSFUL;
93 }
94
95 KeInitializeEvent(&Event,
96 NotificationEvent,
97 FALSE);
98
99 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
100 Fdo,
101 NULL,
102 0,
103 NULL,
104 &Event,
105 &IoStatusBlock);
106
107 IrpSp = IoGetNextIrpStackLocation(Irp);
108 IrpSp->MinorFunction = IRP_MN_SET_POWER;
109 IrpSp->Parameters.Power.Type = SystemPowerState;
110 IrpSp->Parameters.Power.State.SystemState = PowerState;
111
112 DPRINT("Calling ACPI driver");
113 Status = PoCallDriver(Fdo, Irp);
114 if (Status == STATUS_PENDING)
115 {
116 KeWaitForSingleObject(&Event,
117 Executive,
118 KernelMode,
119 FALSE,
120 NULL);
121 Status = IoStatusBlock.Status;
122 }
123
124 ObDereferenceObject(Fdo);
125
126 return Status;
127 }
128
129 BOOLEAN
130 NTAPI
131 INIT_FUNCTION
132 PoInitSystem(IN ULONG BootPhase)
133 {
134 PVOID NotificationEntry;
135 PCHAR CommandLine;
136 BOOLEAN ForceAcpiDisable = FALSE;
137
138 /* Check if this is phase 1 init */
139 if (BootPhase == 1)
140 {
141 /* Register power button notification */
142 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
143 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
144 (PVOID)&GUID_DEVICE_SYS_BUTTON,
145 IopRootDeviceNode->
146 PhysicalDeviceObject->DriverObject,
147 PopAddRemoveSysCapsCallback,
148 NULL,
149 &NotificationEntry);
150
151 /* Register lid notification */
152 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
153 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
154 (PVOID)&GUID_DEVICE_LID,
155 IopRootDeviceNode->
156 PhysicalDeviceObject->DriverObject,
157 PopAddRemoveSysCapsCallback,
158 NULL,
159 &NotificationEntry);
160 return TRUE;
161 }
162
163 /* Get the Command Line */
164 CommandLine = KeLoaderBlock->LoadOptions;
165
166 /* Upcase it */
167 _strupr(CommandLine);
168
169 /* Check for ACPI disable */
170 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
171
172 if (ForceAcpiDisable)
173 {
174 /* Set the ACPI State to False if it's been forced that way */
175 PopAcpiPresent = FALSE;
176 }
177 else
178 {
179 /* Otherwise check if the LoaderBlock has a ACPI Table */
180 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
181 }
182
183
184 /* Initialize volume support */
185 InitializeListHead(&PopVolumeDevices);
186 KeInitializeGuardedMutex(&PopVolumeLock);
187
188 /* Initialize support for dope */
189 KeInitializeSpinLock(&PopDopeGlobalLock);
190 return TRUE;
191 }
192
193 VOID
194 NTAPI
195 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
196 {
197 DPRINT1("PerfIdle function: %p\n", PowerState);
198 }
199
200 VOID
201 NTAPI
202 PopPerfIdleDpc(IN PKDPC Dpc,
203 IN PVOID DeferredContext,
204 IN PVOID SystemArgument1,
205 IN PVOID SystemArgument2)
206 {
207 /* Call the Perf Idle function */
208 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
209 }
210
211 VOID
212 FASTCALL
213 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
214 {
215 /* FIXME: Extremly naive implementation */
216 HalProcessorIdle();
217 }
218
219 VOID
220 NTAPI
221 INIT_FUNCTION
222 PoInitializePrcb(IN PKPRCB Prcb)
223 {
224 /* Initialize the Power State */
225 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
226 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
227 Prcb->PowerState.CurrentThrottle = 100;
228 Prcb->PowerState.CurrentThrottleIndex = 0;
229 Prcb->PowerState.IdleFunction = PopIdle0;
230
231 /* Initialize the Perf DPC and Timer */
232 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
233 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
234 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
235 }
236
237 /* PUBLIC FUNCTIONS **********************************************************/
238
239 /*
240 * @unimplemented
241 */
242 NTSTATUS
243 NTAPI
244 PoCancelDeviceNotify(IN PVOID NotifyBlock)
245 {
246 UNIMPLEMENTED;
247 return STATUS_NOT_IMPLEMENTED;
248 }
249
250 /*
251 * @unimplemented
252 */
253 NTSTATUS
254 NTAPI
255 PoRegisterDeviceNotify(OUT PVOID Unknown0,
256 IN ULONG Unknown1,
257 IN ULONG Unknown2,
258 IN ULONG Unknown3,
259 IN PVOID Unknown4,
260 IN PVOID Unknown5)
261 {
262 UNIMPLEMENTED;
263 return STATUS_NOT_IMPLEMENTED;
264 }
265
266 /*
267 * @unimplemented
268 */
269 VOID
270 NTAPI
271 PoShutdownBugCheck(IN BOOLEAN LogError,
272 IN ULONG BugCheckCode,
273 IN ULONG_PTR BugCheckParameter1,
274 IN ULONG_PTR BugCheckParameter2,
275 IN ULONG_PTR BugCheckParameter3,
276 IN ULONG_PTR BugCheckParameter4)
277 {
278 DPRINT1("PoShutdownBugCheck called\n");
279
280 /* FIXME: Log error if requested */
281 /* FIXME: Initiate a shutdown */
282
283 /* Bugcheck the system */
284 KeBugCheckEx(BugCheckCode,
285 BugCheckParameter1,
286 BugCheckParameter2,
287 BugCheckParameter3,
288 BugCheckParameter4);
289 }
290
291 /*
292 * @unimplemented
293 */
294 NTSTATUS
295 NTAPI
296 PoRequestShutdownEvent(OUT PVOID *Event)
297 {
298 UNIMPLEMENTED;
299 return STATUS_NOT_IMPLEMENTED;
300 }
301
302 /*
303 * @unimplemented
304 */
305 VOID
306 NTAPI
307 PoSetHiberRange(IN PVOID HiberContext,
308 IN ULONG Flags,
309 IN OUT PVOID StartPage,
310 IN ULONG Length,
311 IN ULONG PageTag)
312 {
313 UNIMPLEMENTED;
314 return;
315 }
316
317 /*
318 * @implemented
319 */
320 NTSTATUS
321 NTAPI
322 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
323 IN OUT PIRP Irp)
324 {
325 NTSTATUS Status;
326
327 /* Forward to Io -- FIXME! */
328 Status = IoCallDriver(DeviceObject, Irp);
329
330 /* Return status */
331 return Status;
332 }
333
334 /*
335 * @unimplemented
336 */
337 PULONG
338 NTAPI
339 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
340 IN ULONG ConservationIdleTime,
341 IN ULONG PerformanceIdleTime,
342 IN DEVICE_POWER_STATE State)
343 {
344 UNIMPLEMENTED;
345 return NULL;
346 }
347
348 /*
349 * @unimplemented
350 */
351 PVOID
352 NTAPI
353 PoRegisterSystemState(IN PVOID StateHandle,
354 IN EXECUTION_STATE Flags)
355 {
356 UNIMPLEMENTED;
357 return NULL;
358 }
359
360 /*
361 * @implemented
362 */
363 NTSTATUS
364 NTAPI
365 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
366 IN UCHAR MinorFunction,
367 IN POWER_STATE PowerState,
368 IN PREQUEST_POWER_COMPLETE CompletionFunction,
369 IN PVOID Context,
370 OUT PIRP *pIrp OPTIONAL)
371 {
372 PDEVICE_OBJECT TopDeviceObject;
373 PIO_STACK_LOCATION Stack;
374 PIRP Irp;
375 PREQUEST_POWER_ITEM RequestPowerItem;
376
377 if (MinorFunction != IRP_MN_QUERY_POWER
378 && MinorFunction != IRP_MN_SET_POWER
379 && MinorFunction != IRP_MN_WAIT_WAKE)
380 return STATUS_INVALID_PARAMETER_2;
381
382 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
383 if (!RequestPowerItem)
384 return STATUS_INSUFFICIENT_RESOURCES;
385
386 /* Always call the top of the device stack */
387 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
388
389 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER,
390 TopDeviceObject,
391 NULL,
392 0,
393 NULL,
394 NULL);
395 if (!Irp)
396 {
397 ExFreePool(RequestPowerItem);
398 return STATUS_INSUFFICIENT_RESOURCES;
399 }
400
401 /* POWER IRPs are always initialized with a status code of
402 STATUS_NOT_IMPLEMENTED */
403 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
404 Irp->IoStatus.Information = 0;
405
406 Stack = IoGetNextIrpStackLocation(Irp);
407 Stack->MinorFunction = MinorFunction;
408 if (MinorFunction == IRP_MN_WAIT_WAKE)
409 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
410 else
411 {
412 Stack->Parameters.Power.Type = DevicePowerState;
413 Stack->Parameters.Power.State = PowerState;
414 }
415
416 RequestPowerItem->CompletionRoutine = CompletionFunction;
417 RequestPowerItem->PowerState = PowerState;
418 RequestPowerItem->Context = Context;
419
420 if (pIrp != NULL)
421 *pIrp = Irp;
422
423 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
424 IoCallDriver(TopDeviceObject, Irp);
425
426 /* Always return STATUS_PENDING. The completion routine
427 * will call CompletionFunction and complete the Irp.
428 */
429 return STATUS_PENDING;
430 }
431
432 /*
433 * @unimplemented
434 */
435 POWER_STATE
436 NTAPI
437 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
438 IN POWER_STATE_TYPE Type,
439 IN POWER_STATE State)
440 {
441 POWER_STATE ps;
442
443 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
444
445 ps.SystemState = PowerSystemWorking; // Fully on
446 ps.DeviceState = PowerDeviceD0; // Fully on
447
448 return ps;
449 }
450
451 /*
452 * @unimplemented
453 */
454 VOID
455 NTAPI
456 PoSetSystemState(IN EXECUTION_STATE Flags)
457 {
458 UNIMPLEMENTED;
459 }
460
461 /*
462 * @unimplemented
463 */
464 VOID
465 NTAPI
466 PoStartNextPowerIrp(IN PIRP Irp)
467 {
468 UNIMPLEMENTED;
469 }
470
471 /*
472 * @unimplemented
473 */
474 VOID
475 NTAPI
476 PoUnregisterSystemState(IN PVOID StateHandle)
477 {
478 UNIMPLEMENTED;
479 }
480
481 /*
482 * @unimplemented
483 */
484 NTSTATUS
485 NTAPI
486 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem)
487 {
488 PAGED_CODE();
489
490 UNIMPLEMENTED;
491 return STATUS_NOT_IMPLEMENTED;
492 }
493
494 /*
495 * @unimplemented
496 */
497 NTSTATUS
498 NTAPI
499 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
500 IN SYSTEM_POWER_STATE MinSystemState,
501 IN ULONG Flags,
502 IN BOOLEAN Asynchronous)
503 {
504 UNIMPLEMENTED;
505 return STATUS_NOT_IMPLEMENTED;
506 }
507
508 /*
509 * @unimplemented
510 */
511 NTSTATUS
512 NTAPI
513 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
514 IN PVOID InputBuffer OPTIONAL,
515 IN ULONG InputBufferLength,
516 OUT PVOID OutputBuffer OPTIONAL,
517 IN ULONG OutputBufferLength)
518 {
519 NTSTATUS Status;
520
521 PAGED_CODE();
522
523 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
524 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
525 PowerInformationLevel,
526 InputBuffer, InputBufferLength,
527 OutputBuffer, OutputBufferLength);
528
529 switch (PowerInformationLevel)
530 {
531 case SystemBatteryState:
532 {
533 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
534
535 if (InputBuffer != NULL)
536 return STATUS_INVALID_PARAMETER;
537 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
538 return STATUS_BUFFER_TOO_SMALL;
539
540 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
541 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
542 BatteryState->EstimatedTime = MAXULONG;
543
544 Status = STATUS_SUCCESS;
545 break;
546 }
547 case SystemPowerCapabilities:
548 {
549 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
550
551 if (InputBuffer != NULL)
552 return STATUS_INVALID_PARAMETER;
553 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
554 return STATUS_BUFFER_TOO_SMALL;
555
556 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
557 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
558 //PowerCapabilities->SystemBatteriesPresent = 0;
559
560 Status = STATUS_SUCCESS;
561 break;
562 }
563
564 default:
565 Status = STATUS_NOT_IMPLEMENTED;
566 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
567 PowerInformationLevel);
568 break;
569 }
570
571 return Status;
572 }
573
574 NTSTATUS
575 NTAPI
576 NtGetDevicePowerState(IN HANDLE Device,
577 IN PDEVICE_POWER_STATE PowerState)
578 {
579 UNIMPLEMENTED;
580 return STATUS_NOT_IMPLEMENTED;
581 }
582
583 BOOLEAN
584 NTAPI
585 NtIsSystemResumeAutomatic(VOID)
586 {
587 UNIMPLEMENTED;
588 return FALSE;
589 }
590
591 NTSTATUS
592 NTAPI
593 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
594 {
595 UNIMPLEMENTED;
596 return STATUS_NOT_IMPLEMENTED;
597 }
598
599 NTSTATUS
600 NTAPI
601 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
602 OUT EXECUTION_STATE *PreviousFlags)
603 {
604 PKTHREAD Thread = KeGetCurrentThread();
605 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
606 EXECUTION_STATE PreviousState;
607 PAGED_CODE();
608
609 /* Validate flags */
610 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
611 {
612 /* Fail the request */
613 return STATUS_INVALID_PARAMETER;
614 }
615
616 /* Check for user parameters */
617 if (PreviousMode != KernelMode)
618 {
619 /* Protect the probes */
620 _SEH2_TRY
621 {
622 /* Check if the pointer is valid */
623 ProbeForWriteUlong(PreviousFlags);
624 }
625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
626 {
627 /* It isn't -- fail */
628 _SEH2_YIELD(return _SEH2_GetExceptionCode());
629 }
630 _SEH2_END;
631 }
632
633 /* Save the previous state, always masking in the continous flag */
634 PreviousState = Thread->PowerState | ES_CONTINUOUS;
635
636 /* Check if we need to update the power state */
637 if (esFlags & ES_CONTINUOUS) Thread->PowerState = esFlags;
638
639 /* Protect the write back to user mode */
640 _SEH2_TRY
641 {
642 /* Return the previous flags */
643 *PreviousFlags = PreviousState;
644 }
645 _SEH2_EXCEPT(ExSystemExceptionFilter())
646 {
647 /* Something's wrong, fail */
648 _SEH2_YIELD(return _SEH2_GetExceptionCode());
649 }
650 _SEH2_END;
651
652 /* All is good */
653 return STATUS_SUCCESS;
654 }
655
656 NTSTATUS
657 NTAPI
658 NtSetSystemPowerState(IN POWER_ACTION SystemAction,
659 IN SYSTEM_POWER_STATE MinSystemState,
660 IN ULONG Flags)
661 {
662 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
663 POP_POWER_ACTION Action = {0};
664 NTSTATUS Status;
665 ULONG Dummy;
666
667 /* Check for invalid parameter combinations */
668 if ((MinSystemState >= PowerSystemMaximum) ||
669 (MinSystemState <= PowerSystemUnspecified) ||
670 (SystemAction > PowerActionWarmEject) ||
671 (SystemAction < PowerActionReserved) ||
672 (Flags & ~(POWER_ACTION_QUERY_ALLOWED |
673 POWER_ACTION_UI_ALLOWED |
674 POWER_ACTION_OVERRIDE_APPS |
675 POWER_ACTION_LIGHTEST_FIRST |
676 POWER_ACTION_LOCK_CONSOLE |
677 POWER_ACTION_DISABLE_WAKES |
678 POWER_ACTION_CRITICAL)))
679 {
680 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
681 DPRINT1(" SystemAction: 0x%x\n", SystemAction);
682 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
683 DPRINT1(" Flags: 0x%x\n", Flags);
684 return STATUS_INVALID_PARAMETER;
685 }
686
687 /* Check for user caller */
688 if (PreviousMode != KernelMode)
689 {
690 /* Check for shutdown permission */
691 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
692 {
693 /* Not granted */
694 DPRINT1("ERROR: Privilege not held for shutdown\n");
695 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
696 }
697
698 /* Do it as a kernel-mode caller for consistency with system state */
699 return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags);
700 }
701
702 /* Read policy settings (partial shutdown vs. full shutdown) */
703 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
704
705 /* Disable lazy flushing of registry */
706 DPRINT1("Stopping lazy flush\n");
707 CmSetLazyFlushState(FALSE);
708
709 /* Setup the power action */
710 Action.Action = SystemAction;
711 Action.Flags = Flags;
712
713 /* Notify callbacks */
714 DPRINT1("Notifying callbacks\n");
715 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
716
717 /* Swap in any worker thread stacks */
718 DPRINT1("Swapping worker threads\n");
719 ExSwapinWorkerThreads(FALSE);
720
721 /* Make our action global */
722 PopAction = Action;
723
724 /* Start power loop */
725 Status = STATUS_CANCELLED;
726 while (TRUE)
727 {
728 /* Break out if there's nothing to do */
729 if (Action.Action == PowerActionNone) break;
730
731 /* Check for first-pass or restart */
732 if (Status == STATUS_CANCELLED)
733 {
734 /* Check for shutdown action */
735 if ((PopAction.Action == PowerActionShutdown) ||
736 (PopAction.Action == PowerActionShutdownReset) ||
737 (PopAction.Action == PowerActionShutdownOff))
738 {
739 /* Set the action */
740 PopAction.Shutdown = TRUE;
741 }
742
743 /* Now we are good to go */
744 Status = STATUS_SUCCESS;
745 }
746
747 /* Check if we're still in an invalid status */
748 if (!NT_SUCCESS(Status)) break;
749
750 #ifndef NEWCC
751 /* Flush dirty cache pages */
752 CcRosFlushDirtyPages(-1, &Dummy);
753 #else
754 Dummy = 0;
755 #endif
756
757 /* Flush all volumes and the registry */
758 DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy);
759 PopFlushVolumes(PopAction.Shutdown);
760
761 /* Set IRP for drivers */
762 PopAction.IrpMinor = IRP_MN_SET_POWER;
763 if (PopAction.Shutdown)
764 {
765 DPRINT1("Queueing shutdown thread\n");
766 /* Check if we are running in the system context */
767 if (PsGetCurrentProcess() != PsInitialSystemProcess)
768 {
769 /* We're not, so use a worker thread for shutdown */
770 ExInitializeWorkItem(&PopShutdownWorkItem,
771 &PopGracefulShutdown,
772 NULL);
773
774 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
775
776 /* Spend us -- when we wake up, the system is good to go down */
777 KeSuspendThread(KeGetCurrentThread());
778 Status = STATUS_SYSTEM_SHUTDOWN;
779 goto Exit;
780
781 }
782 else
783 {
784 /* Do the shutdown inline */
785 PopGracefulShutdown(NULL);
786 }
787 }
788
789 /* You should not have made it this far */
790 ASSERT(FALSE && "System is still up and running?!");
791 break;
792 }
793
794 Exit:
795 /* We're done, return */
796 return Status;
797 }