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 } REQUEST_POWER_ITEM
, *PREQUEST_POWER_ITEM
;
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_ITEM RequestPowerItem
;
42 Stack
= IoGetNextIrpStackLocation(Irp
);
43 RequestPowerItem
= (PREQUEST_POWER_ITEM
)Context
;
45 RequestPowerItem
->CompletionRoutine(DeviceObject
,
47 RequestPowerItem
->PowerState
,
48 RequestPowerItem
->Context
,
55 return STATUS_SUCCESS
;
60 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
67 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
)
69 IO_STATUS_BLOCK IoStatusBlock
;
70 PDEVICE_OBJECT DeviceObject
;
71 PIO_STACK_LOCATION IrpSp
;
77 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
79 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
80 if (!NT_SUCCESS(Status
))
82 DPRINT1("No system power driver available\n");
83 return STATUS_UNSUCCESSFUL
;
86 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
88 if (Fdo
== DeviceObject
)
90 DPRINT("An FDO was not attached\n");
91 return STATUS_UNSUCCESSFUL
;
94 KeInitializeEvent(&Event
,
98 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
106 IrpSp
= IoGetNextIrpStackLocation(Irp
);
107 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
108 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
109 IrpSp
->Parameters
.Power
.State
.SystemState
= PowerState
;
111 DPRINT("Calling ACPI driver");
112 Status
= PoCallDriver(Fdo
, Irp
);
113 if (Status
== STATUS_PENDING
)
115 KeWaitForSingleObject(&Event
,
120 Status
= IoStatusBlock
.Status
;
123 ObDereferenceObject(Fdo
);
130 PoInitSystem(IN ULONG BootPhase
)
132 PVOID NotificationEntry
;
134 BOOLEAN ForceAcpiDisable
= FALSE
;
136 /* Check if this is phase 1 init */
139 /* Registry power button notification */
140 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
141 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
142 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
144 PhysicalDeviceObject
->DriverObject
,
145 PopAddRemoveSysCapsCallback
,
151 /* Get the Command Line */
152 CommandLine
= KeLoaderBlock
->LoadOptions
;
155 _strupr(CommandLine
);
157 /* Check for ACPI disable */
158 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
160 if (ForceAcpiDisable
)
162 /* Set the ACPI State to False if it's been forced that way */
163 PopAcpiPresent
= FALSE
;
167 /* Otherwise check if the LoaderBlock has a ACPI Table */
168 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
172 /* Initialize volume support */
173 InitializeListHead(&PopVolumeDevices
);
174 KeInitializeGuardedMutex(&PopVolumeLock
);
176 /* Initialize support for dope */
177 KeInitializeSpinLock(&PopDopeGlobalLock
);
183 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
185 DPRINT1("PerfIdle function: %p\n", PowerState
);
190 PopPerfIdleDpc(IN PKDPC Dpc
,
191 IN PVOID DeferredContext
,
192 IN PVOID SystemArgument1
,
193 IN PVOID SystemArgument2
)
195 /* Call the Perf Idle function */
196 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
201 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
203 /* FIXME: Extremly naive implementation */
209 PoInitializePrcb(IN PKPRCB Prcb
)
211 /* Initialize the Power State */
212 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
213 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
214 Prcb
->PowerState
.CurrentThrottle
= 100;
215 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
216 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
218 /* Initialize the Perf DPC and Timer */
219 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
220 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
221 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
224 /* PUBLIC FUNCTIONS **********************************************************/
231 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
234 return STATUS_NOT_IMPLEMENTED
;
242 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
250 return STATUS_NOT_IMPLEMENTED
;
258 PoShutdownBugCheck(IN BOOLEAN LogError
,
259 IN ULONG BugCheckCode
,
260 IN ULONG_PTR BugCheckParameter1
,
261 IN ULONG_PTR BugCheckParameter2
,
262 IN ULONG_PTR BugCheckParameter3
,
263 IN ULONG_PTR BugCheckParameter4
)
265 DPRINT1("PoShutdownBugCheck called\n");
267 /* FIXME: Log error if requested */
268 /* FIXME: Initiate a shutdown */
270 /* Bugcheck the system */
271 KeBugCheckEx(BugCheckCode
,
283 PoRequestShutdownEvent(OUT PVOID
*Event
)
286 return STATUS_NOT_IMPLEMENTED
;
294 PoSetHiberRange(IN PVOID HiberContext
,
296 IN OUT PVOID StartPage
,
309 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
314 /* Forward to Io -- FIXME! */
315 Status
= IoCallDriver(DeviceObject
, Irp
);
326 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
327 IN ULONG ConservationIdleTime
,
328 IN ULONG PerformanceIdleTime
,
329 IN DEVICE_POWER_STATE State
)
340 PoRegisterSystemState(IN PVOID StateHandle
,
341 IN EXECUTION_STATE Flags
)
352 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
353 IN UCHAR MinorFunction
,
354 IN POWER_STATE PowerState
,
355 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
357 OUT PIRP
*pIrp OPTIONAL
)
359 PDEVICE_OBJECT TopDeviceObject
;
360 PIO_STACK_LOCATION Stack
;
362 PREQUEST_POWER_ITEM RequestPowerItem
;
365 if (MinorFunction
!= IRP_MN_QUERY_POWER
366 && MinorFunction
!= IRP_MN_SET_POWER
367 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
368 return STATUS_INVALID_PARAMETER_2
;
370 RequestPowerItem
= ExAllocatePool(NonPagedPool
, sizeof(REQUEST_POWER_ITEM
));
371 if (!RequestPowerItem
)
372 return STATUS_INSUFFICIENT_RESOURCES
;
374 /* Always call the top of the device stack */
375 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
377 Irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_POWER
,
385 ExFreePool(RequestPowerItem
);
386 return STATUS_INSUFFICIENT_RESOURCES
;
389 /* POWER IRPs are always initialized with a status code of
390 STATUS_NOT_IMPLEMENTED */
391 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
392 Irp
->IoStatus
.Information
= 0;
394 Stack
= IoGetNextIrpStackLocation(Irp
);
395 Stack
->MinorFunction
= MinorFunction
;
396 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
397 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
400 Stack
->Parameters
.Power
.Type
= DevicePowerState
;
401 Stack
->Parameters
.Power
.State
= PowerState
;
404 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
405 RequestPowerItem
->PowerState
= PowerState
;
406 RequestPowerItem
->Context
= Context
;
411 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, RequestPowerItem
, TRUE
, TRUE
, TRUE
);
412 Status
= IoCallDriver(TopDeviceObject
, Irp
);
414 /* Always return STATUS_PENDING. The completion routine
415 * will call CompletionFunction and complete the Irp.
417 return STATUS_PENDING
;
425 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
426 IN POWER_STATE_TYPE Type
,
427 IN POWER_STATE State
)
431 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
433 ps
.SystemState
= PowerSystemWorking
; // Fully on
434 ps
.DeviceState
= PowerDeviceD0
; // Fully on
444 PoSetSystemState(IN EXECUTION_STATE Flags
)
454 PoStartNextPowerIrp(IN PIRP Irp
)
464 PoUnregisterSystemState(IN PVOID StateHandle
)
474 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem
)
479 return STATUS_NOT_IMPLEMENTED
;
487 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
488 IN SYSTEM_POWER_STATE MinSystemState
,
490 IN BOOLEAN Asynchronous
)
493 return STATUS_NOT_IMPLEMENTED
;
501 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
502 IN PVOID InputBuffer OPTIONAL
,
503 IN ULONG InputBufferLength
,
504 OUT PVOID OutputBuffer OPTIONAL
,
505 IN ULONG OutputBufferLength
)
511 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
512 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
513 PowerInformationLevel
,
514 InputBuffer
, InputBufferLength
,
515 OutputBuffer
, OutputBufferLength
);
517 switch (PowerInformationLevel
)
519 case SystemBatteryState
:
521 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
523 if (InputBuffer
!= NULL
)
524 return STATUS_INVALID_PARAMETER
;
525 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
526 return STATUS_BUFFER_TOO_SMALL
;
528 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
529 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
530 BatteryState
->EstimatedTime
= MAXULONG
;
532 Status
= STATUS_SUCCESS
;
535 case SystemPowerCapabilities
:
537 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
539 if (InputBuffer
!= NULL
)
540 return STATUS_INVALID_PARAMETER
;
541 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
542 return STATUS_BUFFER_TOO_SMALL
;
544 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
545 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
546 //PowerCapabilities->SystemBatteriesPresent = 0;
548 Status
= STATUS_SUCCESS
;
553 Status
= STATUS_NOT_IMPLEMENTED
;
554 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
555 PowerInformationLevel
);
564 NtGetDevicePowerState(IN HANDLE Device
,
565 IN PDEVICE_POWER_STATE PowerState
)
568 return STATUS_NOT_IMPLEMENTED
;
573 NtIsSystemResumeAutomatic(VOID
)
581 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
584 return STATUS_NOT_IMPLEMENTED
;
589 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
590 OUT EXECUTION_STATE
*PreviousFlags
)
592 PKTHREAD Thread
= KeGetCurrentThread();
593 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
594 EXECUTION_STATE PreviousState
;
598 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
600 /* Fail the request */
601 return STATUS_INVALID_PARAMETER
;
604 /* Check for user parameters */
605 if (PreviousMode
!= KernelMode
)
607 /* Protect the probes */
610 /* Check if the pointer is valid */
611 ProbeForWriteUlong(PreviousFlags
);
613 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
615 /* It isn't -- fail */
616 _SEH2_YIELD(return _SEH2_GetExceptionCode());
621 /* Save the previous state, always masking in the continous flag */
622 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
624 /* Check if we need to update the power state */
625 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= esFlags
;
627 /* Protect the write back to user mode */
630 /* Return the previous flags */
631 *PreviousFlags
= PreviousState
;
633 _SEH2_EXCEPT(ExSystemExceptionFilter())
635 /* Something's wrong, fail */
636 _SEH2_YIELD(return _SEH2_GetExceptionCode());
641 return STATUS_SUCCESS
;
646 NtSetSystemPowerState(IN POWER_ACTION SystemAction
,
647 IN SYSTEM_POWER_STATE MinSystemState
,
650 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
651 POP_POWER_ACTION Action
= {0};
654 /* Check for invalid parameter combinations */
655 if ((MinSystemState
>= PowerSystemMaximum
) ||
656 (MinSystemState
<= PowerSystemUnspecified
) ||
657 (SystemAction
> PowerActionWarmEject
) ||
658 (SystemAction
< PowerActionReserved
) ||
659 (Flags
& ~(POWER_ACTION_QUERY_ALLOWED
|
660 POWER_ACTION_UI_ALLOWED
|
661 POWER_ACTION_OVERRIDE_APPS
|
662 POWER_ACTION_LIGHTEST_FIRST
|
663 POWER_ACTION_LOCK_CONSOLE
|
664 POWER_ACTION_DISABLE_WAKES
|
665 POWER_ACTION_CRITICAL
)))
667 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
668 DPRINT1(" SystemAction: 0x%x\n", SystemAction
);
669 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState
);
670 DPRINT1(" Flags: 0x%x\n", Flags
);
671 return STATUS_INVALID_PARAMETER
;
674 /* Check for user caller */
675 if (PreviousMode
!= KernelMode
)
677 /* Check for shutdown permission */
678 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege
, PreviousMode
))
681 DPRINT1("ERROR: Privilege not held for shutdown\n");
682 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
685 /* Do it as a kernel-mode caller for consistency with system state */
686 return ZwSetSystemPowerState (SystemAction
, MinSystemState
, Flags
);
689 /* Read policy settings (partial shutdown vs. full shutdown) */
690 if (SystemAction
== PowerActionShutdown
) PopReadShutdownPolicy();
692 /* Disable lazy flushing of registry */
693 DPRINT1("Stopping lazy flush\n");
694 CmSetLazyFlushState(FALSE
);
696 /* Setup the power action */
697 Action
.Action
= SystemAction
;
698 Action
.Flags
= Flags
;
700 /* Notify callbacks */
701 DPRINT1("Notifying callbacks\n");
702 ExNotifyCallback(PowerStateCallback
, (PVOID
)3, NULL
);
704 /* Swap in any worker thread stacks */
705 DPRINT1("Swapping worker threads\n");
706 ExSwapinWorkerThreads(FALSE
);
708 /* Make our action global */
711 /* Start power loop */
712 Status
= STATUS_CANCELLED
;
715 /* Break out if there's nothing to do */
716 if (Action
.Action
== PowerActionNone
) break;
718 /* Check for first-pass or restart */
719 if (Status
== STATUS_CANCELLED
)
721 /* Check for shutdown action */
722 if ((PopAction
.Action
== PowerActionShutdown
) ||
723 (PopAction
.Action
== PowerActionShutdownReset
) ||
724 (PopAction
.Action
== PowerActionShutdownOff
))
727 PopAction
.Shutdown
= TRUE
;
730 /* Now we are good to go */
731 Status
= STATUS_SUCCESS
;
734 /* Check if we're still in an invalid status */
735 if (!NT_SUCCESS(Status
)) break;
737 /* Flush all volumes and the registry */
738 DPRINT1("Flushing volumes\n");
739 PopFlushVolumes(PopAction
.Shutdown
);
741 /* Set IRP for drivers */
742 PopAction
.IrpMinor
= IRP_MN_SET_POWER
;
743 if (PopAction
.Shutdown
)
745 DPRINT1("Queueing shutdown thread\n");
746 /* Check if we are running in the system context */
747 if (PsGetCurrentProcess() != PsInitialSystemProcess
)
749 /* We're not, so use a worker thread for shutdown */
750 ExInitializeWorkItem(&PopShutdownWorkItem
,
751 &PopGracefulShutdown
,
754 ExQueueWorkItem(&PopShutdownWorkItem
, CriticalWorkQueue
);
756 /* Spend us -- when we wake up, the system is good to go down */
757 KeSuspendThread(KeGetCurrentThread());
758 Status
= STATUS_SYSTEM_SHUTDOWN
;
764 /* Do the shutdown inline */
765 PopGracefulShutdown(NULL
);
769 /* You should not have made it this far */
770 ASSERT(FALSE
&& "System is still up and running?!");
775 /* We're done, return */