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 _POWER_STATE_TRAVERSE_CONTEXT
20 SYSTEM_POWER_STATE SystemPowerState
;
21 POWER_ACTION PowerAction
;
22 PDEVICE_OBJECT PowerDevice
;
23 } POWER_STATE_TRAVERSE_CONTEXT
, *PPOWER_STATE_TRAVERSE_CONTEXT
;
25 PDEVICE_NODE PopSystemPowerDeviceNode
= NULL
;
26 BOOLEAN PopAcpiPresent
= FALSE
;
27 POP_POWER_ACTION PopAction
;
28 WORK_QUEUE_ITEM PopShutdownWorkItem
;
30 /* PRIVATE FUNCTIONS *********************************************************/
35 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject
,
39 PIO_STACK_LOCATION Stack
;
40 PREQUEST_POWER_COMPLETE CompletionRoutine
;
41 POWER_STATE PowerState
;
43 Stack
= IoGetCurrentIrpStackLocation(Irp
);
44 CompletionRoutine
= Context
;
46 PowerState
.DeviceState
= (ULONG_PTR
)Stack
->Parameters
.Others
.Argument3
;
47 CompletionRoutine(Stack
->Parameters
.Others
.Argument1
,
48 (UCHAR
)(ULONG_PTR
)Stack
->Parameters
.Others
.Argument2
,
50 Stack
->Parameters
.Others
.Argument4
,
53 IoSkipCurrentIrpStackLocation(Irp
);
55 ObDereferenceObject(DeviceObject
);
57 return STATUS_MORE_PROCESSING_REQUIRED
;
62 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
68 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
71 IO_STATUS_BLOCK IoStatusBlock
;
72 PIO_STACK_LOCATION IrpSp
;
76 KeInitializeEvent(&Event
,
80 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
87 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
89 IrpSp
= IoGetNextIrpStackLocation(Irp
);
90 IrpSp
->MinorFunction
= IRP_MN_QUERY_POWER
;
91 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
92 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
93 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
95 Status
= PoCallDriver(DeviceObject
, Irp
);
96 if (Status
== STATUS_PENDING
)
98 KeWaitForSingleObject(&Event
,
103 Status
= IoStatusBlock
.Status
;
110 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
113 IO_STATUS_BLOCK IoStatusBlock
;
114 PIO_STACK_LOCATION IrpSp
;
118 KeInitializeEvent(&Event
,
122 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
129 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
131 IrpSp
= IoGetNextIrpStackLocation(Irp
);
132 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
133 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
134 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
135 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
137 Status
= PoCallDriver(DeviceObject
, Irp
);
138 if (Status
== STATUS_PENDING
)
140 KeWaitForSingleObject(&Event
,
145 Status
= IoStatusBlock
.Status
;
152 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
155 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
156 PDEVICE_OBJECT TopDeviceObject
;
159 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
161 if (DeviceNode
== IopRootDeviceNode
)
162 return STATUS_SUCCESS
;
164 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
165 return STATUS_SUCCESS
;
167 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
169 Status
= PopSendQuerySystemPowerState(TopDeviceObject
,
170 PowerStateContext
->SystemPowerState
,
171 PowerStateContext
->PowerAction
);
172 if (!NT_SUCCESS(Status
))
174 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode
->InstancePath
);
176 ObDereferenceObject(TopDeviceObject
);
181 return STATUS_SUCCESS
;
186 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
189 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
190 PDEVICE_OBJECT TopDeviceObject
;
193 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
195 if (DeviceNode
== IopRootDeviceNode
)
196 return STATUS_SUCCESS
;
198 if (DeviceNode
->PhysicalDeviceObject
== PowerStateContext
->PowerDevice
)
199 return STATUS_SUCCESS
;
201 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
202 return STATUS_SUCCESS
;
204 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
205 if (TopDeviceObject
== PowerStateContext
->PowerDevice
)
207 ObDereferenceObject(TopDeviceObject
);
208 return STATUS_SUCCESS
;
211 Status
= PopSendSetSystemPowerState(TopDeviceObject
,
212 PowerStateContext
->SystemPowerState
,
213 PowerStateContext
->PowerAction
);
214 if (!NT_SUCCESS(Status
))
216 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode
->InstancePath
);
219 ObDereferenceObject(TopDeviceObject
);
224 return STATUS_SUCCESS
;
230 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
, POWER_ACTION PowerAction
)
232 PDEVICE_OBJECT DeviceObject
;
235 DEVICETREE_TRAVERSE_CONTEXT Context
;
236 POWER_STATE_TRAVERSE_CONTEXT PowerContext
;
238 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
239 if (!NT_SUCCESS(Status
))
241 DPRINT1("No system power driver available\n");
246 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
247 if (Fdo
== DeviceObject
)
249 DPRINT("An FDO was not attached\n");
250 return STATUS_UNSUCCESSFUL
;
255 PowerContext
.PowerAction
= PowerAction
;
256 PowerContext
.SystemPowerState
= PowerState
;
257 PowerContext
.PowerDevice
= Fdo
;
259 /* Query for system power change */
260 IopInitDeviceTreeTraverseContext(&Context
,
262 PopQuerySystemPowerStateTraverse
,
265 Status
= IopTraverseDeviceTree(&Context
);
266 if (!NT_SUCCESS(Status
))
268 DPRINT1("Query system power state failed; changing state anyway\n");
271 /* Set system power change */
272 IopInitDeviceTreeTraverseContext(&Context
,
274 PopSetSystemPowerStateTraverse
,
277 IopTraverseDeviceTree(&Context
);
279 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
283 if (PowerAction
!= PowerActionShutdownReset
)
284 PopSendSetSystemPowerState(Fdo
, PowerState
, PowerAction
);
286 ObDereferenceObject(Fdo
);
295 PoInitSystem(IN ULONG BootPhase
)
297 PVOID NotificationEntry
;
299 BOOLEAN ForceAcpiDisable
= FALSE
;
301 /* Check if this is phase 1 init */
304 /* Register power button notification */
305 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
306 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
307 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
309 PhysicalDeviceObject
->DriverObject
,
310 PopAddRemoveSysCapsCallback
,
314 /* Register lid notification */
315 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
316 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
317 (PVOID
)&GUID_DEVICE_LID
,
319 PhysicalDeviceObject
->DriverObject
,
320 PopAddRemoveSysCapsCallback
,
326 /* Get the Command Line */
327 CommandLine
= KeLoaderBlock
->LoadOptions
;
330 _strupr(CommandLine
);
332 /* Check for ACPI disable */
333 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
335 if (ForceAcpiDisable
)
337 /* Set the ACPI State to False if it's been forced that way */
338 PopAcpiPresent
= FALSE
;
342 /* Otherwise check if the LoaderBlock has a ACPI Table */
343 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
347 /* Initialize volume support */
348 InitializeListHead(&PopVolumeDevices
);
349 KeInitializeGuardedMutex(&PopVolumeLock
);
351 /* Initialize support for dope */
352 KeInitializeSpinLock(&PopDopeGlobalLock
);
354 /* Initialize support for shutdown waits and work-items */
355 PopInitShutdownList();
362 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
364 DPRINT1("PerfIdle function: %p\n", PowerState
);
369 PopPerfIdleDpc(IN PKDPC Dpc
,
370 IN PVOID DeferredContext
,
371 IN PVOID SystemArgument1
,
372 IN PVOID SystemArgument2
)
374 /* Call the Perf Idle function */
375 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
380 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
382 /* FIXME: Extremly naive implementation */
389 PoInitializePrcb(IN PKPRCB Prcb
)
391 /* Initialize the Power State */
392 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
393 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
394 Prcb
->PowerState
.CurrentThrottle
= 100;
395 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
396 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
398 /* Initialize the Perf DPC and Timer */
399 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
400 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
401 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
404 /* PUBLIC FUNCTIONS **********************************************************/
411 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
414 return STATUS_NOT_IMPLEMENTED
;
422 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
430 return STATUS_NOT_IMPLEMENTED
;
438 PoShutdownBugCheck(IN BOOLEAN LogError
,
439 IN ULONG BugCheckCode
,
440 IN ULONG_PTR BugCheckParameter1
,
441 IN ULONG_PTR BugCheckParameter2
,
442 IN ULONG_PTR BugCheckParameter3
,
443 IN ULONG_PTR BugCheckParameter4
)
445 DPRINT1("PoShutdownBugCheck called\n");
447 /* FIXME: Log error if requested */
448 /* FIXME: Initiate a shutdown */
450 /* Bugcheck the system */
451 KeBugCheckEx(BugCheckCode
,
463 PoSetHiberRange(IN PVOID HiberContext
,
465 IN OUT PVOID StartPage
,
478 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
483 /* Forward to Io -- FIXME! */
484 Status
= IoCallDriver(DeviceObject
, Irp
);
495 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
496 IN ULONG ConservationIdleTime
,
497 IN ULONG PerformanceIdleTime
,
498 IN DEVICE_POWER_STATE State
)
509 PoRegisterSystemState(IN PVOID StateHandle
,
510 IN EXECUTION_STATE Flags
)
521 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
522 IN UCHAR MinorFunction
,
523 IN POWER_STATE PowerState
,
524 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
526 OUT PIRP
*pIrp OPTIONAL
)
528 PDEVICE_OBJECT TopDeviceObject
;
529 PIO_STACK_LOCATION Stack
;
532 if (MinorFunction
!= IRP_MN_QUERY_POWER
533 && MinorFunction
!= IRP_MN_SET_POWER
534 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
535 return STATUS_INVALID_PARAMETER_2
;
537 /* Always call the top of the device stack */
538 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
540 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
+ 2, FALSE
);
543 ObDereferenceObject(TopDeviceObject
);
544 return STATUS_INSUFFICIENT_RESOURCES
;
547 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
548 Irp
->IoStatus
.Information
= 0;
550 IoSetNextIrpStackLocation(Irp
);
552 Stack
= IoGetNextIrpStackLocation(Irp
);
553 Stack
->Parameters
.Others
.Argument1
= DeviceObject
;
554 Stack
->Parameters
.Others
.Argument2
= (PVOID
)(ULONG_PTR
)MinorFunction
;
555 Stack
->Parameters
.Others
.Argument3
= (PVOID
)(ULONG_PTR
)PowerState
.DeviceState
;
556 Stack
->Parameters
.Others
.Argument4
= Context
;
557 Stack
->DeviceObject
= TopDeviceObject
;
558 IoSetNextIrpStackLocation(Irp
);
560 Stack
= IoGetNextIrpStackLocation(Irp
);
561 Stack
->MajorFunction
= IRP_MJ_POWER
;
562 Stack
->MinorFunction
= MinorFunction
;
563 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
565 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
569 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
570 Stack
->Parameters
.Power
.State
= PowerState
;
576 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, CompletionFunction
, 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
)
660 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
664 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
665 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
666 PowerInformationLevel
,
667 InputBuffer
, InputBufferLength
,
668 OutputBuffer
, OutputBufferLength
);
670 if (PreviousMode
!= KernelMode
)
674 ProbeForRead(InputBuffer
, InputBufferLength
, 1);
675 ProbeForWrite(OutputBuffer
, OutputBufferLength
, sizeof(ULONG
));
677 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
679 _SEH2_YIELD(return _SEH2_GetExceptionCode());
684 switch (PowerInformationLevel
)
686 case SystemBatteryState
:
688 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
690 if (InputBuffer
!= NULL
)
691 return STATUS_INVALID_PARAMETER
;
692 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
693 return STATUS_BUFFER_TOO_SMALL
;
697 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
698 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
699 BatteryState
->EstimatedTime
= MAXULONG
;
701 Status
= STATUS_SUCCESS
;
703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
705 Status
= _SEH2_GetExceptionCode();
712 case SystemPowerCapabilities
:
714 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
716 if (InputBuffer
!= NULL
)
717 return STATUS_INVALID_PARAMETER
;
718 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
719 return STATUS_BUFFER_TOO_SMALL
;
723 /* Just zero the struct (and thus set PowerCapabilities->SystemBatteriesPresent = FALSE) */
724 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
725 //PowerCapabilities->SystemBatteriesPresent = 0;
727 Status
= STATUS_SUCCESS
;
729 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
731 Status
= _SEH2_GetExceptionCode();
738 case ProcessorInformation
:
740 PPROCESSOR_POWER_INFORMATION PowerInformation
= (PPROCESSOR_POWER_INFORMATION
)OutputBuffer
;
742 if (InputBuffer
!= NULL
)
743 return STATUS_INVALID_PARAMETER
;
744 if (OutputBufferLength
< sizeof(PROCESSOR_POWER_INFORMATION
))
745 return STATUS_BUFFER_TOO_SMALL
;
749 PowerInformation
->Number
= 0;
750 PowerInformation
->MaxMhz
= 1000;
751 PowerInformation
->CurrentMhz
= 1000;
752 PowerInformation
->MhzLimit
= 1000;
753 PowerInformation
->MaxIdleState
= 0;
754 PowerInformation
->CurrentIdleState
= 0;
756 Status
= STATUS_SUCCESS
;
758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
760 Status
= _SEH2_GetExceptionCode();
768 Status
= STATUS_NOT_IMPLEMENTED
;
769 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
770 PowerInformationLevel
);
779 NtGetDevicePowerState(IN HANDLE Device
,
780 IN PDEVICE_POWER_STATE PowerState
)
783 return STATUS_NOT_IMPLEMENTED
;
788 NtIsSystemResumeAutomatic(VOID
)
796 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
799 return STATUS_NOT_IMPLEMENTED
;
804 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
805 OUT EXECUTION_STATE
*PreviousFlags
)
807 PKTHREAD Thread
= KeGetCurrentThread();
808 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
809 EXECUTION_STATE PreviousState
;
813 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
815 /* Fail the request */
816 return STATUS_INVALID_PARAMETER
;
819 /* Check for user parameters */
820 if (PreviousMode
!= KernelMode
)
822 /* Protect the probes */
825 /* Check if the pointer is valid */
826 ProbeForWriteUlong(PreviousFlags
);
828 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
830 /* It isn't -- fail */
831 _SEH2_YIELD(return _SEH2_GetExceptionCode());
836 /* Save the previous state, always masking in the continous flag */
837 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
839 /* Check if we need to update the power state */
840 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= (UCHAR
)esFlags
;
842 /* Protect the write back to user mode */
845 /* Return the previous flags */
846 *PreviousFlags
= PreviousState
;
848 _SEH2_EXCEPT(ExSystemExceptionFilter())
850 /* Something's wrong, fail */
851 _SEH2_YIELD(return _SEH2_GetExceptionCode());
856 return STATUS_SUCCESS
;
861 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
862 IN SYSTEM_POWER_STATE MinSystemState
,
865 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
866 POP_POWER_ACTION Action
= {0};
870 /* Check for invalid parameter combinations */
871 if ((MinSystemState
>= PowerSystemMaximum
) ||
872 (MinSystemState
<= PowerSystemUnspecified
) ||
873 (SystemAction
> PowerActionWarmEject
) ||
874 (SystemAction
< PowerActionReserved
) ||
875 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
876 POWER_ACTION_UI_ALLOWED
|
877 POWER_ACTION_OVERRIDE_APPS
|
878 POWER_ACTION_LIGHTEST_FIRST
|
879 POWER_ACTION_LOCK_CONSOLE
|
880 POWER_ACTION_DISABLE_WAKES
|
881 POWER_ACTION_CRITICAL
)))
883 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
884 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
885 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
886 DPRINT1(" Flags: 0x%x\n", Flags
);
887 return STATUS_INVALID_PARAMETER
;
890 /* Check for user caller */
891 if (PreviousMode
!= KernelMode
)
893 /* Check for shutdown permission */
894 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
897 DPRINT1("ERROR: Privilege not held for shutdown\n");
898 return STATUS_PRIVILEGE_NOT_HELD
;
901 /* Do it as a kernel-mode caller for consistency with system state */
902 return ZwSetSystemPowerState(SystemAction
, MinSystemState
, Flags
);
905 /* Read policy settings (partial shutdown vs. full shutdown) */
906 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
908 /* Disable lazy flushing of registry */
909 DPRINT("Stopping lazy flush\n");
910 CmSetLazyFlushState(FALSE
);
912 /* Setup the power action */
913 Action
.Action
= SystemAction
;
914 Action
.Flags
= Flags
;
916 /* Notify callbacks */
917 DPRINT("Notifying callbacks\n");
918 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
920 /* Swap in any worker thread stacks */
921 DPRINT("Swapping worker threads\n");
922 ExSwapinWorkerThreads(FALSE
);
924 /* Make our action global */
927 /* Start power loop */
928 Status
= STATUS_CANCELLED
;
931 /* Break out if there's nothing to do */
932 if (Action
.Action
== PowerActionNone
) break;
934 /* Check for first-pass or restart */
935 if (Status
== STATUS_CANCELLED
)
937 /* Check for shutdown action */
938 if ((PopAction
.Action
== PowerActionShutdown
) ||
939 (PopAction
.Action
== PowerActionShutdownReset
) ||
940 (PopAction
.Action
== PowerActionShutdownOff
))
943 PopAction
.Shutdown
= TRUE
;
946 /* Now we are good to go */
947 Status
= STATUS_SUCCESS
;
950 /* Check if we're still in an invalid status */
951 if (!NT_SUCCESS(Status
)) break;
954 /* Flush dirty cache pages */
955 CcRosFlushDirtyPages(-1, &Dummy
, FALSE
); //HACK: We really should wait here!
960 /* Flush all volumes and the registry */
961 DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy
);
962 PopFlushVolumes(PopAction
.Shutdown
);
964 /* Set IRP for drivers */
965 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
966 if (PopAction
.Shutdown
)
968 DPRINT("Queueing shutdown thread\n");
969 /* Check if we are running in the system context */
970 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
972 /* We're not, so use a worker thread for shutdown */
973 ExInitializeWorkItem(&PopShutdownWorkItem
,
974 &PopGracefulShutdown
,
977 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
979 /* Spend us -- when we wake up, the system is good to go down */
980 KeSuspendThread(KeGetCurrentThread());
981 Status
= STATUS_SYSTEM_SHUTDOWN
;
987 /* Do the shutdown inline */
988 PopGracefulShutdown(NULL
);
992 /* You should not have made it this far */
993 // ASSERTMSG("System is still up and running?!", FALSE);
994 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction
.Action
);
999 /* We're done, return */