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
;
29 SYSTEM_POWER_CAPABILITIES PopCapabilities
;
31 /* PRIVATE FUNCTIONS *********************************************************/
36 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject
,
40 PIO_STACK_LOCATION Stack
;
41 PREQUEST_POWER_COMPLETE CompletionRoutine
;
42 POWER_STATE PowerState
;
44 Stack
= IoGetCurrentIrpStackLocation(Irp
);
45 CompletionRoutine
= Context
;
47 PowerState
.DeviceState
= (ULONG_PTR
)Stack
->Parameters
.Others
.Argument3
;
48 CompletionRoutine(Stack
->Parameters
.Others
.Argument1
,
49 (UCHAR
)(ULONG_PTR
)Stack
->Parameters
.Others
.Argument2
,
51 Stack
->Parameters
.Others
.Argument4
,
54 IoSkipCurrentIrpStackLocation(Irp
);
56 ObDereferenceObject(DeviceObject
);
58 return STATUS_MORE_PROCESSING_REQUIRED
;
63 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
69 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
72 IO_STATUS_BLOCK IoStatusBlock
;
73 PIO_STACK_LOCATION IrpSp
;
77 KeInitializeEvent(&Event
,
81 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
88 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
90 IrpSp
= IoGetNextIrpStackLocation(Irp
);
91 IrpSp
->MinorFunction
= IRP_MN_QUERY_POWER
;
92 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
93 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
94 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
96 Status
= PoCallDriver(DeviceObject
, Irp
);
97 if (Status
== STATUS_PENDING
)
99 KeWaitForSingleObject(&Event
,
104 Status
= IoStatusBlock
.Status
;
111 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
114 IO_STATUS_BLOCK IoStatusBlock
;
115 PIO_STACK_LOCATION IrpSp
;
119 KeInitializeEvent(&Event
,
123 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
130 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
132 IrpSp
= IoGetNextIrpStackLocation(Irp
);
133 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
134 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
135 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
136 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
138 Status
= PoCallDriver(DeviceObject
, Irp
);
139 if (Status
== STATUS_PENDING
)
141 KeWaitForSingleObject(&Event
,
146 Status
= IoStatusBlock
.Status
;
153 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
156 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
157 PDEVICE_OBJECT TopDeviceObject
;
160 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
162 if (DeviceNode
== IopRootDeviceNode
)
163 return STATUS_SUCCESS
;
165 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
166 return STATUS_SUCCESS
;
168 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
170 Status
= PopSendQuerySystemPowerState(TopDeviceObject
,
171 PowerStateContext
->SystemPowerState
,
172 PowerStateContext
->PowerAction
);
173 if (!NT_SUCCESS(Status
))
175 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode
->InstancePath
);
177 ObDereferenceObject(TopDeviceObject
);
182 return STATUS_SUCCESS
;
187 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
190 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
191 PDEVICE_OBJECT TopDeviceObject
;
194 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
196 if (DeviceNode
== IopRootDeviceNode
)
197 return STATUS_SUCCESS
;
199 if (DeviceNode
->PhysicalDeviceObject
== PowerStateContext
->PowerDevice
)
200 return STATUS_SUCCESS
;
202 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
203 return STATUS_SUCCESS
;
205 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
206 if (TopDeviceObject
== PowerStateContext
->PowerDevice
)
208 ObDereferenceObject(TopDeviceObject
);
209 return STATUS_SUCCESS
;
212 Status
= PopSendSetSystemPowerState(TopDeviceObject
,
213 PowerStateContext
->SystemPowerState
,
214 PowerStateContext
->PowerAction
);
215 if (!NT_SUCCESS(Status
))
217 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode
->InstancePath
);
220 ObDereferenceObject(TopDeviceObject
);
225 return STATUS_SUCCESS
;
231 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
, POWER_ACTION PowerAction
)
233 PDEVICE_OBJECT DeviceObject
;
236 DEVICETREE_TRAVERSE_CONTEXT Context
;
237 POWER_STATE_TRAVERSE_CONTEXT PowerContext
;
239 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
240 if (!NT_SUCCESS(Status
))
242 DPRINT1("No system power driver available\n");
247 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
248 if (Fdo
== DeviceObject
)
250 DPRINT("An FDO was not attached\n");
251 return STATUS_UNSUCCESSFUL
;
256 PowerContext
.PowerAction
= PowerAction
;
257 PowerContext
.SystemPowerState
= PowerState
;
258 PowerContext
.PowerDevice
= Fdo
;
260 /* Query for system power change */
261 IopInitDeviceTreeTraverseContext(&Context
,
263 PopQuerySystemPowerStateTraverse
,
266 Status
= IopTraverseDeviceTree(&Context
);
267 if (!NT_SUCCESS(Status
))
269 DPRINT1("Query system power state failed; changing state anyway\n");
272 /* Set system power change */
273 IopInitDeviceTreeTraverseContext(&Context
,
275 PopSetSystemPowerStateTraverse
,
278 IopTraverseDeviceTree(&Context
);
280 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
284 if (PowerAction
!= PowerActionShutdownReset
)
285 PopSendSetSystemPowerState(Fdo
, PowerState
, PowerAction
);
287 ObDereferenceObject(Fdo
);
296 PoInitSystem(IN ULONG BootPhase
)
298 PVOID NotificationEntry
;
300 BOOLEAN ForceAcpiDisable
= FALSE
;
302 /* Check if this is phase 1 init */
305 /* Register power button notification */
306 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
307 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
308 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
310 PhysicalDeviceObject
->DriverObject
,
311 PopAddRemoveSysCapsCallback
,
315 /* Register lid notification */
316 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
317 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
318 (PVOID
)&GUID_DEVICE_LID
,
320 PhysicalDeviceObject
->DriverObject
,
321 PopAddRemoveSysCapsCallback
,
327 /* Initialize the power capabilities */
328 RtlZeroMemory(&PopCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
330 /* Get the Command Line */
331 CommandLine
= KeLoaderBlock
->LoadOptions
;
334 _strupr(CommandLine
);
336 /* Check for ACPI disable */
337 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
339 if (ForceAcpiDisable
)
341 /* Set the ACPI State to False if it's been forced that way */
342 PopAcpiPresent
= FALSE
;
346 /* Otherwise check if the LoaderBlock has a ACPI Table */
347 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
350 /* Enable shutdown by power button */
352 PopCapabilities
.SystemS5
= TRUE
;
354 /* Initialize volume support */
355 InitializeListHead(&PopVolumeDevices
);
356 KeInitializeGuardedMutex(&PopVolumeLock
);
358 /* Initialize support for dope */
359 KeInitializeSpinLock(&PopDopeGlobalLock
);
361 /* Initialize support for shutdown waits and work-items */
362 PopInitShutdownList();
369 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
371 DPRINT1("PerfIdle function: %p\n", PowerState
);
376 PopPerfIdleDpc(IN PKDPC Dpc
,
377 IN PVOID DeferredContext
,
378 IN PVOID SystemArgument1
,
379 IN PVOID SystemArgument2
)
381 /* Call the Perf Idle function */
382 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
387 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
389 /* FIXME: Extremly naive implementation */
396 PoInitializePrcb(IN PKPRCB Prcb
)
398 /* Initialize the Power State */
399 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
400 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
401 Prcb
->PowerState
.CurrentThrottle
= 100;
402 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
403 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
405 /* Initialize the Perf DPC and Timer */
406 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
407 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
408 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
411 /* PUBLIC FUNCTIONS **********************************************************/
418 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
421 return STATUS_NOT_IMPLEMENTED
;
429 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
437 return STATUS_NOT_IMPLEMENTED
;
445 PoShutdownBugCheck(IN BOOLEAN LogError
,
446 IN ULONG BugCheckCode
,
447 IN ULONG_PTR BugCheckParameter1
,
448 IN ULONG_PTR BugCheckParameter2
,
449 IN ULONG_PTR BugCheckParameter3
,
450 IN ULONG_PTR BugCheckParameter4
)
452 DPRINT1("PoShutdownBugCheck called\n");
454 /* FIXME: Log error if requested */
455 /* FIXME: Initiate a shutdown */
457 /* Bugcheck the system */
458 KeBugCheckEx(BugCheckCode
,
470 PoSetHiberRange(IN PVOID HiberContext
,
472 IN OUT PVOID StartPage
,
485 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
490 /* Forward to Io -- FIXME! */
491 Status
= IoCallDriver(DeviceObject
, Irp
);
502 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
503 IN ULONG ConservationIdleTime
,
504 IN ULONG PerformanceIdleTime
,
505 IN DEVICE_POWER_STATE State
)
516 PoRegisterSystemState(IN PVOID StateHandle
,
517 IN EXECUTION_STATE Flags
)
528 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
529 IN UCHAR MinorFunction
,
530 IN POWER_STATE PowerState
,
531 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
533 OUT PIRP
*pIrp OPTIONAL
)
535 PDEVICE_OBJECT TopDeviceObject
;
536 PIO_STACK_LOCATION Stack
;
539 if (MinorFunction
!= IRP_MN_QUERY_POWER
540 && MinorFunction
!= IRP_MN_SET_POWER
541 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
542 return STATUS_INVALID_PARAMETER_2
;
544 /* Always call the top of the device stack */
545 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
547 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
+ 2, FALSE
);
550 ObDereferenceObject(TopDeviceObject
);
551 return STATUS_INSUFFICIENT_RESOURCES
;
554 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
555 Irp
->IoStatus
.Information
= 0;
557 IoSetNextIrpStackLocation(Irp
);
559 Stack
= IoGetNextIrpStackLocation(Irp
);
560 Stack
->Parameters
.Others
.Argument1
= DeviceObject
;
561 Stack
->Parameters
.Others
.Argument2
= (PVOID
)(ULONG_PTR
)MinorFunction
;
562 Stack
->Parameters
.Others
.Argument3
= (PVOID
)(ULONG_PTR
)PowerState
.DeviceState
;
563 Stack
->Parameters
.Others
.Argument4
= Context
;
564 Stack
->DeviceObject
= TopDeviceObject
;
565 IoSetNextIrpStackLocation(Irp
);
567 Stack
= IoGetNextIrpStackLocation(Irp
);
568 Stack
->MajorFunction
= IRP_MJ_POWER
;
569 Stack
->MinorFunction
= MinorFunction
;
570 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
572 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
576 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
577 Stack
->Parameters
.Power
.State
= PowerState
;
583 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, CompletionFunction
, TRUE
, TRUE
, TRUE
);
584 PoCallDriver(TopDeviceObject
, Irp
);
586 /* Always return STATUS_PENDING. The completion routine
587 * will call CompletionFunction and complete the Irp.
589 return STATUS_PENDING
;
597 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
598 IN POWER_STATE_TYPE Type
,
599 IN POWER_STATE State
)
603 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
605 ps
.SystemState
= PowerSystemWorking
; // Fully on
606 ps
.DeviceState
= PowerDeviceD0
; // Fully on
616 PoSetSystemState(IN EXECUTION_STATE Flags
)
626 PoStartNextPowerIrp(IN PIRP Irp
)
636 PoUnregisterSystemState(IN PVOID StateHandle
)
646 NtInitiatePowerAction(IN POWER_ACTION SystemAction
,
647 IN SYSTEM_POWER_STATE MinSystemState
,
649 IN BOOLEAN Asynchronous
)
652 return STATUS_NOT_IMPLEMENTED
;
660 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
661 IN PVOID InputBuffer OPTIONAL
,
662 IN ULONG InputBufferLength
,
663 OUT PVOID OutputBuffer OPTIONAL
,
664 IN ULONG OutputBufferLength
)
667 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
671 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
672 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
673 PowerInformationLevel
,
674 InputBuffer
, InputBufferLength
,
675 OutputBuffer
, OutputBufferLength
);
677 if (PreviousMode
!= KernelMode
)
681 ProbeForRead(InputBuffer
, InputBufferLength
, 1);
682 ProbeForWrite(OutputBuffer
, OutputBufferLength
, sizeof(ULONG
));
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
686 _SEH2_YIELD(return _SEH2_GetExceptionCode());
691 switch (PowerInformationLevel
)
693 case SystemBatteryState
:
695 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
697 if (InputBuffer
!= NULL
)
698 return STATUS_INVALID_PARAMETER
;
699 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
700 return STATUS_BUFFER_TOO_SMALL
;
704 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
705 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
706 BatteryState
->AcOnLine
= TRUE
;
708 Status
= STATUS_SUCCESS
;
710 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
712 Status
= _SEH2_GetExceptionCode();
719 case SystemPowerCapabilities
:
721 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
723 if (InputBuffer
!= NULL
)
724 return STATUS_INVALID_PARAMETER
;
725 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
726 return STATUS_BUFFER_TOO_SMALL
;
730 RtlCopyMemory(PowerCapabilities
,
732 sizeof(SYSTEM_POWER_CAPABILITIES
));
734 Status
= STATUS_SUCCESS
;
736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
738 Status
= _SEH2_GetExceptionCode();
745 case ProcessorInformation
:
747 PPROCESSOR_POWER_INFORMATION PowerInformation
= (PPROCESSOR_POWER_INFORMATION
)OutputBuffer
;
749 if (InputBuffer
!= NULL
)
750 return STATUS_INVALID_PARAMETER
;
751 if (OutputBufferLength
< sizeof(PROCESSOR_POWER_INFORMATION
))
752 return STATUS_BUFFER_TOO_SMALL
;
756 PowerInformation
->Number
= 0;
757 PowerInformation
->MaxMhz
= 1000;
758 PowerInformation
->CurrentMhz
= 1000;
759 PowerInformation
->MhzLimit
= 1000;
760 PowerInformation
->MaxIdleState
= 0;
761 PowerInformation
->CurrentIdleState
= 0;
763 Status
= STATUS_SUCCESS
;
765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
767 Status
= _SEH2_GetExceptionCode();
775 Status
= STATUS_NOT_IMPLEMENTED
;
776 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
777 PowerInformationLevel
);
786 NtGetDevicePowerState(IN HANDLE Device
,
787 IN PDEVICE_POWER_STATE PowerState
)
790 return STATUS_NOT_IMPLEMENTED
;
795 NtIsSystemResumeAutomatic(VOID
)
803 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
806 return STATUS_NOT_IMPLEMENTED
;
811 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
812 OUT EXECUTION_STATE
*PreviousFlags
)
814 PKTHREAD Thread
= KeGetCurrentThread();
815 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
816 EXECUTION_STATE PreviousState
;
820 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
822 /* Fail the request */
823 return STATUS_INVALID_PARAMETER
;
826 /* Check for user parameters */
827 if (PreviousMode
!= KernelMode
)
829 /* Protect the probes */
832 /* Check if the pointer is valid */
833 ProbeForWriteUlong(PreviousFlags
);
835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
837 /* It isn't -- fail */
838 _SEH2_YIELD(return _SEH2_GetExceptionCode());
843 /* Save the previous state, always masking in the continous flag */
844 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
846 /* Check if we need to update the power state */
847 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= (UCHAR
)esFlags
;
849 /* Protect the write back to user mode */
852 /* Return the previous flags */
853 *PreviousFlags
= PreviousState
;
855 _SEH2_EXCEPT(ExSystemExceptionFilter())
857 /* Something's wrong, fail */
858 _SEH2_YIELD(return _SEH2_GetExceptionCode());
863 return STATUS_SUCCESS
;
868 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
869 IN SYSTEM_POWER_STATE MinSystemState
,
872 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
873 POP_POWER_ACTION Action
= {0};
877 /* Check for invalid parameter combinations */
878 if ((MinSystemState
>= PowerSystemMaximum
) ||
879 (MinSystemState
<= PowerSystemUnspecified
) ||
880 (SystemAction
> PowerActionWarmEject
) ||
881 (SystemAction
< PowerActionReserved
) ||
882 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
883 POWER_ACTION_UI_ALLOWED
|
884 POWER_ACTION_OVERRIDE_APPS
|
885 POWER_ACTION_LIGHTEST_FIRST
|
886 POWER_ACTION_LOCK_CONSOLE
|
887 POWER_ACTION_DISABLE_WAKES
|
888 POWER_ACTION_CRITICAL
)))
890 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
891 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
892 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
893 DPRINT1(" Flags: 0x%x\n", Flags
);
894 return STATUS_INVALID_PARAMETER
;
897 /* Check for user caller */
898 if (PreviousMode
!= KernelMode
)
900 /* Check for shutdown permission */
901 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
904 DPRINT1("ERROR: Privilege not held for shutdown\n");
905 return STATUS_PRIVILEGE_NOT_HELD
;
908 /* Do it as a kernel-mode caller for consistency with system state */
909 return ZwSetSystemPowerState(SystemAction
, MinSystemState
, Flags
);
912 /* Read policy settings (partial shutdown vs. full shutdown) */
913 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
915 /* Disable lazy flushing of registry */
916 DPRINT("Stopping lazy flush\n");
917 CmSetLazyFlushState(FALSE
);
919 /* Setup the power action */
920 Action
.Action
= SystemAction
;
921 Action
.Flags
= Flags
;
923 /* Notify callbacks */
924 DPRINT("Notifying callbacks\n");
925 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
927 /* Swap in any worker thread stacks */
928 DPRINT("Swapping worker threads\n");
929 ExSwapinWorkerThreads(FALSE
);
931 /* Make our action global */
934 /* Start power loop */
935 Status
= STATUS_CANCELLED
;
938 /* Break out if there's nothing to do */
939 if (Action
.Action
== PowerActionNone
) break;
941 /* Check for first-pass or restart */
942 if (Status
== STATUS_CANCELLED
)
944 /* Check for shutdown action */
945 if ((PopAction
.Action
== PowerActionShutdown
) ||
946 (PopAction
.Action
== PowerActionShutdownReset
) ||
947 (PopAction
.Action
== PowerActionShutdownOff
))
950 PopAction
.Shutdown
= TRUE
;
953 /* Now we are good to go */
954 Status
= STATUS_SUCCESS
;
957 /* Check if we're still in an invalid status */
958 if (!NT_SUCCESS(Status
)) break;
961 /* Flush dirty cache pages */
962 /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */
963 CcRosFlushDirtyPages(-1, &Dummy
, FALSE
, FALSE
); //HACK: We really should wait here!
968 /* Flush all volumes and the registry */
969 DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy
);
970 PopFlushVolumes(PopAction
.Shutdown
);
972 /* Set IRP for drivers */
973 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
974 if (PopAction
.Shutdown
)
976 DPRINT("Queueing shutdown thread\n");
977 /* Check if we are running in the system context */
978 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
980 /* We're not, so use a worker thread for shutdown */
981 ExInitializeWorkItem(&PopShutdownWorkItem
,
982 &PopGracefulShutdown
,
985 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
987 /* Spend us -- when we wake up, the system is good to go down */
988 KeSuspendThread(KeGetCurrentThread());
989 Status
= STATUS_SYSTEM_SHUTDOWN
;
995 /* Do the shutdown inline */
996 PopGracefulShutdown(NULL
);
1000 /* You should not have made it this far */
1001 // ASSERTMSG("System is still up and running?!\n", FALSE);
1002 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction
.Action
);
1007 /* We're done, return */