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 ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 typedef struct _REQUEST_POWER_ITEM
20 PREQUEST_POWER_COMPLETE CompletionRoutine
;
21 POWER_STATE PowerState
;
23 PDEVICE_OBJECT TopDeviceObject
;
24 } REQUEST_POWER_ITEM
, *PREQUEST_POWER_ITEM
;
26 typedef struct _POWER_STATE_TRAVERSE_CONTEXT
28 SYSTEM_POWER_STATE SystemPowerState
;
29 POWER_ACTION PowerAction
;
30 PDEVICE_OBJECT PowerDevice
;
31 } POWER_STATE_TRAVERSE_CONTEXT
, *PPOWER_STATE_TRAVERSE_CONTEXT
;
33 PDEVICE_NODE PopSystemPowerDeviceNode
= NULL
;
34 BOOLEAN PopAcpiPresent
= FALSE
;
35 POP_POWER_ACTION PopAction
;
36 WORK_QUEUE_ITEM PopShutdownWorkItem
;
38 /* PRIVATE FUNCTIONS *********************************************************/
43 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject
,
47 PIO_STACK_LOCATION Stack
;
48 PREQUEST_POWER_ITEM RequestPowerItem
;
50 Stack
= IoGetNextIrpStackLocation(Irp
);
51 RequestPowerItem
= (PREQUEST_POWER_ITEM
)Context
;
53 RequestPowerItem
->CompletionRoutine(DeviceObject
,
55 RequestPowerItem
->PowerState
,
56 RequestPowerItem
->Context
,
61 ObDereferenceObject(RequestPowerItem
->TopDeviceObject
);
62 ExFreePoolWithTag(Context
, 'IRoP');
64 return STATUS_MORE_PROCESSING_REQUIRED
;
69 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
75 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
78 IO_STATUS_BLOCK IoStatusBlock
;
79 PIO_STACK_LOCATION IrpSp
;
83 KeInitializeEvent(&Event
,
87 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
94 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
96 IrpSp
= IoGetNextIrpStackLocation(Irp
);
97 IrpSp
->MinorFunction
= IRP_MN_QUERY_POWER
;
98 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
99 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
100 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
102 Status
= PoCallDriver(DeviceObject
, Irp
);
103 if (Status
== STATUS_PENDING
)
105 KeWaitForSingleObject(&Event
,
110 Status
= IoStatusBlock
.Status
;
117 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
120 IO_STATUS_BLOCK IoStatusBlock
;
121 PIO_STACK_LOCATION IrpSp
;
125 KeInitializeEvent(&Event
,
129 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
136 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
138 IrpSp
= IoGetNextIrpStackLocation(Irp
);
139 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
140 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
141 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
142 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
144 Status
= PoCallDriver(DeviceObject
, Irp
);
145 if (Status
== STATUS_PENDING
)
147 KeWaitForSingleObject(&Event
,
152 Status
= IoStatusBlock
.Status
;
159 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
162 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
165 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
167 if (DeviceNode
== IopRootDeviceNode
)
168 return STATUS_SUCCESS
;
170 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
171 return STATUS_SUCCESS
;
173 Status
= PopSendQuerySystemPowerState(DeviceNode
->PhysicalDeviceObject
,
174 PowerStateContext
->SystemPowerState
,
175 PowerStateContext
->PowerAction
);
176 if (!NT_SUCCESS(Status
))
178 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode
->InstancePath
);
184 return STATUS_SUCCESS
;
189 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
192 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
195 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
197 if (DeviceNode
== IopRootDeviceNode
)
198 return STATUS_SUCCESS
;
200 if (DeviceNode
->PhysicalDeviceObject
== PowerStateContext
->PowerDevice
)
201 return STATUS_SUCCESS
;
203 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
204 return STATUS_SUCCESS
;
206 Status
= PopSendSetSystemPowerState(DeviceNode
->PhysicalDeviceObject
,
207 PowerStateContext
->SystemPowerState
,
208 PowerStateContext
->PowerAction
);
209 if (!NT_SUCCESS(Status
))
211 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode
->InstancePath
);
217 return STATUS_SUCCESS
;
223 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
, POWER_ACTION PowerAction
)
225 PDEVICE_OBJECT DeviceObject
;
228 DEVICETREE_TRAVERSE_CONTEXT Context
;
229 POWER_STATE_TRAVERSE_CONTEXT PowerContext
;
231 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
232 if (!NT_SUCCESS(Status
))
234 DPRINT1("No system power driver available\n");
239 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
240 if (Fdo
== DeviceObject
)
242 DPRINT("An FDO was not attached\n");
243 return STATUS_UNSUCCESSFUL
;
248 PowerContext
.PowerAction
= PowerAction
;
249 PowerContext
.SystemPowerState
= PowerState
;
250 PowerContext
.PowerDevice
= Fdo
;
252 /* Query for system power change */
253 IopInitDeviceTreeTraverseContext(&Context
,
255 PopQuerySystemPowerStateTraverse
,
258 Status
= IopTraverseDeviceTree(&Context
);
259 if (!NT_SUCCESS(Status
))
261 DPRINT1("Query system power state failed; changing state anyway\n");
264 /* Set system power change */
265 IopInitDeviceTreeTraverseContext(&Context
,
267 PopSetSystemPowerStateTraverse
,
270 IopTraverseDeviceTree(&Context
);
272 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
276 if (PowerAction
!= PowerActionShutdownReset
)
277 PopSendSetSystemPowerState(Fdo
, PowerState
, PowerAction
);
279 ObDereferenceObject(Fdo
);
288 PoInitSystem(IN ULONG BootPhase
)
290 PVOID NotificationEntry
;
292 BOOLEAN ForceAcpiDisable
= FALSE
;
294 /* Check if this is phase 1 init */
297 /* Register power button notification */
298 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
299 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
300 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
302 PhysicalDeviceObject
->DriverObject
,
303 PopAddRemoveSysCapsCallback
,
307 /* Register lid notification */
308 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
309 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
310 (PVOID
)&GUID_DEVICE_LID
,
312 PhysicalDeviceObject
->DriverObject
,
313 PopAddRemoveSysCapsCallback
,
319 /* Get the Command Line */
320 CommandLine
= KeLoaderBlock
->LoadOptions
;
323 _strupr(CommandLine
);
325 /* Check for ACPI disable */
326 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
328 if (ForceAcpiDisable
)
330 /* Set the ACPI State to False if it's been forced that way */
331 PopAcpiPresent
= FALSE
;
335 /* Otherwise check if the LoaderBlock has a ACPI Table */
336 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
340 /* Initialize volume support */
341 InitializeListHead(&PopVolumeDevices
);
342 KeInitializeGuardedMutex(&PopVolumeLock
);
344 /* Initialize support for dope */
345 KeInitializeSpinLock(&PopDopeGlobalLock
);
347 /* Initialize support for shutdown waits and work-items */
348 PopInitShutdownList();
355 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
357 DPRINT1("PerfIdle function: %p\n", PowerState
);
362 PopPerfIdleDpc(IN PKDPC Dpc
,
363 IN PVOID DeferredContext
,
364 IN PVOID SystemArgument1
,
365 IN PVOID SystemArgument2
)
367 /* Call the Perf Idle function */
368 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
373 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
375 /* FIXME: Extremly naive implementation */
382 PoInitializePrcb(IN PKPRCB Prcb
)
384 /* Initialize the Power State */
385 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
386 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
387 Prcb
->PowerState
.CurrentThrottle
= 100;
388 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
389 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
391 /* Initialize the Perf DPC and Timer */
392 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
393 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
394 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
397 /* PUBLIC FUNCTIONS **********************************************************/
404 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
407 return STATUS_NOT_IMPLEMENTED
;
415 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
423 return STATUS_NOT_IMPLEMENTED
;
431 PoShutdownBugCheck(IN BOOLEAN LogError
,
432 IN ULONG BugCheckCode
,
433 IN ULONG_PTR BugCheckParameter1
,
434 IN ULONG_PTR BugCheckParameter2
,
435 IN ULONG_PTR BugCheckParameter3
,
436 IN ULONG_PTR BugCheckParameter4
)
438 DPRINT1("PoShutdownBugCheck called\n");
440 /* FIXME: Log error if requested */
441 /* FIXME: Initiate a shutdown */
443 /* Bugcheck the system */
444 KeBugCheckEx(BugCheckCode
,
456 PoSetHiberRange(IN PVOID HiberContext
,
458 IN OUT PVOID StartPage
,
471 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
476 /* Forward to Io -- FIXME! */
477 Status
= IoCallDriver(DeviceObject
, Irp
);
488 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
489 IN ULONG ConservationIdleTime
,
490 IN ULONG PerformanceIdleTime
,
491 IN DEVICE_POWER_STATE State
)
502 PoRegisterSystemState(IN PVOID StateHandle
,
503 IN EXECUTION_STATE Flags
)
514 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
515 IN UCHAR MinorFunction
,
516 IN POWER_STATE PowerState
,
517 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
519 OUT PIRP
*pIrp OPTIONAL
)
521 PDEVICE_OBJECT TopDeviceObject
;
522 PIO_STACK_LOCATION Stack
;
524 PREQUEST_POWER_ITEM RequestPowerItem
;
526 if (MinorFunction
!= IRP_MN_QUERY_POWER
527 && MinorFunction
!= IRP_MN_SET_POWER
528 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
529 return STATUS_INVALID_PARAMETER_2
;
531 RequestPowerItem
= ExAllocatePoolWithTag(NonPagedPool
,
532 sizeof(REQUEST_POWER_ITEM
),
534 if (!RequestPowerItem
)
535 return STATUS_INSUFFICIENT_RESOURCES
;
537 /* Always call the top of the device stack */
538 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
540 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_POWER
,
548 ObDereferenceObject(TopDeviceObject
);
549 ExFreePoolWithTag(RequestPowerItem
, 'IRoP');
550 return STATUS_INSUFFICIENT_RESOURCES
;
553 /* POWER IRPs are always initialized with a status code of
554 STATUS_NOT_IMPLEMENTED */
555 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
556 Irp
->IoStatus
.Information
= 0;
558 Stack
= IoGetNextIrpStackLocation(Irp
);
559 Stack
->MinorFunction
= MinorFunction
;
560 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
561 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
564 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
565 Stack
->Parameters
.Power
.State
= PowerState
;
568 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
569 RequestPowerItem
->PowerState
= PowerState
;
570 RequestPowerItem
->Context
= Context
;
571 RequestPowerItem
->TopDeviceObject
= TopDeviceObject
;
576 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, RequestPowerItem
, TRUE
, TRUE
, TRUE
);
577 PoCallDriver(TopDeviceObject
, Irp
);
579 /* Always return STATUS_PENDING. The completion routine
580 * will call CompletionFunction and complete the Irp.
582 return STATUS_PENDING
;
590 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
591 IN POWER_STATE_TYPE Type
,
592 IN POWER_STATE State
)
596 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
598 ps
.SystemState
= PowerSystemWorking
; // Fully on
599 ps
.DeviceState
= PowerDeviceD0
; // Fully on
609 PoSetSystemState(IN EXECUTION_STATE Flags
)
619 PoStartNextPowerIrp(IN PIRP Irp
)
629 PoUnregisterSystemState(IN PVOID StateHandle
)
639 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
640 IN SYSTEM_POWER_STATE MinSystemState
,
642 IN BOOLEAN Asynchronous
)
645 return STATUS_NOT_IMPLEMENTED
;
653 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
654 IN PVOID InputBuffer OPTIONAL
,
655 IN ULONG InputBufferLength
,
656 OUT PVOID OutputBuffer OPTIONAL
,
657 IN ULONG OutputBufferLength
)
663 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
664 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
665 PowerInformationLevel
,
666 InputBuffer
, InputBufferLength
,
667 OutputBuffer
, OutputBufferLength
);
669 switch (PowerInformationLevel
)
671 case SystemBatteryState
:
673 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
675 if (InputBuffer
!= NULL
)
676 return STATUS_INVALID_PARAMETER
;
677 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
678 return STATUS_BUFFER_TOO_SMALL
;
680 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
681 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
682 BatteryState
->EstimatedTime
= MAXULONG
;
684 Status
= STATUS_SUCCESS
;
688 case SystemPowerCapabilities
:
690 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
692 if (InputBuffer
!= NULL
)
693 return STATUS_INVALID_PARAMETER
;
694 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
695 return STATUS_BUFFER_TOO_SMALL
;
697 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
698 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
699 //PowerCapabilities->SystemBatteriesPresent = 0;
701 Status
= STATUS_SUCCESS
;
706 Status
= STATUS_NOT_IMPLEMENTED
;
707 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
708 PowerInformationLevel
);
717 NtGetDevicePowerState(IN HANDLE Device
,
718 IN PDEVICE_POWER_STATE PowerState
)
721 return STATUS_NOT_IMPLEMENTED
;
726 NtIsSystemResumeAutomatic(VOID
)
734 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
737 return STATUS_NOT_IMPLEMENTED
;
742 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
743 OUT EXECUTION_STATE
*PreviousFlags
)
745 PKTHREAD Thread
= KeGetCurrentThread();
746 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
747 EXECUTION_STATE PreviousState
;
751 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
753 /* Fail the request */
754 return STATUS_INVALID_PARAMETER
;
757 /* Check for user parameters */
758 if (PreviousMode
!= KernelMode
)
760 /* Protect the probes */
763 /* Check if the pointer is valid */
764 ProbeForWriteUlong(PreviousFlags
);
766 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
768 /* It isn't -- fail */
769 _SEH2_YIELD(return _SEH2_GetExceptionCode());
774 /* Save the previous state, always masking in the continous flag */
775 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
777 /* Check if we need to update the power state */
778 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= (UCHAR
)esFlags
;
780 /* Protect the write back to user mode */
783 /* Return the previous flags */
784 *PreviousFlags
= PreviousState
;
786 _SEH2_EXCEPT(ExSystemExceptionFilter())
788 /* Something's wrong, fail */
789 _SEH2_YIELD(return _SEH2_GetExceptionCode());
794 return STATUS_SUCCESS
;
799 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
800 IN SYSTEM_POWER_STATE MinSystemState
,
803 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
804 POP_POWER_ACTION Action
= {0};
808 /* Check for invalid parameter combinations */
809 if ((MinSystemState
>= PowerSystemMaximum
) ||
810 (MinSystemState
<= PowerSystemUnspecified
) ||
811 (SystemAction
> PowerActionWarmEject
) ||
812 (SystemAction
< PowerActionReserved
) ||
813 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
814 POWER_ACTION_UI_ALLOWED
|
815 POWER_ACTION_OVERRIDE_APPS
|
816 POWER_ACTION_LIGHTEST_FIRST
|
817 POWER_ACTION_LOCK_CONSOLE
|
818 POWER_ACTION_DISABLE_WAKES
|
819 POWER_ACTION_CRITICAL
)))
821 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
822 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
823 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
824 DPRINT1(" Flags: 0x%x\n", Flags
);
825 return STATUS_INVALID_PARAMETER
;
828 /* Check for user caller */
829 if (PreviousMode
!= KernelMode
)
831 /* Check for shutdown permission */
832 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
835 DPRINT1("ERROR: Privilege not held for shutdown\n");
836 return STATUS_PRIVILEGE_NOT_HELD
;
839 /* Do it as a kernel-mode caller for consistency with system state */
840 return ZwSetSystemPowerState(SystemAction
, MinSystemState
, Flags
);
843 /* Read policy settings (partial shutdown vs. full shutdown) */
844 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
846 /* Disable lazy flushing of registry */
847 DPRINT("Stopping lazy flush\n");
848 CmSetLazyFlushState(FALSE
);
850 /* Setup the power action */
851 Action
.Action
= SystemAction
;
852 Action
.Flags
= Flags
;
854 /* Notify callbacks */
855 DPRINT("Notifying callbacks\n");
856 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
858 /* Swap in any worker thread stacks */
859 DPRINT("Swapping worker threads\n");
860 ExSwapinWorkerThreads(FALSE
);
862 /* Make our action global */
865 /* Start power loop */
866 Status
= STATUS_CANCELLED
;
869 /* Break out if there's nothing to do */
870 if (Action
.Action
== PowerActionNone
) break;
872 /* Check for first-pass or restart */
873 if (Status
== STATUS_CANCELLED
)
875 /* Check for shutdown action */
876 if ((PopAction
.Action
== PowerActionShutdown
) ||
877 (PopAction
.Action
== PowerActionShutdownReset
) ||
878 (PopAction
.Action
== PowerActionShutdownOff
))
881 PopAction
.Shutdown
= TRUE
;
884 /* Now we are good to go */
885 Status
= STATUS_SUCCESS
;
888 /* Check if we're still in an invalid status */
889 if (!NT_SUCCESS(Status
)) break;
892 /* Flush dirty cache pages */
893 CcRosFlushDirtyPages(-1, &Dummy
, FALSE
); //HACK: We really should wait here!
898 /* Flush all volumes and the registry */
899 DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy
);
900 PopFlushVolumes(PopAction
.Shutdown
);
902 /* Set IRP for drivers */
903 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
904 if (PopAction
.Shutdown
)
906 DPRINT("Queueing shutdown thread\n");
907 /* Check if we are running in the system context */
908 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
910 /* We're not, so use a worker thread for shutdown */
911 ExInitializeWorkItem(&PopShutdownWorkItem
,
912 &PopGracefulShutdown
,
915 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
917 /* Spend us -- when we wake up, the system is good to go down */
918 KeSuspendThread(KeGetCurrentThread());
919 Status
= STATUS_SYSTEM_SHUTDOWN
;
925 /* Do the shutdown inline */
926 PopGracefulShutdown(NULL
);
930 /* You should not have made it this far */
931 // ASSERTMSG("System is still up and running?!", FALSE);
932 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction
.Action
);
937 /* We're done, return */