Merge trunk HEAD (r46369)
[reactos.git] / reactos / ntoskrnl / po / power.c
1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
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 /* PRIVATE FUNCTIONS *********************************************************/
29
30 static
31 NTSTATUS
32 NTAPI
33 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
34 IN PIRP Irp,
35 IN PVOID Context)
36 {
37 PIO_STACK_LOCATION Stack;
38 PREQUEST_POWER_ITEM RequestPowerItem;
39
40 Stack = IoGetNextIrpStackLocation(Irp);
41 RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
42
43 RequestPowerItem->CompletionRoutine(DeviceObject,
44 Stack->MinorFunction,
45 RequestPowerItem->PowerState,
46 RequestPowerItem->Context,
47 &Irp->IoStatus);
48
49 ExFreePool(&Irp->IoStatus);
50 ExFreePool(Context);
51
52 return STATUS_SUCCESS;
53 }
54
55 VOID
56 NTAPI
57 PopCleanupPowerState(IN PPOWER_STATE PowerState)
58 {
59 //UNIMPLEMENTED;
60 }
61
62 NTSTATUS
63 NTAPI
64 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState)
65 {
66 IO_STATUS_BLOCK IoStatusBlock;
67 PDEVICE_OBJECT DeviceObject;
68 PIO_STACK_LOCATION IrpSp;
69 PDEVICE_OBJECT Fdo;
70 NTSTATUS Status;
71 KEVENT Event;
72 PIRP Irp;
73
74 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
75
76 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
77 if (!NT_SUCCESS(Status))
78 {
79 DPRINT1("No system power driver available\n");
80 return STATUS_UNSUCCESSFUL;
81 }
82
83 Fdo = IoGetAttachedDeviceReference(DeviceObject);
84
85 if (Fdo == DeviceObject)
86 {
87 DPRINT("An FDO was not attached\n");
88 return STATUS_UNSUCCESSFUL;
89 }
90
91 KeInitializeEvent(&Event,
92 NotificationEvent,
93 FALSE);
94
95 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
96 Fdo,
97 NULL,
98 0,
99 NULL,
100 &Event,
101 &IoStatusBlock);
102
103 IrpSp = IoGetNextIrpStackLocation(Irp);
104 IrpSp->MinorFunction = IRP_MN_SET_POWER;
105 IrpSp->Parameters.Power.Type = SystemPowerState;
106 IrpSp->Parameters.Power.State.SystemState = PowerState;
107
108 DPRINT("Calling ACPI driver");
109 Status = PoCallDriver(Fdo, Irp);
110 if (Status == STATUS_PENDING)
111 {
112 KeWaitForSingleObject(&Event,
113 Executive,
114 KernelMode,
115 FALSE,
116 NULL);
117 Status = IoStatusBlock.Status;
118 }
119
120 ObDereferenceObject(Fdo);
121
122 return Status;
123 }
124
125 BOOLEAN
126 NTAPI
127 PoInitSystem(IN ULONG BootPhase)
128 {
129 PVOID NotificationEntry;
130 PCHAR CommandLine;
131 BOOLEAN ForceAcpiDisable = FALSE;
132
133 /* Check if this is phase 1 init */
134 if (BootPhase == 1)
135 {
136 /* Registry power button notification */
137 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
138 0, /* The registry has not been initialized yet */
139 (PVOID)&GUID_DEVICE_SYS_BUTTON,
140 IopRootDeviceNode->
141 PhysicalDeviceObject->DriverObject,
142 PopAddRemoveSysCapsCallback,
143 NULL,
144 &NotificationEntry);
145 return TRUE;
146 }
147
148 /* Get the Command Line */
149 CommandLine = KeLoaderBlock->LoadOptions;
150
151 /* Upcase it */
152 _strupr(CommandLine);
153
154 /* Check for ACPI disable */
155 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
156
157 if (ForceAcpiDisable)
158 {
159 /* Set the ACPI State to False if it's been forced that way */
160 PopAcpiPresent = FALSE;
161 }
162 else
163 {
164 /* Otherwise check if the LoaderBlock has a ACPI Table */
165 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
166 }
167
168 return TRUE;
169 }
170
171 VOID
172 NTAPI
173 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
174 {
175 DPRINT1("PerfIdle function: %p\n", PowerState);
176 }
177
178 VOID
179 NTAPI
180 PopPerfIdleDpc(IN PKDPC Dpc,
181 IN PVOID DeferredContext,
182 IN PVOID SystemArgument1,
183 IN PVOID SystemArgument2)
184 {
185 /* Call the Perf Idle function */
186 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
187 }
188
189 VOID
190 FASTCALL
191 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
192 {
193 /* FIXME: Extremly naive implementation */
194 HalProcessorIdle();
195 }
196
197 VOID
198 NTAPI
199 PoInitializePrcb(IN PKPRCB Prcb)
200 {
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;
207
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);
212 }
213
214 /* PUBLIC FUNCTIONS **********************************************************/
215
216 /*
217 * @unimplemented
218 */
219 NTSTATUS
220 NTAPI
221 PoCancelDeviceNotify(IN PVOID NotifyBlock)
222 {
223 UNIMPLEMENTED;
224 return STATUS_NOT_IMPLEMENTED;
225 }
226
227 /*
228 * @unimplemented
229 */
230 NTSTATUS
231 NTAPI
232 PoRegisterDeviceNotify(OUT PVOID Unknown0,
233 IN ULONG Unknown1,
234 IN ULONG Unknown2,
235 IN ULONG Unknown3,
236 IN PVOID Unknown4,
237 IN PVOID Unknown5)
238 {
239 UNIMPLEMENTED;
240 return STATUS_NOT_IMPLEMENTED;
241 }
242
243 /*
244 * @unimplemented
245 */
246 VOID
247 NTAPI
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)
254 {
255 DPRINT1("PoShutdownBugCheck called\n");
256
257 /* FIXME: Log error if requested */
258 /* FIXME: Initiate a shutdown */
259
260 /* Bugcheck the system */
261 KeBugCheckEx(BugCheckCode,
262 BugCheckParameter1,
263 BugCheckParameter2,
264 BugCheckParameter3,
265 BugCheckParameter4);
266 }
267
268 /*
269 * @unimplemented
270 */
271 NTSTATUS
272 NTAPI
273 PoRequestShutdownEvent(OUT PVOID *Event)
274 {
275 UNIMPLEMENTED;
276 return STATUS_NOT_IMPLEMENTED;
277 }
278
279 /*
280 * @unimplemented
281 */
282 VOID
283 NTAPI
284 PoSetHiberRange(IN PVOID HiberContext,
285 IN ULONG Flags,
286 IN OUT PVOID StartPage,
287 IN ULONG Length,
288 IN ULONG PageTag)
289 {
290 UNIMPLEMENTED;
291 return;
292 }
293
294 /*
295 * @implemented
296 */
297 NTSTATUS
298 NTAPI
299 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
300 IN OUT PIRP Irp)
301 {
302 NTSTATUS Status;
303
304 /* Forward to Io -- FIXME! */
305 Status = IoCallDriver(DeviceObject, Irp);
306
307 /* Return status */
308 return Status;
309 }
310
311 /*
312 * @unimplemented
313 */
314 PULONG
315 NTAPI
316 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
317 IN ULONG ConservationIdleTime,
318 IN ULONG PerformanceIdleTime,
319 IN DEVICE_POWER_STATE State)
320 {
321 UNIMPLEMENTED;
322 return NULL;
323 }
324
325 /*
326 * @unimplemented
327 */
328 PVOID
329 NTAPI
330 PoRegisterSystemState(IN PVOID StateHandle,
331 IN EXECUTION_STATE Flags)
332 {
333 UNIMPLEMENTED;
334 return NULL;
335 }
336
337 /*
338 * @implemented
339 */
340 NTSTATUS
341 NTAPI
342 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
343 IN UCHAR MinorFunction,
344 IN POWER_STATE PowerState,
345 IN PREQUEST_POWER_COMPLETE CompletionFunction,
346 IN PVOID Context,
347 OUT PIRP *pIrp OPTIONAL)
348 {
349 PDEVICE_OBJECT TopDeviceObject;
350 PIO_STACK_LOCATION Stack;
351 PIRP Irp;
352 PIO_STATUS_BLOCK IoStatusBlock;
353 PREQUEST_POWER_ITEM RequestPowerItem;
354 NTSTATUS Status;
355
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;
360
361 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
362 if (!RequestPowerItem)
363 return STATUS_INSUFFICIENT_RESOURCES;
364 IoStatusBlock = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
365 if (!IoStatusBlock)
366 {
367 ExFreePool(RequestPowerItem);
368 return STATUS_INSUFFICIENT_RESOURCES;
369 }
370
371 /* Always call the top of the device stack */
372 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
373
374 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
375 TopDeviceObject,
376 NULL,
377 0,
378 NULL,
379 NULL,
380 IoStatusBlock);
381 if (!Irp)
382 {
383 ExFreePool(RequestPowerItem);
384 ExFreePool(IoStatusBlock);
385 return STATUS_INSUFFICIENT_RESOURCES;
386 }
387
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;
392
393 Stack = IoGetNextIrpStackLocation(Irp);
394 Stack->MinorFunction = MinorFunction;
395 if (MinorFunction == IRP_MN_WAIT_WAKE)
396 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
397 else
398 Stack->Parameters.WaitWake.PowerState = PowerState.DeviceState;
399
400 RequestPowerItem->CompletionRoutine = CompletionFunction;
401 RequestPowerItem->PowerState = PowerState;
402 RequestPowerItem->Context = Context;
403
404 if (pIrp != NULL)
405 *pIrp = Irp;
406
407 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
408 Status = IoCallDriver(TopDeviceObject, Irp);
409
410 /* Always return STATUS_PENDING. The completion routine
411 * will call CompletionFunction and complete the Irp.
412 */
413 return STATUS_PENDING;
414 }
415
416 /*
417 * @unimplemented
418 */
419 POWER_STATE
420 NTAPI
421 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
422 IN POWER_STATE_TYPE Type,
423 IN POWER_STATE State)
424 {
425 POWER_STATE ps;
426
427 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
428
429 ps.SystemState = PowerSystemWorking; // Fully on
430 ps.DeviceState = PowerDeviceD0; // Fully on
431
432 return ps;
433 }
434
435 /*
436 * @unimplemented
437 */
438 VOID
439 NTAPI
440 PoSetSystemState(IN EXECUTION_STATE Flags)
441 {
442 UNIMPLEMENTED;
443 }
444
445 /*
446 * @unimplemented
447 */
448 VOID
449 NTAPI
450 PoStartNextPowerIrp(IN PIRP Irp)
451 {
452 UNIMPLEMENTED;
453 }
454
455 /*
456 * @unimplemented
457 */
458 VOID
459 NTAPI
460 PoUnregisterSystemState(IN PVOID StateHandle)
461 {
462 UNIMPLEMENTED;
463 }
464
465 /*
466 * @unimplemented
467 */
468 NTSTATUS
469 NTAPI
470 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem)
471 {
472 PAGED_CODE();
473
474 UNIMPLEMENTED;
475 return STATUS_NOT_IMPLEMENTED;
476 }
477
478 /*
479 * @unimplemented
480 */
481 NTSTATUS
482 NTAPI
483 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
484 IN SYSTEM_POWER_STATE MinSystemState,
485 IN ULONG Flags,
486 IN BOOLEAN Asynchronous)
487 {
488 UNIMPLEMENTED;
489 return STATUS_NOT_IMPLEMENTED;
490 }
491
492 /*
493 * @unimplemented
494 */
495 NTSTATUS
496 NTAPI
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)
502 {
503 NTSTATUS Status;
504
505 PAGED_CODE();
506
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);
512
513 switch (PowerInformationLevel)
514 {
515 case SystemBatteryState:
516 {
517 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
518
519 if (InputBuffer != NULL)
520 return STATUS_INVALID_PARAMETER;
521 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
522 return STATUS_BUFFER_TOO_SMALL;
523
524 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
525 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
526 BatteryState->EstimatedTime = MAXULONG;
527
528 Status = STATUS_SUCCESS;
529 break;
530 }
531 case SystemPowerCapabilities:
532 {
533 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
534
535 if (InputBuffer != NULL)
536 return STATUS_INVALID_PARAMETER;
537 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
538 return STATUS_BUFFER_TOO_SMALL;
539
540 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
541 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
542 //PowerCapabilities->SystemBatteriesPresent = 0;
543
544 Status = STATUS_SUCCESS;
545 break;
546 }
547
548 default:
549 Status = STATUS_NOT_IMPLEMENTED;
550 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
551 PowerInformationLevel);
552 break;
553 }
554
555 return Status;
556 }
557
558 NTSTATUS
559 NTAPI
560 NtGetDevicePowerState(IN HANDLE Device,
561 IN PDEVICE_POWER_STATE PowerState)
562 {
563 UNIMPLEMENTED;
564 return STATUS_NOT_IMPLEMENTED;
565 }
566
567 BOOLEAN
568 NTAPI
569 NtIsSystemResumeAutomatic(VOID)
570 {
571 UNIMPLEMENTED;
572 return FALSE;
573 }
574
575 NTSTATUS
576 NTAPI
577 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
578 {
579 UNIMPLEMENTED;
580 return STATUS_NOT_IMPLEMENTED;
581 }
582
583 NTSTATUS
584 NTAPI
585 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
586 OUT EXECUTION_STATE *PreviousFlags)
587 {
588 PKTHREAD Thread = KeGetCurrentThread();
589 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
590 EXECUTION_STATE PreviousState;
591 PAGED_CODE();
592
593 /* Validate flags */
594 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
595 {
596 /* Fail the request */
597 return STATUS_INVALID_PARAMETER;
598 }
599
600 /* Check for user parameters */
601 if (PreviousMode != KernelMode)
602 {
603 /* Protect the probes */
604 _SEH2_TRY
605 {
606 /* Check if the pointer is valid */
607 ProbeForWriteUlong(PreviousFlags);
608 }
609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
610 {
611 /* It isn't -- fail */
612 _SEH2_YIELD(return _SEH2_GetExceptionCode());
613 }
614 _SEH2_END;
615 }
616
617 /* Save the previous state, always masking in the continous flag */
618 PreviousState = Thread->PowerState | ES_CONTINUOUS;
619
620 /* Check if we need to update the power state */
621 if (esFlags & ES_CONTINUOUS) Thread->PowerState = esFlags;
622
623 /* Protect the write back to user mode */
624 _SEH2_TRY
625 {
626 /* Return the previous flags */
627 *PreviousFlags = PreviousState;
628 }
629 _SEH2_EXCEPT(ExSystemExceptionFilter())
630 {
631 /* Something's wrong, fail */
632 _SEH2_YIELD(return _SEH2_GetExceptionCode());
633 }
634 _SEH2_END;
635
636 /* All is good */
637 return STATUS_SUCCESS;
638 }