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