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 } 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
,
63 return STATUS_MORE_PROCESSING_REQUIRED
;
68 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
74 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
77 IO_STATUS_BLOCK IoStatusBlock
;
78 PIO_STACK_LOCATION IrpSp
;
82 KeInitializeEvent(&Event
,
86 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
94 IrpSp
= IoGetNextIrpStackLocation(Irp
);
95 IrpSp
->MinorFunction
= IRP_MN_QUERY_POWER
;
96 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
97 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
98 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
100 Status
= PoCallDriver(DeviceObject
, Irp
);
101 if (Status
== STATUS_PENDING
)
103 KeWaitForSingleObject(&Event
,
108 Status
= IoStatusBlock
.Status
;
115 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject
, SYSTEM_POWER_STATE SystemState
, POWER_ACTION PowerAction
)
118 IO_STATUS_BLOCK IoStatusBlock
;
119 PIO_STACK_LOCATION IrpSp
;
123 KeInitializeEvent(&Event
,
127 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
135 IrpSp
= IoGetNextIrpStackLocation(Irp
);
136 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
137 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
138 IrpSp
->Parameters
.Power
.State
.SystemState
= SystemState
;
139 IrpSp
->Parameters
.Power
.ShutdownType
= PowerAction
;
141 Status
= PoCallDriver(DeviceObject
, Irp
);
142 if (Status
== STATUS_PENDING
)
144 KeWaitForSingleObject(&Event
,
149 Status
= IoStatusBlock
.Status
;
156 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
159 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
162 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
164 if (DeviceNode
== IopRootDeviceNode
)
165 return STATUS_SUCCESS
;
167 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
168 return STATUS_SUCCESS
;
170 Status
= PopSendQuerySystemPowerState(DeviceNode
->PhysicalDeviceObject
,
171 PowerStateContext
->SystemPowerState
,
172 PowerStateContext
->PowerAction
);
173 if (!NT_SUCCESS(Status
))
175 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode
->InstancePath
);
181 return STATUS_SUCCESS
;
186 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode
,
189 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext
= Context
;
192 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode
, Context
);
194 if (DeviceNode
== IopRootDeviceNode
)
195 return STATUS_SUCCESS
;
197 if (DeviceNode
->PhysicalDeviceObject
== PowerStateContext
->PowerDevice
)
198 return STATUS_SUCCESS
;
200 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
201 return STATUS_SUCCESS
;
203 Status
= PopSendSetSystemPowerState(DeviceNode
->PhysicalDeviceObject
,
204 PowerStateContext
->SystemPowerState
,
205 PowerStateContext
->PowerAction
);
206 if (!NT_SUCCESS(Status
))
208 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode
->InstancePath
);
214 return STATUS_SUCCESS
;
220 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
, POWER_ACTION PowerAction
)
222 PDEVICE_OBJECT DeviceObject
;
225 DEVICETREE_TRAVERSE_CONTEXT Context
;
226 POWER_STATE_TRAVERSE_CONTEXT PowerContext
;
228 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
229 if (!NT_SUCCESS(Status
))
231 DPRINT1("No system power driver available\n");
236 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
237 if (Fdo
== DeviceObject
)
239 DPRINT("An FDO was not attached\n");
240 return STATUS_UNSUCCESSFUL
;
245 PowerContext
.PowerAction
= PowerAction
;
246 PowerContext
.SystemPowerState
= PowerState
;
247 PowerContext
.PowerDevice
= Fdo
;
249 /* Query for system power change */
250 IopInitDeviceTreeTraverseContext(&Context
,
252 PopQuerySystemPowerStateTraverse
,
255 Status
= IopTraverseDeviceTree(&Context
);
256 if (!NT_SUCCESS(Status
))
258 DPRINT1("Query system power state failed; changing state anyway\n");
261 /* Set system power change */
262 IopInitDeviceTreeTraverseContext(&Context
,
264 PopSetSystemPowerStateTraverse
,
267 IopTraverseDeviceTree(&Context
);
269 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
273 if (PowerAction
!= PowerActionShutdownReset
)
274 PopSendSetSystemPowerState(Fdo
, PowerState
, PowerAction
);
276 ObDereferenceObject(Fdo
);
285 PoInitSystem(IN ULONG BootPhase
)
287 PVOID NotificationEntry
;
289 BOOLEAN ForceAcpiDisable
= FALSE
;
291 /* Check if this is phase 1 init */
294 /* Register power button notification */
295 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
296 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
297 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
299 PhysicalDeviceObject
->DriverObject
,
300 PopAddRemoveSysCapsCallback
,
304 /* Register lid notification */
305 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
306 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
307 (PVOID
)&GUID_DEVICE_LID
,
309 PhysicalDeviceObject
->DriverObject
,
310 PopAddRemoveSysCapsCallback
,
316 /* Get the Command Line */
317 CommandLine
= KeLoaderBlock
->LoadOptions
;
320 _strupr(CommandLine
);
322 /* Check for ACPI disable */
323 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
325 if (ForceAcpiDisable
)
327 /* Set the ACPI State to False if it's been forced that way */
328 PopAcpiPresent
= FALSE
;
332 /* Otherwise check if the LoaderBlock has a ACPI Table */
333 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
337 /* Initialize volume support */
338 InitializeListHead(&PopVolumeDevices
);
339 KeInitializeGuardedMutex(&PopVolumeLock
);
341 /* Initialize support for dope */
342 KeInitializeSpinLock(&PopDopeGlobalLock
);
348 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
350 DPRINT1("PerfIdle function: %p\n", PowerState
);
355 PopPerfIdleDpc(IN PKDPC Dpc
,
356 IN PVOID DeferredContext
,
357 IN PVOID SystemArgument1
,
358 IN PVOID SystemArgument2
)
360 /* Call the Perf Idle function */
361 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
366 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
368 /* FIXME: Extremly naive implementation */
375 PoInitializePrcb(IN PKPRCB Prcb
)
377 /* Initialize the Power State */
378 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
379 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
380 Prcb
->PowerState
.CurrentThrottle
= 100;
381 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
382 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
384 /* Initialize the Perf DPC and Timer */
385 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
386 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
387 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
390 /* PUBLIC FUNCTIONS **********************************************************/
397 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
400 return STATUS_NOT_IMPLEMENTED
;
408 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
416 return STATUS_NOT_IMPLEMENTED
;
424 PoShutdownBugCheck(IN BOOLEAN LogError
,
425 IN ULONG BugCheckCode
,
426 IN ULONG_PTR BugCheckParameter1
,
427 IN ULONG_PTR BugCheckParameter2
,
428 IN ULONG_PTR BugCheckParameter3
,
429 IN ULONG_PTR BugCheckParameter4
)
431 DPRINT1("PoShutdownBugCheck called\n");
433 /* FIXME: Log error if requested */
434 /* FIXME: Initiate a shutdown */
436 /* Bugcheck the system */
437 KeBugCheckEx(BugCheckCode
,
449 PoRequestShutdownEvent(OUT PVOID
*Event
)
452 return STATUS_NOT_IMPLEMENTED
;
460 PoSetHiberRange(IN PVOID HiberContext
,
462 IN OUT PVOID StartPage
,
475 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
480 /* Forward to Io -- FIXME! */
481 Status
= IoCallDriver(DeviceObject
, Irp
);
492 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
493 IN ULONG ConservationIdleTime
,
494 IN ULONG PerformanceIdleTime
,
495 IN DEVICE_POWER_STATE State
)
506 PoRegisterSystemState(IN PVOID StateHandle
,
507 IN EXECUTION_STATE Flags
)
518 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
519 IN UCHAR MinorFunction
,
520 IN POWER_STATE PowerState
,
521 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
523 OUT PIRP
*pIrp OPTIONAL
)
525 PDEVICE_OBJECT TopDeviceObject
;
526 PIO_STACK_LOCATION Stack
;
528 PREQUEST_POWER_ITEM RequestPowerItem
;
530 if (MinorFunction
!= IRP_MN_QUERY_POWER
531 && MinorFunction
!= IRP_MN_SET_POWER
532 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
533 return STATUS_INVALID_PARAMETER_2
;
535 RequestPowerItem
= ExAllocatePool(NonPagedPool
, sizeof(REQUEST_POWER_ITEM
));
536 if (!RequestPowerItem
)
537 return STATUS_INSUFFICIENT_RESOURCES
;
539 /* Always call the top of the device stack */
540 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
542 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_POWER
,
550 ExFreePool(RequestPowerItem
);
551 return STATUS_INSUFFICIENT_RESOURCES
;
554 /* POWER IRPs are always initialized with a status code of
555 STATUS_NOT_IMPLEMENTED */
556 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
557 Irp
->IoStatus
.Information
= 0;
559 Stack
= IoGetNextIrpStackLocation(Irp
);
560 Stack
->MinorFunction
= MinorFunction
;
561 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
562 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
565 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
566 Stack
->Parameters
.Power
.State
= PowerState
;
569 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
570 RequestPowerItem
->PowerState
= PowerState
;
571 RequestPowerItem
->Context
= Context
;
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 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem
)
644 return STATUS_NOT_IMPLEMENTED
;
652 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
653 IN SYSTEM_POWER_STATE MinSystemState
,
655 IN BOOLEAN Asynchronous
)
658 return STATUS_NOT_IMPLEMENTED
;
666 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
667 IN PVOID InputBuffer OPTIONAL
,
668 IN ULONG InputBufferLength
,
669 OUT PVOID OutputBuffer OPTIONAL
,
670 IN ULONG OutputBufferLength
)
676 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
677 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
678 PowerInformationLevel
,
679 InputBuffer
, InputBufferLength
,
680 OutputBuffer
, OutputBufferLength
);
682 switch (PowerInformationLevel
)
684 case SystemBatteryState
:
686 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
688 if (InputBuffer
!= NULL
)
689 return STATUS_INVALID_PARAMETER
;
690 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
691 return STATUS_BUFFER_TOO_SMALL
;
693 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
694 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
695 BatteryState
->EstimatedTime
= MAXULONG
;
697 Status
= STATUS_SUCCESS
;
700 case SystemPowerCapabilities
:
702 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
704 if (InputBuffer
!= NULL
)
705 return STATUS_INVALID_PARAMETER
;
706 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
707 return STATUS_BUFFER_TOO_SMALL
;
709 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
710 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
711 //PowerCapabilities->SystemBatteriesPresent = 0;
713 Status
= STATUS_SUCCESS
;
718 Status
= STATUS_NOT_IMPLEMENTED
;
719 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
720 PowerInformationLevel
);
729 NtGetDevicePowerState(IN HANDLE Device
,
730 IN PDEVICE_POWER_STATE PowerState
)
733 return STATUS_NOT_IMPLEMENTED
;
738 NtIsSystemResumeAutomatic(VOID
)
746 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
749 return STATUS_NOT_IMPLEMENTED
;
754 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
755 OUT EXECUTION_STATE
*PreviousFlags
)
757 PKTHREAD Thread
= KeGetCurrentThread();
758 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
759 EXECUTION_STATE PreviousState
;
763 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
765 /* Fail the request */
766 return STATUS_INVALID_PARAMETER
;
769 /* Check for user parameters */
770 if (PreviousMode
!= KernelMode
)
772 /* Protect the probes */
775 /* Check if the pointer is valid */
776 ProbeForWriteUlong(PreviousFlags
);
778 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
780 /* It isn't -- fail */
781 _SEH2_YIELD(return _SEH2_GetExceptionCode());
786 /* Save the previous state, always masking in the continous flag */
787 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
789 /* Check if we need to update the power state */
790 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= (UCHAR
)esFlags
;
792 /* Protect the write back to user mode */
795 /* Return the previous flags */
796 *PreviousFlags
= PreviousState
;
798 _SEH2_EXCEPT(ExSystemExceptionFilter())
800 /* Something's wrong, fail */
801 _SEH2_YIELD(return _SEH2_GetExceptionCode());
806 return STATUS_SUCCESS
;
811 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
812 IN SYSTEM_POWER_STATE MinSystemState
,
815 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
816 POP_POWER_ACTION Action
= {0};
820 /* Check for invalid parameter combinations */
821 if ((MinSystemState
>= PowerSystemMaximum
) ||
822 (MinSystemState
<= PowerSystemUnspecified
) ||
823 (SystemAction
> PowerActionWarmEject
) ||
824 (SystemAction
< PowerActionReserved
) ||
825 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
826 POWER_ACTION_UI_ALLOWED
|
827 POWER_ACTION_OVERRIDE_APPS
|
828 POWER_ACTION_LIGHTEST_FIRST
|
829 POWER_ACTION_LOCK_CONSOLE
|
830 POWER_ACTION_DISABLE_WAKES
|
831 POWER_ACTION_CRITICAL
)))
833 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
834 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
835 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
836 DPRINT1(" Flags: 0x%x\n", Flags
);
837 return STATUS_INVALID_PARAMETER
;
840 /* Check for user caller */
841 if (PreviousMode
!= KernelMode
)
843 /* Check for shutdown permission */
844 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
847 DPRINT1("ERROR: Privilege not held for shutdown\n");
848 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
851 /* Do it as a kernel-mode caller for consistency with system state */
852 return ZwSetSystemPowerState (SystemAction
, MinSystemState
, Flags
);
855 /* Read policy settings (partial shutdown vs. full shutdown) */
856 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
858 /* Disable lazy flushing of registry */
859 DPRINT1("Stopping lazy flush\n");
860 CmSetLazyFlushState(FALSE
);
862 /* Setup the power action */
863 Action
.Action
= SystemAction
;
864 Action
.Flags
= Flags
;
866 /* Notify callbacks */
867 DPRINT1("Notifying callbacks\n");
868 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
870 /* Swap in any worker thread stacks */
871 DPRINT1("Swapping worker threads\n");
872 ExSwapinWorkerThreads(FALSE
);
874 /* Make our action global */
877 /* Start power loop */
878 Status
= STATUS_CANCELLED
;
881 /* Break out if there's nothing to do */
882 if (Action
.Action
== PowerActionNone
) break;
884 /* Check for first-pass or restart */
885 if (Status
== STATUS_CANCELLED
)
887 /* Check for shutdown action */
888 if ((PopAction
.Action
== PowerActionShutdown
) ||
889 (PopAction
.Action
== PowerActionShutdownReset
) ||
890 (PopAction
.Action
== PowerActionShutdownOff
))
893 PopAction
.Shutdown
= TRUE
;
896 /* Now we are good to go */
897 Status
= STATUS_SUCCESS
;
900 /* Check if we're still in an invalid status */
901 if (!NT_SUCCESS(Status
)) break;
904 /* Flush dirty cache pages */
905 CcRosFlushDirtyPages(-1, &Dummy
, FALSE
); //HACK: We really should wait here!
910 /* Flush all volumes and the registry */
911 DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy
);
912 PopFlushVolumes(PopAction
.Shutdown
);
914 /* Set IRP for drivers */
915 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
916 if (PopAction
.Shutdown
)
918 DPRINT1("Queueing shutdown thread\n");
919 /* Check if we are running in the system context */
920 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
922 /* We're not, so use a worker thread for shutdown */
923 ExInitializeWorkItem(&PopShutdownWorkItem
,
924 &PopGracefulShutdown
,
927 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
929 /* Spend us -- when we wake up, the system is good to go down */
930 KeSuspendThread(KeGetCurrentThread());
931 Status
= STATUS_SYSTEM_SHUTDOWN
;
937 /* Do the shutdown inline */
938 PopGracefulShutdown(NULL
);
942 /* You should not have made it this far */
943 ASSERT(FALSE
&& "System is still up and running?!");
948 /* We're done, return */