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
;
28 /* PRIVATE FUNCTIONS *********************************************************/
33 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject
,
37 PIO_STACK_LOCATION Stack
;
38 PREQUEST_POWER_ITEM RequestPowerItem
;
40 Stack
= IoGetNextIrpStackLocation(Irp
);
41 RequestPowerItem
= (PREQUEST_POWER_ITEM
)Context
;
43 RequestPowerItem
->CompletionRoutine(DeviceObject
,
45 RequestPowerItem
->PowerState
,
46 RequestPowerItem
->Context
,
49 ExFreePool(&Irp
->IoStatus
);
52 return STATUS_SUCCESS
;
57 PopCleanupPowerState(IN PPOWER_STATE PowerState
)
64 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState
)
66 IO_STATUS_BLOCK IoStatusBlock
;
67 PDEVICE_OBJECT DeviceObject
;
68 PIO_STACK_LOCATION IrpSp
;
74 if (!PopAcpiPresent
) return STATUS_NOT_IMPLEMENTED
;
76 Status
= IopGetSystemPowerDeviceObject(&DeviceObject
);
77 if (!NT_SUCCESS(Status
))
79 DPRINT1("No system power driver available\n");
80 return STATUS_UNSUCCESSFUL
;
83 Fdo
= IoGetAttachedDeviceReference(DeviceObject
);
85 if (Fdo
== DeviceObject
)
87 DPRINT("An FDO was not attached\n");
88 return STATUS_UNSUCCESSFUL
;
91 KeInitializeEvent(&Event
,
95 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_POWER
,
103 IrpSp
= IoGetNextIrpStackLocation(Irp
);
104 IrpSp
->MinorFunction
= IRP_MN_SET_POWER
;
105 IrpSp
->Parameters
.Power
.Type
= SystemPowerState
;
106 IrpSp
->Parameters
.Power
.State
.SystemState
= PowerState
;
108 DPRINT("Calling ACPI driver");
109 Status
= PoCallDriver(Fdo
, Irp
);
110 if (Status
== STATUS_PENDING
)
112 KeWaitForSingleObject(&Event
,
117 Status
= IoStatusBlock
.Status
;
120 ObDereferenceObject(Fdo
);
127 PoInitSystem(IN ULONG BootPhase
)
129 PVOID NotificationEntry
;
131 BOOLEAN ForceAcpiDisable
= FALSE
;
133 /* Check if this is phase 1 init */
136 /* Registry power button notification */
137 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
138 0, /* The registry has not been initialized yet */
139 (PVOID
)&GUID_DEVICE_SYS_BUTTON
,
141 PhysicalDeviceObject
->DriverObject
,
142 PopAddRemoveSysCapsCallback
,
148 /* Get the Command Line */
149 CommandLine
= KeLoaderBlock
->LoadOptions
;
152 _strupr(CommandLine
);
154 /* Check for ACPI disable */
155 if (strstr(CommandLine
, "NOACPI")) ForceAcpiDisable
= TRUE
;
157 if (ForceAcpiDisable
)
159 /* Set the ACPI State to False if it's been forced that way */
160 PopAcpiPresent
= FALSE
;
164 /* Otherwise check if the LoaderBlock has a ACPI Table */
165 PopAcpiPresent
= KeLoaderBlock
->Extension
->AcpiTable
!= NULL
? TRUE
: FALSE
;
173 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState
)
175 DPRINT1("PerfIdle function: %p\n", PowerState
);
180 PopPerfIdleDpc(IN PKDPC Dpc
,
181 IN PVOID DeferredContext
,
182 IN PVOID SystemArgument1
,
183 IN PVOID SystemArgument2
)
185 /* Call the Perf Idle function */
186 PopPerfIdle(&((PKPRCB
)DeferredContext
)->PowerState
);
191 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState
)
193 /* FIXME: Extremly naive implementation */
199 PoInitializePrcb(IN PKPRCB Prcb
)
201 /* Initialize the Power State */
202 RtlZeroMemory(&Prcb
->PowerState
, sizeof(Prcb
->PowerState
));
203 Prcb
->PowerState
.Idle0KernelTimeLimit
= 0xFFFFFFFF;
204 Prcb
->PowerState
.CurrentThrottle
= 100;
205 Prcb
->PowerState
.CurrentThrottleIndex
= 0;
206 Prcb
->PowerState
.IdleFunction
= PopIdle0
;
208 /* Initialize the Perf DPC and Timer */
209 KeInitializeDpc(&Prcb
->PowerState
.PerfDpc
, PopPerfIdleDpc
, Prcb
);
210 KeSetTargetProcessorDpc(&Prcb
->PowerState
.PerfDpc
, Prcb
->Number
);
211 KeInitializeTimerEx(&Prcb
->PowerState
.PerfTimer
, SynchronizationTimer
);
214 /* PUBLIC FUNCTIONS **********************************************************/
221 PoCancelDeviceNotify(IN PVOID NotifyBlock
)
224 return STATUS_NOT_IMPLEMENTED
;
232 PoRegisterDeviceNotify(OUT PVOID Unknown0
,
240 return STATUS_NOT_IMPLEMENTED
;
248 PoShutdownBugCheck(IN BOOLEAN LogError
,
249 IN ULONG BugCheckCode
,
250 IN ULONG_PTR BugCheckParameter1
,
251 IN ULONG_PTR BugCheckParameter2
,
252 IN ULONG_PTR BugCheckParameter3
,
253 IN ULONG_PTR BugCheckParameter4
)
255 DPRINT1("PoShutdownBugCheck called\n");
257 /* FIXME: Log error if requested */
258 /* FIXME: Initiate a shutdown */
260 /* Bugcheck the system */
261 KeBugCheckEx(BugCheckCode
,
273 PoRequestShutdownEvent(OUT PVOID
*Event
)
276 return STATUS_NOT_IMPLEMENTED
;
284 PoSetHiberRange(IN PVOID HiberContext
,
286 IN OUT PVOID StartPage
,
299 PoCallDriver(IN PDEVICE_OBJECT DeviceObject
,
304 /* Forward to Io -- FIXME! */
305 Status
= IoCallDriver(DeviceObject
, Irp
);
316 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject
,
317 IN ULONG ConservationIdleTime
,
318 IN ULONG PerformanceIdleTime
,
319 IN DEVICE_POWER_STATE State
)
330 PoRegisterSystemState(IN PVOID StateHandle
,
331 IN EXECUTION_STATE Flags
)
342 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject
,
343 IN UCHAR MinorFunction
,
344 IN POWER_STATE PowerState
,
345 IN PREQUEST_POWER_COMPLETE CompletionFunction
,
347 OUT PIRP
*pIrp OPTIONAL
)
349 PDEVICE_OBJECT TopDeviceObject
;
350 PIO_STACK_LOCATION Stack
;
352 PIO_STATUS_BLOCK IoStatusBlock
;
353 PREQUEST_POWER_ITEM RequestPowerItem
;
356 if (MinorFunction
!= IRP_MN_QUERY_POWER
357 && MinorFunction
!= IRP_MN_SET_POWER
358 && MinorFunction
!= IRP_MN_WAIT_WAKE
)
359 return STATUS_INVALID_PARAMETER_2
;
361 RequestPowerItem
= ExAllocatePool(NonPagedPool
, sizeof(REQUEST_POWER_ITEM
));
362 if (!RequestPowerItem
)
363 return STATUS_INSUFFICIENT_RESOURCES
;
364 IoStatusBlock
= ExAllocatePool(NonPagedPool
, sizeof(IO_STATUS_BLOCK
));
367 ExFreePool(RequestPowerItem
);
368 return STATUS_INSUFFICIENT_RESOURCES
;
371 /* Always call the top of the device stack */
372 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
374 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
,
383 ExFreePool(RequestPowerItem
);
384 ExFreePool(IoStatusBlock
);
385 return STATUS_INSUFFICIENT_RESOURCES
;
388 /* POWER IRPs are always initialized with a status code of
389 STATUS_NOT_IMPLEMENTED */
390 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
391 Irp
->IoStatus
.Information
= 0;
393 Stack
= IoGetNextIrpStackLocation(Irp
);
394 Stack
->MinorFunction
= MinorFunction
;
395 if (MinorFunction
== IRP_MN_WAIT_WAKE
)
396 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.SystemState
;
398 Stack
->Parameters
.WaitWake
.PowerState
= PowerState
.DeviceState
;
400 RequestPowerItem
->CompletionRoutine
= CompletionFunction
;
401 RequestPowerItem
->PowerState
= PowerState
;
402 RequestPowerItem
->Context
= Context
;
407 IoSetCompletionRoutine(Irp
, PopRequestPowerIrpCompletion
, RequestPowerItem
, TRUE
, TRUE
, TRUE
);
408 Status
= IoCallDriver(TopDeviceObject
, Irp
);
410 /* Always return STATUS_PENDING. The completion routine
411 * will call CompletionFunction and complete the Irp.
413 return STATUS_PENDING
;
421 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject
,
422 IN POWER_STATE_TYPE Type
,
423 IN POWER_STATE State
)
427 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
429 ps
.SystemState
= PowerSystemWorking
; // Fully on
430 ps
.DeviceState
= PowerDeviceD0
; // Fully on
440 PoSetSystemState(IN EXECUTION_STATE Flags
)
450 PoStartNextPowerIrp(IN PIRP Irp
)
460 PoUnregisterSystemState(IN PVOID StateHandle
)
470 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem
)
475 return STATUS_NOT_IMPLEMENTED
;
483 NtInitiatePowerAction (IN POWER_ACTION SystemAction
,
484 IN SYSTEM_POWER_STATE MinSystemState
,
486 IN BOOLEAN Asynchronous
)
489 return STATUS_NOT_IMPLEMENTED
;
497 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel
,
498 IN PVOID InputBuffer OPTIONAL
,
499 IN ULONG InputBufferLength
,
500 OUT PVOID OutputBuffer OPTIONAL
,
501 IN ULONG OutputBufferLength
)
507 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
508 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
509 PowerInformationLevel
,
510 InputBuffer
, InputBufferLength
,
511 OutputBuffer
, OutputBufferLength
);
513 switch (PowerInformationLevel
)
515 case SystemBatteryState
:
517 PSYSTEM_BATTERY_STATE BatteryState
= (PSYSTEM_BATTERY_STATE
)OutputBuffer
;
519 if (InputBuffer
!= NULL
)
520 return STATUS_INVALID_PARAMETER
;
521 if (OutputBufferLength
< sizeof(SYSTEM_BATTERY_STATE
))
522 return STATUS_BUFFER_TOO_SMALL
;
524 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
525 RtlZeroMemory(BatteryState
, sizeof(SYSTEM_BATTERY_STATE
));
526 BatteryState
->EstimatedTime
= MAXULONG
;
528 Status
= STATUS_SUCCESS
;
531 case SystemPowerCapabilities
:
533 PSYSTEM_POWER_CAPABILITIES PowerCapabilities
= (PSYSTEM_POWER_CAPABILITIES
)OutputBuffer
;
535 if (InputBuffer
!= NULL
)
536 return STATUS_INVALID_PARAMETER
;
537 if (OutputBufferLength
< sizeof(SYSTEM_POWER_CAPABILITIES
))
538 return STATUS_BUFFER_TOO_SMALL
;
540 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
541 RtlZeroMemory(PowerCapabilities
, sizeof(SYSTEM_POWER_CAPABILITIES
));
542 //PowerCapabilities->SystemBatteriesPresent = 0;
544 Status
= STATUS_SUCCESS
;
549 Status
= STATUS_NOT_IMPLEMENTED
;
550 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
551 PowerInformationLevel
);
560 NtGetDevicePowerState(IN HANDLE Device
,
561 IN PDEVICE_POWER_STATE PowerState
)
564 return STATUS_NOT_IMPLEMENTED
;
569 NtIsSystemResumeAutomatic(VOID
)
577 NtRequestWakeupLatency(IN LATENCY_TIME Latency
)
580 return STATUS_NOT_IMPLEMENTED
;
585 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags
,
586 OUT EXECUTION_STATE
*PreviousFlags
)
588 PKTHREAD Thread
= KeGetCurrentThread();
589 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
590 EXECUTION_STATE PreviousState
;
594 if (esFlags
& ~(ES_CONTINUOUS
| ES_USER_PRESENT
))
596 /* Fail the request */
597 return STATUS_INVALID_PARAMETER
;
600 /* Check for user parameters */
601 if (PreviousMode
!= KernelMode
)
603 /* Protect the probes */
606 /* Check if the pointer is valid */
607 ProbeForWriteUlong(PreviousFlags
);
609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
611 /* It isn't -- fail */
612 _SEH2_YIELD(return _SEH2_GetExceptionCode());
617 /* Save the previous state, always masking in the continous flag */
618 PreviousState
= Thread
->PowerState
| ES_CONTINUOUS
;
620 /* Check if we need to update the power state */
621 if (esFlags
& ES_CONTINUOUS
) Thread
->PowerState
= esFlags
;
623 /* Protect the write back to user mode */
626 /* Return the previous flags */
627 *PreviousFlags
= PreviousState
;
629 _SEH2_EXCEPT(ExSystemExceptionFilter())
631 /* Something's wrong, fail */
632 _SEH2_YIELD(return _SEH2_GetExceptionCode());
637 return STATUS_SUCCESS
;