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)
10 /* INCLUDES ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 typedef struct _REQUEST_POWER_ITEM
21 PREQUEST_POWER_COMPLETE CompletionRoutine
;
22 POWER_STATE PowerState
;
24 PDEVICE_OBJECT TopDeviceObject
;
25 } REQUEST_POWER_ITEM
, *PREQUEST_POWER_ITEM
;
27 typedef struct _POWER_STATE_TRAVERSE_CONTEXT
29 SYSTEM_POWER_STATE SystemPowerState
;
30 POWER_ACTION PowerAction
;
31 PDEVICE_OBJECT PowerDevice
;
32 } POWER_STATE_TRAVERSE_CONTEXT
, *PPOWER_STATE_TRAVERSE_CONTEXT
;
34 PDEVICE_NODE PopSystemPowerDeviceNode
= NULL
;
35 BOOLEAN PopAcpiPresent
= FALSE
;
36 POP_POWER_ACTION PopAction
;
37 WORK_QUEUE_ITEM PopShutdownWorkItem
;
39 /* PRIVATE FUNCTIONS *********************************************************/
44 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject
,
48 PIO_STACK_LOCATION Stack
;
49 PREQUEST_POWER_ITEM RequestPowerItem
;
51 Stack
= IoGetNextIrpStackLocation(Irp
);
52 RequestPowerItem
= (PREQUEST_POWER_ITEM
)Context
;
54 RequestPowerItem
->CompletionRoutine(DeviceObject
,
56 RequestPowerItem
->PowerState
,
57 RequestPowerItem
->Context
,
62 ObDereferenceObject(RequestPowerItem
->TopDeviceObject
);
65 return STATUS_MORE_PROCESSING_REQUIRED
;
70 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
76 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
79 IO_STATUS_BLOCK IoStatusBlock
;
80 PIO_STACK_LOCATION IrpSp
;
84 KeInitializeEvent(&Event
,
88 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
95 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
97 IrpSp
= IoGetNextIrpStackLocation(Irp
);
98 IrpSp
->MinorFunction
= IRP_MN_QUERY_POWER
;
99 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
100 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
101 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
103 Status
= PoCallDriver(DeviceObject
, Irp
);
104 if (Status
== STATUS_PENDING
)
106 KeWaitForSingleObject(&Event
,
111 Status
= IoStatusBlock
.Status
;
118 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
121 IO_STATUS_BLOCK IoStatusBlock
;
122 PIO_STACK_LOCATION IrpSp
;
126 KeInitializeEvent(&Event
,
130 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
137 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
139 IrpSp
= IoGetNextIrpStackLocation(Irp
);
140 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
141 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
142 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
143 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
145 Status
= PoCallDriver(DeviceObject
, Irp
);
146 if (Status
== STATUS_PENDING
)
148 KeWaitForSingleObject(&Event
,
153 Status
= IoStatusBlock
.Status
;
160 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
163 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
166 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
168 if (DeviceNode
== IopRootDeviceNode
)
169 return STATUS_SUCCESS
;
171 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
172 return STATUS_SUCCESS
;
174 Status
= PopSendQuerySystemPowerState(DeviceNode
->PhysicalDeviceObject
,
175 PowerStateContext
->SystemPowerState
,
176 PowerStateContext
->PowerAction
);
177 if (!NT_SUCCESS(Status
))
179 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode
->InstancePath
);
185 return STATUS_SUCCESS
;
190 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
193 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
196 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
198 if (DeviceNode
== IopRootDeviceNode
)
199 return STATUS_SUCCESS
;
201 if (DeviceNode
->PhysicalDeviceObject
== PowerStateContext
->PowerDevice
)
202 return STATUS_SUCCESS
;
204 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
205 return STATUS_SUCCESS
;
207 Status
= PopSendSetSystemPowerState(DeviceNode
->PhysicalDeviceObject
,
208 PowerStateContext
->SystemPowerState
,
209 PowerStateContext
->PowerAction
);
210 if (!NT_SUCCESS(Status
))
212 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode
->InstancePath
);
218 return STATUS_SUCCESS
;
224 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
, POWER_ACTION PowerAction
)
226 PDEVICE_OBJECT DeviceObject
;
229 DEVICETREE_TRAVERSE_CONTEXT Context
;
230 POWER_STATE_TRAVERSE_CONTEXT PowerContext
;
232 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
233 if (!NT_SUCCESS(Status
))
235 DPRINT1("No system power driver available\n");
240 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
241 if (Fdo
== DeviceObject
)
243 DPRINT("An FDO was not attached\n");
244 return STATUS_UNSUCCESSFUL
;
249 PowerContext
.PowerAction
= PowerAction
;
250 PowerContext
.SystemPowerState
= PowerState
;
251 PowerContext
.PowerDevice
= Fdo
;
253 /* Query for system power change */
254 IopInitDeviceTreeTraverseContext(&Context
,
256 PopQuerySystemPowerStateTraverse
,
259 Status
= IopTraverseDeviceTree(&Context
);
260 if (!NT_SUCCESS(Status
))
262 DPRINT1("Query system power state failed; changing state anyway\n");
265 /* Set system power change */
266 IopInitDeviceTreeTraverseContext(&Context
,
268 PopSetSystemPowerStateTraverse
,
271 IopTraverseDeviceTree(&Context
);
273 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
277 if (PowerAction
!= PowerActionShutdownReset
)
278 PopSendSetSystemPowerState(Fdo
, PowerState
, PowerAction
);
280 ObDereferenceObject(Fdo
);
289 PoInitSystem(IN ULONG BootPhase
)
291 PVOID NotificationEntry
;
293 BOOLEAN ForceAcpiDisable
= FALSE
;
295 /* Check if this is phase 1 init */
298 /* Register power button notification */
299 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
300 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
301 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
303 PhysicalDeviceObject
->DriverObject
,
304 PopAddRemoveSysCapsCallback
,
308 /* Register lid notification */
309 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
310 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
311 (PVOID
)&GUID_DEVICE_LID
,
313 PhysicalDeviceObject
->DriverObject
,
314 PopAddRemoveSysCapsCallback
,
320 /* Get the Command Line */
321 CommandLine
= KeLoaderBlock
->LoadOptions
;
324 _strupr(CommandLine
);
326 /* Check for ACPI disable */
327 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
329 if (ForceAcpiDisable
)
331 /* Set the ACPI State to False if it's been forced that way */
332 PopAcpiPresent
= FALSE
;
336 /* Otherwise check if the LoaderBlock has a ACPI Table */
337 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
341 /* Initialize volume support */
342 InitializeListHead(&PopVolumeDevices
);
343 KeInitializeGuardedMutex(&PopVolumeLock
);
345 /* Initialize support for dope */
346 KeInitializeSpinLock(&PopDopeGlobalLock
);
352 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
354 DPRINT1("PerfIdle function: %p\n", PowerState
);
359 PopPerfIdleDpc(IN PKDPC Dpc
,
360 IN PVOID DeferredContext
,
361 IN PVOID SystemArgument1
,
362 IN PVOID SystemArgument2
)
364 /* Call the Perf Idle function */
365 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
370 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
372 /* FIXME: Extremly naive implementation */
379 PoInitializePrcb(IN PKPRCB Prcb
)
381 /* Initialize the Power State */
382 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
383 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
384 Prcb
->PowerState
.CurrentThrottle
= 100;
385 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
386 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
388 /* Initialize the Perf DPC and Timer */
389 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
390 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
391 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
394 /* PUBLIC FUNCTIONS **********************************************************/
401 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
404 return STATUS_NOT_IMPLEMENTED
;
412 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
420 return STATUS_NOT_IMPLEMENTED
;
428 PoShutdownBugCheck(IN BOOLEAN LogError
,
429 IN ULONG BugCheckCode
,
430 IN ULONG_PTR BugCheckParameter1
,
431 IN ULONG_PTR BugCheckParameter2
,
432 IN ULONG_PTR BugCheckParameter3
,
433 IN ULONG_PTR BugCheckParameter4
)
435 DPRINT1("PoShutdownBugCheck called\n");
437 /* FIXME: Log error if requested */
438 /* FIXME: Initiate a shutdown */
440 /* Bugcheck the system */
441 KeBugCheckEx(BugCheckCode
,
453 PoRequestShutdownEvent(OUT PVOID
*Event
)
456 return STATUS_NOT_IMPLEMENTED
;
464 PoSetHiberRange(IN PVOID HiberContext
,
466 IN OUT PVOID StartPage
,
479 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
484 /* Forward to Io -- FIXME! */
485 Status
= IoCallDriver(DeviceObject
, Irp
);
496 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
497 IN ULONG ConservationIdleTime
,
498 IN ULONG PerformanceIdleTime
,
499 IN DEVICE_POWER_STATE State
)
510 PoRegisterSystemState(IN PVOID StateHandle
,
511 IN EXECUTION_STATE Flags
)
522 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
523 IN UCHAR MinorFunction
,
524 IN POWER_STATE PowerState
,
525 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
527 OUT PIRP
*pIrp OPTIONAL
)
529 PDEVICE_OBJECT TopDeviceObject
;
530 PIO_STACK_LOCATION Stack
;
532 PREQUEST_POWER_ITEM RequestPowerItem
;
534 if (MinorFunction
!= IRP_MN_QUERY_POWER
535 && MinorFunction
!= IRP_MN_SET_POWER
536 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
537 return STATUS_INVALID_PARAMETER_2
;
539 RequestPowerItem
= ExAllocatePool(NonPagedPool
, sizeof(REQUEST_POWER_ITEM
));
540 if (!RequestPowerItem
)
541 return STATUS_INSUFFICIENT_RESOURCES
;
543 /* Always call the top of the device stack */
544 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
546 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_POWER
,
554 ObDereferenceObject(TopDeviceObject
);
555 ExFreePool(RequestPowerItem
);
556 return STATUS_INSUFFICIENT_RESOURCES
;
559 /* POWER IRPs are always initialized with a status code of
560 STATUS_NOT_IMPLEMENTED */
561 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
562 Irp
->IoStatus
.Information
= 0;
564 Stack
= IoGetNextIrpStackLocation(Irp
);
565 Stack
->MinorFunction
= MinorFunction
;
566 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
567 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
570 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
571 Stack
->Parameters
.Power
.State
= PowerState
;
574 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
575 RequestPowerItem
->PowerState
= PowerState
;
576 RequestPowerItem
->Context
= Context
;
577 RequestPowerItem
->TopDeviceObject
= TopDeviceObject
;
582 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, RequestPowerItem
, TRUE
, TRUE
, TRUE
);
583 PoCallDriver(TopDeviceObject
, Irp
);
585 /* Always return STATUS_PENDING. The completion routine
586 * will call CompletionFunction and complete the Irp.
588 return STATUS_PENDING
;
596 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
597 IN POWER_STATE_TYPE Type
,
598 IN POWER_STATE State
)
602 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
604 ps
.SystemState
= PowerSystemWorking
; // Fully on
605 ps
.DeviceState
= PowerDeviceD0
; // Fully on
615 PoSetSystemState(IN EXECUTION_STATE Flags
)
625 PoStartNextPowerIrp(IN PIRP Irp
)
635 PoUnregisterSystemState(IN PVOID StateHandle
)
645 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem
)
650 return STATUS_NOT_IMPLEMENTED
;
658 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
659 IN SYSTEM_POWER_STATE MinSystemState
,
661 IN BOOLEAN Asynchronous
)
664 return STATUS_NOT_IMPLEMENTED
;
672 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
673 IN PVOID InputBuffer OPTIONAL
,
674 IN ULONG InputBufferLength
,
675 OUT PVOID OutputBuffer OPTIONAL
,
676 IN ULONG OutputBufferLength
)
682 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
683 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
684 PowerInformationLevel
,
685 InputBuffer
, InputBufferLength
,
686 OutputBuffer
, OutputBufferLength
);
688 switch (PowerInformationLevel
)
690 case SystemBatteryState
:
692 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
694 if (InputBuffer
!= NULL
)
695 return STATUS_INVALID_PARAMETER
;
696 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
697 return STATUS_BUFFER_TOO_SMALL
;
699 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
700 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
701 BatteryState
->EstimatedTime
= MAXULONG
;
703 Status
= STATUS_SUCCESS
;
706 case SystemPowerCapabilities
:
708 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
710 if (InputBuffer
!= NULL
)
711 return STATUS_INVALID_PARAMETER
;
712 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
713 return STATUS_BUFFER_TOO_SMALL
;
715 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
716 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
717 //PowerCapabilities->SystemBatteriesPresent = 0;
719 Status
= STATUS_SUCCESS
;
724 Status
= STATUS_NOT_IMPLEMENTED
;
725 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
726 PowerInformationLevel
);
735 NtGetDevicePowerState(IN HANDLE Device
,
736 IN PDEVICE_POWER_STATE PowerState
)
739 return STATUS_NOT_IMPLEMENTED
;
744 NtIsSystemResumeAutomatic(VOID
)
752 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
755 return STATUS_NOT_IMPLEMENTED
;
760 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
761 OUT EXECUTION_STATE
*PreviousFlags
)
763 PKTHREAD Thread
= KeGetCurrentThread();
764 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
765 EXECUTION_STATE PreviousState
;
769 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
771 /* Fail the request */
772 return STATUS_INVALID_PARAMETER
;
775 /* Check for user parameters */
776 if (PreviousMode
!= KernelMode
)
778 /* Protect the probes */
781 /* Check if the pointer is valid */
782 ProbeForWriteUlong(PreviousFlags
);
784 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
786 /* It isn't -- fail */
787 _SEH2_YIELD(return _SEH2_GetExceptionCode());
792 /* Save the previous state, always masking in the continous flag */
793 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
795 /* Check if we need to update the power state */
796 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= (UCHAR
)esFlags
;
798 /* Protect the write back to user mode */
801 /* Return the previous flags */
802 *PreviousFlags
= PreviousState
;
804 _SEH2_EXCEPT(ExSystemExceptionFilter())
806 /* Something's wrong, fail */
807 _SEH2_YIELD(return _SEH2_GetExceptionCode());
812 return STATUS_SUCCESS
;
817 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
818 IN SYSTEM_POWER_STATE MinSystemState
,
821 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
822 POP_POWER_ACTION Action
= {0};
826 /* Check for invalid parameter combinations */
827 if ((MinSystemState
>= PowerSystemMaximum
) ||
828 (MinSystemState
<= PowerSystemUnspecified
) ||
829 (SystemAction
> PowerActionWarmEject
) ||
830 (SystemAction
< PowerActionReserved
) ||
831 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
832 POWER_ACTION_UI_ALLOWED
|
833 POWER_ACTION_OVERRIDE_APPS
|
834 POWER_ACTION_LIGHTEST_FIRST
|
835 POWER_ACTION_LOCK_CONSOLE
|
836 POWER_ACTION_DISABLE_WAKES
|
837 POWER_ACTION_CRITICAL
)))
839 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
840 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
841 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
842 DPRINT1(" Flags: 0x%x\n", Flags
);
843 return STATUS_INVALID_PARAMETER
;
846 /* Check for user caller */
847 if (PreviousMode
!= KernelMode
)
849 /* Check for shutdown permission */
850 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
853 DPRINT1("ERROR: Privilege not held for shutdown\n");
854 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
857 /* Do it as a kernel-mode caller for consistency with system state */
858 return ZwSetSystemPowerState (SystemAction
, MinSystemState
, Flags
);
861 /* Read policy settings (partial shutdown vs. full shutdown) */
862 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
864 /* Disable lazy flushing of registry */
865 DPRINT1("Stopping lazy flush\n");
866 CmSetLazyFlushState(FALSE
);
868 /* Setup the power action */
869 Action
.Action
= SystemAction
;
870 Action
.Flags
= Flags
;
872 /* Notify callbacks */
873 DPRINT1("Notifying callbacks\n");
874 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
876 /* Swap in any worker thread stacks */
877 DPRINT1("Swapping worker threads\n");
878 ExSwapinWorkerThreads(FALSE
);
880 /* Make our action global */
883 /* Start power loop */
884 Status
= STATUS_CANCELLED
;
887 /* Break out if there's nothing to do */
888 if (Action
.Action
== PowerActionNone
) break;
890 /* Check for first-pass or restart */
891 if (Status
== STATUS_CANCELLED
)
893 /* Check for shutdown action */
894 if ((PopAction
.Action
== PowerActionShutdown
) ||
895 (PopAction
.Action
== PowerActionShutdownReset
) ||
896 (PopAction
.Action
== PowerActionShutdownOff
))
899 PopAction
.Shutdown
= TRUE
;
902 /* Now we are good to go */
903 Status
= STATUS_SUCCESS
;
906 /* Check if we're still in an invalid status */
907 if (!NT_SUCCESS(Status
)) break;
910 /* Flush dirty cache pages */
911 CcRosFlushDirtyPages(-1, &Dummy
, FALSE
); //HACK: We really should wait here!
916 /* Flush all volumes and the registry */
917 DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy
);
918 PopFlushVolumes(PopAction
.Shutdown
);
920 /* Set IRP for drivers */
921 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
922 if (PopAction
.Shutdown
)
924 DPRINT1("Queueing shutdown thread\n");
925 /* Check if we are running in the system context */
926 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
928 /* We're not, so use a worker thread for shutdown */
929 ExInitializeWorkItem(&PopShutdownWorkItem
,
930 &PopGracefulShutdown
,
933 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
935 /* Spend us -- when we wake up, the system is good to go down */
936 KeSuspendThread(KeGetCurrentThread());
937 Status
= STATUS_SYSTEM_SHUTDOWN
;
943 /* Do the shutdown inline */
944 PopGracefulShutdown(NULL
);
948 /* You should not have made it this far */
949 ASSERT(FALSE
&& "System is still up and running?!");
954 /* We're done, return */