- Rename KiSetSystemTime to KeSetSystemTime and enhance prototype for later use.
[reactos.git] / reactos / ntoskrnl / po / power.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/po/power.c
6 * PURPOSE: Power Manager
7 *
8 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * Hervé Poussineau (hpoussin@reactos.com)
10 */
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 extern ULONG ExpInitialiationPhase;
17
18 typedef struct _REQUEST_POWER_ITEM
19 {
20 PREQUEST_POWER_COMPLETE CompletionRoutine;
21 POWER_STATE PowerState;
22 PVOID Context;
23 } REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
24
25 PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
26 BOOLEAN PopAcpiPresent = FALSE;
27
28 /*
29 * @implemented
30 */
31 NTSTATUS
32 STDCALL
33 PoCallDriver(
34 IN PDEVICE_OBJECT DeviceObject,
35 IN OUT PIRP Irp)
36 {
37 NTSTATUS Status;
38
39 Status = IoCallDriver(DeviceObject, Irp);
40
41 return Status;
42 }
43
44 /*
45 * @unimplemented
46 */
47 PULONG
48 STDCALL
49 PoRegisterDeviceForIdleDetection(
50 IN PDEVICE_OBJECT DeviceObject,
51 IN ULONG ConservationIdleTime,
52 IN ULONG PerformanceIdleTime,
53 IN DEVICE_POWER_STATE State)
54 {
55 return NULL;
56 }
57
58 /*
59 * @unimplemented
60 */
61 PVOID
62 STDCALL
63 PoRegisterSystemState(
64 IN PVOID StateHandle,
65 IN EXECUTION_STATE Flags)
66 {
67 return NULL;
68 }
69
70 static
71 NTSTATUS STDCALL
72 PopRequestPowerIrpCompletion(
73 IN PDEVICE_OBJECT DeviceObject,
74 IN PIRP Irp,
75 IN PVOID Context)
76 {
77 PIO_STACK_LOCATION Stack;
78 PREQUEST_POWER_ITEM RequestPowerItem;
79
80 Stack = IoGetNextIrpStackLocation(Irp);
81 RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
82
83 RequestPowerItem->CompletionRoutine(
84 DeviceObject,
85 Stack->MinorFunction,
86 RequestPowerItem->PowerState,
87 RequestPowerItem->Context,
88 &Irp->IoStatus);
89
90 ExFreePool(&Irp->IoStatus);
91 ExFreePool(Context);
92 return STATUS_SUCCESS;
93 }
94
95 /*
96 * @implemented
97 */
98 NTSTATUS
99 STDCALL
100 PoRequestPowerIrp(
101 IN PDEVICE_OBJECT DeviceObject,
102 IN UCHAR MinorFunction,
103 IN POWER_STATE PowerState,
104 IN PREQUEST_POWER_COMPLETE CompletionFunction,
105 IN PVOID Context,
106 OUT PIRP *pIrp OPTIONAL)
107 {
108 PDEVICE_OBJECT TopDeviceObject;
109 PIO_STACK_LOCATION Stack;
110 PIRP Irp;
111 PIO_STATUS_BLOCK IoStatusBlock;
112 PREQUEST_POWER_ITEM RequestPowerItem;
113 NTSTATUS Status;
114
115 if (MinorFunction != IRP_MN_QUERY_POWER
116 && MinorFunction != IRP_MN_SET_POWER
117 && MinorFunction != IRP_MN_WAIT_WAKE)
118 return STATUS_INVALID_PARAMETER_2;
119
120 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
121 if (!RequestPowerItem)
122 return STATUS_INSUFFICIENT_RESOURCES;
123 IoStatusBlock = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
124 if (!IoStatusBlock)
125 {
126 ExFreePool(RequestPowerItem);
127 return STATUS_INSUFFICIENT_RESOURCES;
128 }
129
130 /* Always call the top of the device stack */
131 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
132
133 Irp = IoBuildSynchronousFsdRequest(
134 IRP_MJ_PNP,
135 TopDeviceObject,
136 NULL,
137 0,
138 NULL,
139 NULL,
140 IoStatusBlock);
141 if (!Irp)
142 {
143 ExFreePool(RequestPowerItem);
144 ExFreePool(IoStatusBlock);
145 return STATUS_INSUFFICIENT_RESOURCES;
146 }
147
148 /* POWER IRPs are always initialized with a status code of
149 STATUS_NOT_IMPLEMENTED */
150 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
151 Irp->IoStatus.Information = 0;
152
153 Stack = IoGetNextIrpStackLocation(Irp);
154 Stack->MinorFunction = MinorFunction;
155 if (MinorFunction == IRP_MN_WAIT_WAKE)
156 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
157 else
158 Stack->Parameters.WaitWake.PowerState = PowerState.DeviceState;
159
160 RequestPowerItem->CompletionRoutine = CompletionFunction;
161 RequestPowerItem->PowerState = PowerState;
162 RequestPowerItem->Context = Context;
163
164 if (pIrp != NULL)
165 *pIrp = Irp;
166
167 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
168 Status = IoCallDriver(TopDeviceObject, Irp);
169
170 /* Always return STATUS_PENDING. The completion routine
171 * will call CompletionFunction and complete the Irp.
172 */
173 return STATUS_PENDING;
174 }
175
176 #undef PoSetDeviceBusy
177 VOID
178 NTAPI
179 PoSetDeviceBusy(IN PULONG IdlePointer)
180 {
181 *IdlePointer = 0;
182 }
183
184 VOID
185 NTAPI
186 PopCleanupPowerState(IN PPOWER_STATE PowerState)
187 {
188 /* FIXME */
189 }
190
191 /*
192 * @unimplemented
193 */
194 POWER_STATE
195 STDCALL
196 PoSetPowerState(
197 IN PDEVICE_OBJECT DeviceObject,
198 IN POWER_STATE_TYPE Type,
199 IN POWER_STATE State)
200 {
201 POWER_STATE ps;
202
203 ASSERT_IRQL(DISPATCH_LEVEL);
204
205 ps.SystemState = PowerSystemWorking; // Fully on
206 ps.DeviceState = PowerDeviceD0; // Fully on
207
208 return ps;
209 }
210
211 /*
212 * @unimplemented
213 */
214 VOID
215 STDCALL
216 PoSetSystemState(
217 IN EXECUTION_STATE Flags)
218 {
219 }
220
221 /*
222 * @unimplemented
223 */
224 VOID
225 STDCALL
226 PoStartNextPowerIrp(
227 IN PIRP Irp)
228 {
229 }
230
231 /*
232 * @unimplemented
233 */
234 VOID
235 STDCALL
236 PoUnregisterSystemState(
237 IN PVOID StateHandle)
238 {
239 }
240
241 NTSTATUS
242 NTAPI
243 PopSetSystemPowerState(
244 SYSTEM_POWER_STATE PowerState)
245 {
246 IO_STATUS_BLOCK IoStatusBlock;
247 PDEVICE_OBJECT DeviceObject;
248 PIO_STACK_LOCATION IrpSp;
249 PDEVICE_OBJECT Fdo;
250 NTSTATUS Status;
251 KEVENT Event;
252 PIRP Irp;
253
254 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
255
256 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
257 if (!NT_SUCCESS(Status)) {
258 CPRINT("No system power driver available\n");
259 return STATUS_UNSUCCESSFUL;
260 }
261
262 Fdo = IoGetAttachedDeviceReference(DeviceObject);
263
264 if (Fdo == DeviceObject)
265 {
266 DPRINT("An FDO was not attached\n");
267 return STATUS_UNSUCCESSFUL;
268 }
269
270 KeInitializeEvent(&Event,
271 NotificationEvent,
272 FALSE);
273
274 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
275 Fdo,
276 NULL,
277 0,
278 NULL,
279 &Event,
280 &IoStatusBlock);
281
282 IrpSp = IoGetNextIrpStackLocation(Irp);
283 IrpSp->MinorFunction = IRP_MN_SET_POWER;
284 IrpSp->Parameters.Power.Type = SystemPowerState;
285 IrpSp->Parameters.Power.State.SystemState = PowerState;
286
287 Status = PoCallDriver(Fdo, Irp);
288 if (Status == STATUS_PENDING)
289 {
290 KeWaitForSingleObject(&Event,
291 Executive,
292 KernelMode,
293 FALSE,
294 NULL);
295 Status = IoStatusBlock.Status;
296 }
297
298 ObDereferenceObject(Fdo);
299
300 return Status;
301 }
302
303 BOOLEAN
304 NTAPI
305 PoInitSystem(IN ULONG BootPhase,
306 IN BOOLEAN HaveAcpiTable)
307 {
308 PVOID NotificationEntry;
309 PCHAR CommandLine;
310 BOOLEAN ForceAcpiDisable = FALSE;
311
312 /* Check if this is phase 1 init */
313 if (BootPhase == 1)
314 {
315 /* Registry power button notification */
316 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
317 0, /* The registry has not been initialized yet */
318 (PVOID)&GUID_DEVICE_SYS_BUTTON,
319 IopRootDeviceNode->
320 PhysicalDeviceObject->DriverObject,
321 PopAddRemoveSysCapsCallback,
322 NULL,
323 &NotificationEntry);
324 return TRUE;
325 }
326
327 /* Get the Command Line */
328 CommandLine = KeLoaderBlock->LoadOptions;
329
330 /* Upcase it */
331 _strupr(CommandLine);
332
333 /* Check for ACPI disable */
334 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
335
336 if (ForceAcpiDisable)
337 {
338 /* Set the ACPI State to False if it's been forced that way */
339 PopAcpiPresent = FALSE;
340 }
341 else
342 {
343 /* Otherwise check the LoaderBlock's Flag */
344 PopAcpiPresent = HaveAcpiTable;
345 }
346
347 return TRUE;
348 }
349
350 VOID
351 NTAPI
352 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
353 {
354 DPRINT1("PerfIdle function: %p\n", PowerState);
355 }
356
357 VOID
358 NTAPI
359 PopPerfIdleDpc(IN PKDPC Dpc,
360 IN PVOID DeferredContext,
361 IN PVOID SystemArgument1,
362 IN PVOID SystemArgument2)
363 {
364 /* Call the Perf Idle function */
365 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
366 }
367
368 VOID
369 FASTCALL
370 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
371 {
372 /* FIXME: Extremly naive implementation */
373 HalProcessorIdle();
374 }
375
376 VOID
377 NTAPI
378 PoInitializePrcb(IN PKPRCB Prcb)
379 {
380 /* Initialize the Power State */
381 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
382 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
383 Prcb->PowerState.CurrentThrottle = 100;
384 Prcb->PowerState.CurrentThrottleIndex = 0;
385 Prcb->PowerState.IdleFunction = PopIdle0;
386
387 /* Initialize the Perf DPC and Timer */
388 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
389 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
390 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
391 }
392
393 /*
394 * @unimplemented
395 */
396 NTSTATUS
397 STDCALL
398 NtInitiatePowerAction (
399 IN POWER_ACTION SystemAction,
400 IN SYSTEM_POWER_STATE MinSystemState,
401 IN ULONG Flags,
402 IN BOOLEAN Asynchronous)
403 {
404 UNIMPLEMENTED;
405 return STATUS_NOT_IMPLEMENTED;
406 }
407
408 /*
409 * @unimplemented
410 */
411 NTSTATUS
412 STDCALL
413 NtPowerInformation(
414 IN POWER_INFORMATION_LEVEL PowerInformationLevel,
415 IN PVOID InputBuffer OPTIONAL,
416 IN ULONG InputBufferLength,
417 OUT PVOID OutputBuffer OPTIONAL,
418 IN ULONG OutputBufferLength
419 )
420 {
421 NTSTATUS Status;
422
423 PAGED_CODE();
424
425 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
426 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
427 PowerInformationLevel,
428 InputBuffer, InputBufferLength,
429 OutputBuffer, OutputBufferLength);
430 switch (PowerInformationLevel)
431 {
432 case SystemBatteryState:
433 {
434 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
435
436 if (InputBuffer != NULL)
437 return STATUS_INVALID_PARAMETER;
438 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
439 return STATUS_BUFFER_TOO_SMALL;
440
441 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
442 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
443 BatteryState->EstimatedTime = (ULONG)-1;
444
445 Status = STATUS_SUCCESS;
446 break;
447 }
448
449 default:
450 Status = STATUS_NOT_IMPLEMENTED;
451 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
452 PowerInformationLevel);
453 break;
454 }
455
456 return Status;
457 }
458
459
460 NTSTATUS
461 STDCALL
462 PoQueueShutdownWorkItem(
463 IN PWORK_QUEUE_ITEM WorkItem
464 )
465 {
466 PAGED_CODE();
467
468 DPRINT1("PoQueueShutdownWorkItem(%p)\n", WorkItem);
469
470 return STATUS_NOT_IMPLEMENTED;
471 }
472
473 NTSTATUS
474 NTAPI
475 NtGetDevicePowerState(IN HANDLE Device,
476 IN PDEVICE_POWER_STATE PowerState)
477 {
478 UNIMPLEMENTED;
479 return STATUS_NOT_IMPLEMENTED;
480 }
481
482 BOOLEAN
483 NTAPI
484 NtIsSystemResumeAutomatic(VOID)
485 {
486 UNIMPLEMENTED;
487 return FALSE;
488 }
489
490 NTSTATUS
491 NTAPI
492 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
493 {
494 UNIMPLEMENTED;
495 return STATUS_NOT_IMPLEMENTED;
496 }
497
498 NTSTATUS
499 NTAPI
500 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
501 OUT EXECUTION_STATE *PreviousFlags)
502 {
503 UNIMPLEMENTED;
504 return STATUS_NOT_IMPLEMENTED;
505 }
506
507 /* EOF */