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 extern ULONG ExpInitialiationPhase
;
20 typedef struct _REQUEST_POWER_ITEM
22 PREQUEST_POWER_COMPLETE CompletionRoutine
;
23 POWER_STATE PowerState
;
25 } REQUEST_POWER_ITEM
, *PREQUEST_POWER_ITEM
;
27 PDEVICE_NODE PopSystemPowerDeviceNode
= NULL
;
28 BOOLEAN PopAcpiPresent
= FALSE
;
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
,
51 ExFreePool(&Irp
->IoStatus
);
54 return STATUS_SUCCESS
;
59 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
66 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
)
68 IO_STATUS_BLOCK IoStatusBlock
;
69 PDEVICE_OBJECT DeviceObject
;
70 PIO_STACK_LOCATION IrpSp
;
76 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
78 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
79 if (!NT_SUCCESS(Status
))
81 DPRINT1("No system power driver available\n");
82 return STATUS_UNSUCCESSFUL
;
85 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
87 if (Fdo
== DeviceObject
)
89 DPRINT("An FDO was not attached\n");
90 return STATUS_UNSUCCESSFUL
;
93 KeInitializeEvent(&Event
,
97 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
105 IrpSp
= IoGetNextIrpStackLocation(Irp
);
106 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
107 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
108 IrpSp
->Parameters
.Power
.State
.SystemState
= PowerState
;
110 DPRINT("Calling ACPI driver");
111 Status
= PoCallDriver(Fdo
, Irp
);
112 if (Status
== STATUS_PENDING
)
114 KeWaitForSingleObject(&Event
,
119 Status
= IoStatusBlock
.Status
;
122 ObDereferenceObject(Fdo
);
129 PoInitSystem(IN ULONG BootPhase
,
130 IN BOOLEAN HaveAcpiTable
)
132 PVOID NotificationEntry
;
134 BOOLEAN ForceAcpiDisable
= FALSE
;
136 /* Check if this is phase 1 init */
139 /* Registry power button notification */
140 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
141 0, /* The registry has not been initialized yet */
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 the LoaderBlock's Flag */
168 PopAcpiPresent
= HaveAcpiTable
;
176 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
178 DPRINT1("PerfIdle function: %p\n", PowerState
);
183 PopPerfIdleDpc(IN PKDPC Dpc
,
184 IN PVOID DeferredContext
,
185 IN PVOID SystemArgument1
,
186 IN PVOID SystemArgument2
)
188 /* Call the Perf Idle function */
189 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
194 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
196 /* FIXME: Extremly naive implementation */
202 PoInitializePrcb(IN PKPRCB Prcb
)
204 /* Initialize the Power State */
205 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
206 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
207 Prcb
->PowerState
.CurrentThrottle
= 100;
208 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
209 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
211 /* Initialize the Perf DPC and Timer */
212 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
213 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
214 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
217 /* PUBLIC FUNCTIONS **********************************************************/
224 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
227 return STATUS_NOT_IMPLEMENTED
;
235 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
243 return STATUS_NOT_IMPLEMENTED
;
251 PoShutdownBugCheck(IN BOOLEAN LogError
,
252 IN ULONG BugCheckCode
,
253 IN ULONG_PTR BugCheckParameter1
,
254 IN ULONG_PTR BugCheckParameter2
,
255 IN ULONG_PTR BugCheckParameter3
,
256 IN ULONG_PTR BugCheckParameter4
)
258 DPRINT1("PoShutdownBugCheck called\n");
260 /* FIXME: Log error if requested */
261 /* FIXME: Initiate a shutdown */
263 /* Bugcheck the system */
264 KeBugCheckEx(BugCheckCode
,
276 PoRequestShutdownEvent(OUT PVOID
*Event
)
279 return STATUS_NOT_IMPLEMENTED
;
287 PoSetHiberRange(IN PVOID HiberContext
,
289 IN OUT PVOID StartPage
,
302 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
307 /* Forward to Io -- FIXME! */
308 Status
= IoCallDriver(DeviceObject
, Irp
);
319 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
320 IN ULONG ConservationIdleTime
,
321 IN ULONG PerformanceIdleTime
,
322 IN DEVICE_POWER_STATE State
)
333 PoRegisterSystemState(IN PVOID StateHandle
,
334 IN EXECUTION_STATE Flags
)
345 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
346 IN UCHAR MinorFunction
,
347 IN POWER_STATE PowerState
,
348 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
350 OUT PIRP
*pIrp OPTIONAL
)
352 PDEVICE_OBJECT TopDeviceObject
;
353 PIO_STACK_LOCATION Stack
;
355 PIO_STATUS_BLOCK IoStatusBlock
;
356 PREQUEST_POWER_ITEM RequestPowerItem
;
359 if (MinorFunction
!= IRP_MN_QUERY_POWER
360 && MinorFunction
!= IRP_MN_SET_POWER
361 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
362 return STATUS_INVALID_PARAMETER_2
;
364 RequestPowerItem
= ExAllocatePool(NonPagedPool
, sizeof(REQUEST_POWER_ITEM
));
365 if (!RequestPowerItem
)
366 return STATUS_INSUFFICIENT_RESOURCES
;
367 IoStatusBlock
= ExAllocatePool(NonPagedPool
, sizeof(IO_STATUS_BLOCK
));
370 ExFreePool(RequestPowerItem
);
371 return STATUS_INSUFFICIENT_RESOURCES
;
374 /* Always call the top of the device stack */
375 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
377 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
,
386 ExFreePool(RequestPowerItem
);
387 ExFreePool(IoStatusBlock
);
388 return STATUS_INSUFFICIENT_RESOURCES
;
391 /* POWER IRPs are always initialized with a status code of
392 STATUS_NOT_IMPLEMENTED */
393 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
394 Irp
->IoStatus
.Information
= 0;
396 Stack
= IoGetNextIrpStackLocation(Irp
);
397 Stack
->MinorFunction
= MinorFunction
;
398 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
399 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
401 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.DeviceState
;
403 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
404 RequestPowerItem
->PowerState
= PowerState
;
405 RequestPowerItem
->Context
= Context
;
410 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, RequestPowerItem
, TRUE
, TRUE
, TRUE
);
411 Status
= IoCallDriver(TopDeviceObject
, Irp
);
413 /* Always return STATUS_PENDING. The completion routine
414 * will call CompletionFunction and complete the Irp.
416 return STATUS_PENDING
;
424 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
425 IN POWER_STATE_TYPE Type
,
426 IN POWER_STATE State
)
430 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
432 ps
.SystemState
= PowerSystemWorking
; // Fully on
433 ps
.DeviceState
= PowerDeviceD0
; // Fully on
443 PoSetSystemState(IN EXECUTION_STATE Flags
)
453 PoStartNextPowerIrp(IN PIRP Irp
)
463 PoUnregisterSystemState(IN PVOID StateHandle
)
473 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem
)
478 return STATUS_NOT_IMPLEMENTED
;
486 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
487 IN SYSTEM_POWER_STATE MinSystemState
,
489 IN BOOLEAN Asynchronous
)
492 return STATUS_NOT_IMPLEMENTED
;
500 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
501 IN PVOID InputBuffer OPTIONAL
,
502 IN ULONG InputBufferLength
,
503 OUT PVOID OutputBuffer OPTIONAL
,
504 IN ULONG OutputBufferLength
)
510 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
511 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
512 PowerInformationLevel
,
513 InputBuffer
, InputBufferLength
,
514 OutputBuffer
, OutputBufferLength
);
516 switch (PowerInformationLevel
)
518 case SystemBatteryState
:
520 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
522 if (InputBuffer
!= NULL
)
523 return STATUS_INVALID_PARAMETER
;
524 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
525 return STATUS_BUFFER_TOO_SMALL
;
527 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
528 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
529 BatteryState
->EstimatedTime
= (ULONG
)-1;
531 Status
= STATUS_SUCCESS
;
534 case SystemPowerCapabilities
:
536 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
538 if (InputBuffer
!= NULL
)
539 return STATUS_INVALID_PARAMETER
;
540 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
541 return STATUS_BUFFER_TOO_SMALL
;
543 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
544 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
545 //PowerCapabilities->SystemBatteriesPresent = 0;
547 Status
= STATUS_SUCCESS
;
552 Status
= STATUS_NOT_IMPLEMENTED
;
553 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
554 PowerInformationLevel
);
563 NtGetDevicePowerState(IN HANDLE Device
,
564 IN PDEVICE_POWER_STATE PowerState
)
567 return STATUS_NOT_IMPLEMENTED
;
572 NtIsSystemResumeAutomatic(VOID
)
580 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
583 return STATUS_NOT_IMPLEMENTED
;
588 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
589 OUT EXECUTION_STATE
*PreviousFlags
)
591 PKTHREAD Thread
= KeGetCurrentThread();
592 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
593 EXECUTION_STATE PreviousState
;
597 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
599 /* Fail the request */
600 return STATUS_INVALID_PARAMETER
;
603 /* Check for user parameters */
604 if (PreviousMode
!= KernelMode
)
606 /* Protect the probes */
609 /* Check if the pointer is valid */
610 ProbeForWriteUlong(PreviousFlags
);
612 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
614 /* It isn't -- fail */
615 _SEH2_YIELD(return _SEH2_GetExceptionCode());
620 /* Save the previous state, always masking in the continous flag */
621 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
623 /* Check if we need to update the power state */
624 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= esFlags
;
626 /* Protect the write back to user mode */
629 /* Return the previous flags */
630 *PreviousFlags
= PreviousState
;
632 _SEH2_EXCEPT(ExSystemExceptionFilter())
634 /* Something's wrong, fail */
635 _SEH2_YIELD(return _SEH2_GetExceptionCode());
640 return STATUS_SUCCESS
;