a0dd4fb3af9c64e879236524d7fb590ba5bc70f6
[reactos.git] / 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 _POWER_STATE_TRAVERSE_CONTEXT
19 {
20 SYSTEM_POWER_STATE SystemPowerState;
21 POWER_ACTION PowerAction;
22 PDEVICE_OBJECT PowerDevice;
23 } POWER_STATE_TRAVERSE_CONTEXT, *PPOWER_STATE_TRAVERSE_CONTEXT;
24
25 PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
26 BOOLEAN PopAcpiPresent = FALSE;
27 POP_POWER_ACTION PopAction;
28 WORK_QUEUE_ITEM PopShutdownWorkItem;
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_COMPLETE CompletionRoutine;
41 POWER_STATE PowerState;
42
43 Stack = IoGetCurrentIrpStackLocation(Irp);
44 CompletionRoutine = Context;
45
46 PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3;
47 CompletionRoutine(Stack->Parameters.Others.Argument1,
48 (UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2,
49 PowerState,
50 Stack->Parameters.Others.Argument4,
51 &Irp->IoStatus);
52
53 IoSkipCurrentIrpStackLocation(Irp);
54 IoFreeIrp(Irp);
55 ObDereferenceObject(DeviceObject);
56
57 return STATUS_MORE_PROCESSING_REQUIRED;
58 }
59
60 VOID
61 NTAPI
62 PopCleanupPowerState(IN PPOWER_STATE PowerState)
63 {
64 //UNIMPLEMENTED;
65 }
66
67 NTSTATUS
68 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
69 {
70 KEVENT Event;
71 IO_STATUS_BLOCK IoStatusBlock;
72 PIO_STACK_LOCATION IrpSp;
73 PIRP Irp;
74 NTSTATUS Status;
75
76 KeInitializeEvent(&Event,
77 NotificationEvent,
78 FALSE);
79
80 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
81 DeviceObject,
82 NULL,
83 0,
84 NULL,
85 &Event,
86 &IoStatusBlock);
87 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
88
89 IrpSp = IoGetNextIrpStackLocation(Irp);
90 IrpSp->MinorFunction = IRP_MN_QUERY_POWER;
91 IrpSp->Parameters.Power.Type = SystemPowerState;
92 IrpSp->Parameters.Power.State.SystemState = SystemState;
93 IrpSp->Parameters.Power.ShutdownType = PowerAction;
94
95 Status = PoCallDriver(DeviceObject, Irp);
96 if (Status == STATUS_PENDING)
97 {
98 KeWaitForSingleObject(&Event,
99 Executive,
100 KernelMode,
101 FALSE,
102 NULL);
103 Status = IoStatusBlock.Status;
104 }
105
106 return Status;
107 }
108
109 NTSTATUS
110 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
111 {
112 KEVENT Event;
113 IO_STATUS_BLOCK IoStatusBlock;
114 PIO_STACK_LOCATION IrpSp;
115 PIRP Irp;
116 NTSTATUS Status;
117
118 KeInitializeEvent(&Event,
119 NotificationEvent,
120 FALSE);
121
122 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
123 DeviceObject,
124 NULL,
125 0,
126 NULL,
127 &Event,
128 &IoStatusBlock);
129 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
130
131 IrpSp = IoGetNextIrpStackLocation(Irp);
132 IrpSp->MinorFunction = IRP_MN_SET_POWER;
133 IrpSp->Parameters.Power.Type = SystemPowerState;
134 IrpSp->Parameters.Power.State.SystemState = SystemState;
135 IrpSp->Parameters.Power.ShutdownType = PowerAction;
136
137 Status = PoCallDriver(DeviceObject, Irp);
138 if (Status == STATUS_PENDING)
139 {
140 KeWaitForSingleObject(&Event,
141 Executive,
142 KernelMode,
143 FALSE,
144 NULL);
145 Status = IoStatusBlock.Status;
146 }
147
148 return Status;
149 }
150
151 NTSTATUS
152 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
153 PVOID Context)
154 {
155 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
156 PDEVICE_OBJECT TopDeviceObject;
157 NTSTATUS Status;
158
159 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
160
161 if (DeviceNode == IopRootDeviceNode)
162 return STATUS_SUCCESS;
163
164 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
165 return STATUS_SUCCESS;
166
167 TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
168
169 Status = PopSendQuerySystemPowerState(TopDeviceObject,
170 PowerStateContext->SystemPowerState,
171 PowerStateContext->PowerAction);
172 if (!NT_SUCCESS(Status))
173 {
174 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
175 }
176 ObDereferenceObject(TopDeviceObject);
177
178 #if 0
179 return Status;
180 #else
181 return STATUS_SUCCESS;
182 #endif
183 }
184
185 NTSTATUS
186 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
187 PVOID Context)
188 {
189 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
190 PDEVICE_OBJECT TopDeviceObject;
191 NTSTATUS Status;
192
193 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
194
195 if (DeviceNode == IopRootDeviceNode)
196 return STATUS_SUCCESS;
197
198 if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
199 return STATUS_SUCCESS;
200
201 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
202 return STATUS_SUCCESS;
203
204 TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
205 if (TopDeviceObject == PowerStateContext->PowerDevice)
206 {
207 ObDereferenceObject(TopDeviceObject);
208 return STATUS_SUCCESS;
209 }
210
211 Status = PopSendSetSystemPowerState(TopDeviceObject,
212 PowerStateContext->SystemPowerState,
213 PowerStateContext->PowerAction);
214 if (!NT_SUCCESS(Status))
215 {
216 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
217 }
218
219 ObDereferenceObject(TopDeviceObject);
220
221 #if 0
222 return Status;
223 #else
224 return STATUS_SUCCESS;
225 #endif
226 }
227
228 NTSTATUS
229 NTAPI
230 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
231 {
232 PDEVICE_OBJECT DeviceObject;
233 PDEVICE_OBJECT Fdo;
234 NTSTATUS Status;
235 DEVICETREE_TRAVERSE_CONTEXT Context;
236 POWER_STATE_TRAVERSE_CONTEXT PowerContext;
237
238 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
239 if (!NT_SUCCESS(Status))
240 {
241 DPRINT1("No system power driver available\n");
242 Fdo = NULL;
243 }
244 else
245 {
246 Fdo = IoGetAttachedDeviceReference(DeviceObject);
247 if (Fdo == DeviceObject)
248 {
249 DPRINT("An FDO was not attached\n");
250 return STATUS_UNSUCCESSFUL;
251 }
252 }
253
254 /* Set up context */
255 PowerContext.PowerAction = PowerAction;
256 PowerContext.SystemPowerState = PowerState;
257 PowerContext.PowerDevice = Fdo;
258
259 /* Query for system power change */
260 IopInitDeviceTreeTraverseContext(&Context,
261 IopRootDeviceNode,
262 PopQuerySystemPowerStateTraverse,
263 &PowerContext);
264
265 Status = IopTraverseDeviceTree(&Context);
266 if (!NT_SUCCESS(Status))
267 {
268 DPRINT1("Query system power state failed; changing state anyway\n");
269 }
270
271 /* Set system power change */
272 IopInitDeviceTreeTraverseContext(&Context,
273 IopRootDeviceNode,
274 PopSetSystemPowerStateTraverse,
275 &PowerContext);
276
277 IopTraverseDeviceTree(&Context);
278
279 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
280
281 if (Fdo != NULL)
282 {
283 if (PowerAction != PowerActionShutdownReset)
284 PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
285
286 ObDereferenceObject(Fdo);
287 }
288
289 return Status;
290 }
291
292 INIT_FUNCTION
293 BOOLEAN
294 NTAPI
295 PoInitSystem(IN ULONG BootPhase)
296 {
297 PVOID NotificationEntry;
298 PCHAR CommandLine;
299 BOOLEAN ForceAcpiDisable = FALSE;
300
301 /* Check if this is phase 1 init */
302 if (BootPhase == 1)
303 {
304 /* Register power button notification */
305 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
306 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
307 (PVOID)&GUID_DEVICE_SYS_BUTTON,
308 IopRootDeviceNode->
309 PhysicalDeviceObject->DriverObject,
310 PopAddRemoveSysCapsCallback,
311 NULL,
312 &NotificationEntry);
313
314 /* Register lid notification */
315 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
316 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
317 (PVOID)&GUID_DEVICE_LID,
318 IopRootDeviceNode->
319 PhysicalDeviceObject->DriverObject,
320 PopAddRemoveSysCapsCallback,
321 NULL,
322 &NotificationEntry);
323 return TRUE;
324 }
325
326 /* Get the Command Line */
327 CommandLine = KeLoaderBlock->LoadOptions;
328
329 /* Upcase it */
330 _strupr(CommandLine);
331
332 /* Check for ACPI disable */
333 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
334
335 if (ForceAcpiDisable)
336 {
337 /* Set the ACPI State to False if it's been forced that way */
338 PopAcpiPresent = FALSE;
339 }
340 else
341 {
342 /* Otherwise check if the LoaderBlock has a ACPI Table */
343 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
344 }
345
346
347 /* Initialize volume support */
348 InitializeListHead(&PopVolumeDevices);
349 KeInitializeGuardedMutex(&PopVolumeLock);
350
351 /* Initialize support for dope */
352 KeInitializeSpinLock(&PopDopeGlobalLock);
353
354 /* Initialize support for shutdown waits and work-items */
355 PopInitShutdownList();
356
357 return TRUE;
358 }
359
360 VOID
361 NTAPI
362 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
363 {
364 DPRINT1("PerfIdle function: %p\n", PowerState);
365 }
366
367 VOID
368 NTAPI
369 PopPerfIdleDpc(IN PKDPC Dpc,
370 IN PVOID DeferredContext,
371 IN PVOID SystemArgument1,
372 IN PVOID SystemArgument2)
373 {
374 /* Call the Perf Idle function */
375 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
376 }
377
378 VOID
379 FASTCALL
380 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
381 {
382 /* FIXME: Extremly naive implementation */
383 HalProcessorIdle();
384 }
385
386 INIT_FUNCTION
387 VOID
388 NTAPI
389 PoInitializePrcb(IN PKPRCB Prcb)
390 {
391 /* Initialize the Power State */
392 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
393 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
394 Prcb->PowerState.CurrentThrottle = 100;
395 Prcb->PowerState.CurrentThrottleIndex = 0;
396 Prcb->PowerState.IdleFunction = PopIdle0;
397
398 /* Initialize the Perf DPC and Timer */
399 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
400 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
401 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
402 }
403
404 /* PUBLIC FUNCTIONS **********************************************************/
405
406 /*
407 * @unimplemented
408 */
409 NTSTATUS
410 NTAPI
411 PoCancelDeviceNotify(IN PVOID NotifyBlock)
412 {
413 UNIMPLEMENTED;
414 return STATUS_NOT_IMPLEMENTED;
415 }
416
417 /*
418 * @unimplemented
419 */
420 NTSTATUS
421 NTAPI
422 PoRegisterDeviceNotify(OUT PVOID Unknown0,
423 IN ULONG Unknown1,
424 IN ULONG Unknown2,
425 IN ULONG Unknown3,
426 IN PVOID Unknown4,
427 IN PVOID Unknown5)
428 {
429 UNIMPLEMENTED;
430 return STATUS_NOT_IMPLEMENTED;
431 }
432
433 /*
434 * @unimplemented
435 */
436 VOID
437 NTAPI
438 PoShutdownBugCheck(IN BOOLEAN LogError,
439 IN ULONG BugCheckCode,
440 IN ULONG_PTR BugCheckParameter1,
441 IN ULONG_PTR BugCheckParameter2,
442 IN ULONG_PTR BugCheckParameter3,
443 IN ULONG_PTR BugCheckParameter4)
444 {
445 DPRINT1("PoShutdownBugCheck called\n");
446
447 /* FIXME: Log error if requested */
448 /* FIXME: Initiate a shutdown */
449
450 /* Bugcheck the system */
451 KeBugCheckEx(BugCheckCode,
452 BugCheckParameter1,
453 BugCheckParameter2,
454 BugCheckParameter3,
455 BugCheckParameter4);
456 }
457
458 /*
459 * @unimplemented
460 */
461 VOID
462 NTAPI
463 PoSetHiberRange(IN PVOID HiberContext,
464 IN ULONG Flags,
465 IN OUT PVOID StartPage,
466 IN ULONG Length,
467 IN ULONG PageTag)
468 {
469 UNIMPLEMENTED;
470 return;
471 }
472
473 /*
474 * @implemented
475 */
476 NTSTATUS
477 NTAPI
478 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
479 IN OUT PIRP Irp)
480 {
481 NTSTATUS Status;
482
483 /* Forward to Io -- FIXME! */
484 Status = IoCallDriver(DeviceObject, Irp);
485
486 /* Return status */
487 return Status;
488 }
489
490 /*
491 * @unimplemented
492 */
493 PULONG
494 NTAPI
495 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
496 IN ULONG ConservationIdleTime,
497 IN ULONG PerformanceIdleTime,
498 IN DEVICE_POWER_STATE State)
499 {
500 UNIMPLEMENTED;
501 return NULL;
502 }
503
504 /*
505 * @unimplemented
506 */
507 PVOID
508 NTAPI
509 PoRegisterSystemState(IN PVOID StateHandle,
510 IN EXECUTION_STATE Flags)
511 {
512 UNIMPLEMENTED;
513 return NULL;
514 }
515
516 /*
517 * @implemented
518 */
519 NTSTATUS
520 NTAPI
521 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
522 IN UCHAR MinorFunction,
523 IN POWER_STATE PowerState,
524 IN PREQUEST_POWER_COMPLETE CompletionFunction,
525 IN PVOID Context,
526 OUT PIRP *pIrp OPTIONAL)
527 {
528 PDEVICE_OBJECT TopDeviceObject;
529 PIO_STACK_LOCATION Stack;
530 PIRP Irp;
531
532 if (MinorFunction != IRP_MN_QUERY_POWER
533 && MinorFunction != IRP_MN_SET_POWER
534 && MinorFunction != IRP_MN_WAIT_WAKE)
535 return STATUS_INVALID_PARAMETER_2;
536
537 /* Always call the top of the device stack */
538 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
539
540 Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
541 if (!Irp)
542 {
543 ObDereferenceObject(TopDeviceObject);
544 return STATUS_INSUFFICIENT_RESOURCES;
545 }
546
547 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
548 Irp->IoStatus.Information = 0;
549
550 IoSetNextIrpStackLocation(Irp);
551
552 Stack = IoGetNextIrpStackLocation(Irp);
553 Stack->Parameters.Others.Argument1 = DeviceObject;
554 Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
555 Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
556 Stack->Parameters.Others.Argument4 = Context;
557 Stack->DeviceObject = TopDeviceObject;
558 IoSetNextIrpStackLocation(Irp);
559
560 Stack = IoGetNextIrpStackLocation(Irp);
561 Stack->MajorFunction = IRP_MJ_POWER;
562 Stack->MinorFunction = MinorFunction;
563 if (MinorFunction == IRP_MN_WAIT_WAKE)
564 {
565 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
566 }
567 else
568 {
569 Stack->Parameters.Power.Type = DevicePowerState;
570 Stack->Parameters.Power.State = PowerState;
571 }
572
573 if (pIrp != NULL)
574 *pIrp = Irp;
575
576 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
577 PoCallDriver(TopDeviceObject, Irp);
578
579 /* Always return STATUS_PENDING. The completion routine
580 * will call CompletionFunction and complete the Irp.
581 */
582 return STATUS_PENDING;
583 }
584
585 /*
586 * @unimplemented
587 */
588 POWER_STATE
589 NTAPI
590 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
591 IN POWER_STATE_TYPE Type,
592 IN POWER_STATE State)
593 {
594 POWER_STATE ps;
595
596 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
597
598 ps.SystemState = PowerSystemWorking; // Fully on
599 ps.DeviceState = PowerDeviceD0; // Fully on
600
601 return ps;
602 }
603
604 /*
605 * @unimplemented
606 */
607 VOID
608 NTAPI
609 PoSetSystemState(IN EXECUTION_STATE Flags)
610 {
611 UNIMPLEMENTED;
612 }
613
614 /*
615 * @unimplemented
616 */
617 VOID
618 NTAPI
619 PoStartNextPowerIrp(IN PIRP Irp)
620 {
621 UNIMPLEMENTED;
622 }
623
624 /*
625 * @unimplemented
626 */
627 VOID
628 NTAPI
629 PoUnregisterSystemState(IN PVOID StateHandle)
630 {
631 UNIMPLEMENTED;
632 }
633
634 /*
635 * @unimplemented
636 */
637 NTSTATUS
638 NTAPI
639 NtInitiatePowerAction(IN POWER_ACTION SystemAction,
640 IN SYSTEM_POWER_STATE MinSystemState,
641 IN ULONG Flags,
642 IN BOOLEAN Asynchronous)
643 {
644 UNIMPLEMENTED;
645 return STATUS_NOT_IMPLEMENTED;
646 }
647
648 /*
649 * @unimplemented
650 */
651 NTSTATUS
652 NTAPI
653 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
654 IN PVOID InputBuffer OPTIONAL,
655 IN ULONG InputBufferLength,
656 OUT PVOID OutputBuffer OPTIONAL,
657 IN ULONG OutputBufferLength)
658 {
659 NTSTATUS Status;
660 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
661
662 PAGED_CODE();
663
664 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
665 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
666 PowerInformationLevel,
667 InputBuffer, InputBufferLength,
668 OutputBuffer, OutputBufferLength);
669
670 if (PreviousMode != KernelMode)
671 {
672 _SEH2_TRY
673 {
674 ProbeForRead(InputBuffer, InputBufferLength, 1);
675 ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));
676 }
677 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
678 {
679 _SEH2_YIELD(return _SEH2_GetExceptionCode());
680 }
681 _SEH2_END;
682 }
683
684 switch (PowerInformationLevel)
685 {
686 case SystemBatteryState:
687 {
688 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
689
690 if (InputBuffer != NULL)
691 return STATUS_INVALID_PARAMETER;
692 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
693 return STATUS_BUFFER_TOO_SMALL;
694
695 _SEH2_TRY
696 {
697 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
698 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
699 BatteryState->EstimatedTime = MAXULONG;
700
701 Status = STATUS_SUCCESS;
702 }
703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
704 {
705 Status = _SEH2_GetExceptionCode();
706 }
707 _SEH2_END;
708
709 break;
710 }
711
712 case SystemPowerCapabilities:
713 {
714 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
715
716 if (InputBuffer != NULL)
717 return STATUS_INVALID_PARAMETER;
718 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
719 return STATUS_BUFFER_TOO_SMALL;
720
721 _SEH2_TRY
722 {
723 /* Just zero the struct (and thus set PowerCapabilities->SystemBatteriesPresent = FALSE) */
724 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
725 //PowerCapabilities->SystemBatteriesPresent = 0;
726
727 Status = STATUS_SUCCESS;
728 }
729 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
730 {
731 Status = _SEH2_GetExceptionCode();
732 }
733 _SEH2_END;
734
735 break;
736 }
737
738 case ProcessorInformation:
739 {
740 PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer;
741
742 if (InputBuffer != NULL)
743 return STATUS_INVALID_PARAMETER;
744 if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION))
745 return STATUS_BUFFER_TOO_SMALL;
746
747 _SEH2_TRY
748 {
749 PowerInformation->Number = 0;
750 PowerInformation->MaxMhz = 1000;
751 PowerInformation->CurrentMhz = 1000;
752 PowerInformation->MhzLimit = 1000;
753 PowerInformation->MaxIdleState = 0;
754 PowerInformation->CurrentIdleState = 0;
755
756 Status = STATUS_SUCCESS;
757 }
758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
759 {
760 Status = _SEH2_GetExceptionCode();
761 }
762 _SEH2_END;
763
764 break;
765 }
766
767 default:
768 Status = STATUS_NOT_IMPLEMENTED;
769 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
770 PowerInformationLevel);
771 break;
772 }
773
774 return Status;
775 }
776
777 NTSTATUS
778 NTAPI
779 NtGetDevicePowerState(IN HANDLE Device,
780 IN PDEVICE_POWER_STATE PowerState)
781 {
782 UNIMPLEMENTED;
783 return STATUS_NOT_IMPLEMENTED;
784 }
785
786 BOOLEAN
787 NTAPI
788 NtIsSystemResumeAutomatic(VOID)
789 {
790 UNIMPLEMENTED;
791 return FALSE;
792 }
793
794 NTSTATUS
795 NTAPI
796 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
797 {
798 UNIMPLEMENTED;
799 return STATUS_NOT_IMPLEMENTED;
800 }
801
802 NTSTATUS
803 NTAPI
804 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
805 OUT EXECUTION_STATE *PreviousFlags)
806 {
807 PKTHREAD Thread = KeGetCurrentThread();
808 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
809 EXECUTION_STATE PreviousState;
810 PAGED_CODE();
811
812 /* Validate flags */
813 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
814 {
815 /* Fail the request */
816 return STATUS_INVALID_PARAMETER;
817 }
818
819 /* Check for user parameters */
820 if (PreviousMode != KernelMode)
821 {
822 /* Protect the probes */
823 _SEH2_TRY
824 {
825 /* Check if the pointer is valid */
826 ProbeForWriteUlong(PreviousFlags);
827 }
828 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
829 {
830 /* It isn't -- fail */
831 _SEH2_YIELD(return _SEH2_GetExceptionCode());
832 }
833 _SEH2_END;
834 }
835
836 /* Save the previous state, always masking in the continous flag */
837 PreviousState = Thread->PowerState | ES_CONTINUOUS;
838
839 /* Check if we need to update the power state */
840 if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
841
842 /* Protect the write back to user mode */
843 _SEH2_TRY
844 {
845 /* Return the previous flags */
846 *PreviousFlags = PreviousState;
847 }
848 _SEH2_EXCEPT(ExSystemExceptionFilter())
849 {
850 /* Something's wrong, fail */
851 _SEH2_YIELD(return _SEH2_GetExceptionCode());
852 }
853 _SEH2_END;
854
855 /* All is good */
856 return STATUS_SUCCESS;
857 }
858
859 NTSTATUS
860 NTAPI
861 NtSetSystemPowerState(IN POWER_ACTION SystemAction,
862 IN SYSTEM_POWER_STATE MinSystemState,
863 IN ULONG Flags)
864 {
865 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
866 POP_POWER_ACTION Action = {0};
867 NTSTATUS Status;
868 ULONG Dummy;
869
870 /* Check for invalid parameter combinations */
871 if ((MinSystemState >= PowerSystemMaximum) ||
872 (MinSystemState <= PowerSystemUnspecified) ||
873 (SystemAction > PowerActionWarmEject) ||
874 (SystemAction < PowerActionReserved) ||
875 (Flags & ~(POWER_ACTION_QUERY_ALLOWED |
876 POWER_ACTION_UI_ALLOWED |
877 POWER_ACTION_OVERRIDE_APPS |
878 POWER_ACTION_LIGHTEST_FIRST |
879 POWER_ACTION_LOCK_CONSOLE |
880 POWER_ACTION_DISABLE_WAKES |
881 POWER_ACTION_CRITICAL)))
882 {
883 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
884 DPRINT1(" SystemAction: 0x%x\n", SystemAction);
885 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
886 DPRINT1(" Flags: 0x%x\n", Flags);
887 return STATUS_INVALID_PARAMETER;
888 }
889
890 /* Check for user caller */
891 if (PreviousMode != KernelMode)
892 {
893 /* Check for shutdown permission */
894 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
895 {
896 /* Not granted */
897 DPRINT1("ERROR: Privilege not held for shutdown\n");
898 return STATUS_PRIVILEGE_NOT_HELD;
899 }
900
901 /* Do it as a kernel-mode caller for consistency with system state */
902 return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags);
903 }
904
905 /* Read policy settings (partial shutdown vs. full shutdown) */
906 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
907
908 /* Disable lazy flushing of registry */
909 DPRINT("Stopping lazy flush\n");
910 CmSetLazyFlushState(FALSE);
911
912 /* Setup the power action */
913 Action.Action = SystemAction;
914 Action.Flags = Flags;
915
916 /* Notify callbacks */
917 DPRINT("Notifying callbacks\n");
918 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
919
920 /* Swap in any worker thread stacks */
921 DPRINT("Swapping worker threads\n");
922 ExSwapinWorkerThreads(FALSE);
923
924 /* Make our action global */
925 PopAction = Action;
926
927 /* Start power loop */
928 Status = STATUS_CANCELLED;
929 while (TRUE)
930 {
931 /* Break out if there's nothing to do */
932 if (Action.Action == PowerActionNone) break;
933
934 /* Check for first-pass or restart */
935 if (Status == STATUS_CANCELLED)
936 {
937 /* Check for shutdown action */
938 if ((PopAction.Action == PowerActionShutdown) ||
939 (PopAction.Action == PowerActionShutdownReset) ||
940 (PopAction.Action == PowerActionShutdownOff))
941 {
942 /* Set the action */
943 PopAction.Shutdown = TRUE;
944 }
945
946 /* Now we are good to go */
947 Status = STATUS_SUCCESS;
948 }
949
950 /* Check if we're still in an invalid status */
951 if (!NT_SUCCESS(Status)) break;
952
953 #ifndef NEWCC
954 /* Flush dirty cache pages */
955 /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */
956 CcRosFlushDirtyPages(-1, &Dummy, FALSE, FALSE); //HACK: We really should wait here!
957 #else
958 Dummy = 0;
959 #endif
960
961 /* Flush all volumes and the registry */
962 DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy);
963 PopFlushVolumes(PopAction.Shutdown);
964
965 /* Set IRP for drivers */
966 PopAction.IrpMinor = IRP_MN_SET_POWER;
967 if (PopAction.Shutdown)
968 {
969 DPRINT("Queueing shutdown thread\n");
970 /* Check if we are running in the system context */
971 if (PsGetCurrentProcess() != PsInitialSystemProcess)
972 {
973 /* We're not, so use a worker thread for shutdown */
974 ExInitializeWorkItem(&PopShutdownWorkItem,
975 &PopGracefulShutdown,
976 NULL);
977
978 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
979
980 /* Spend us -- when we wake up, the system is good to go down */
981 KeSuspendThread(KeGetCurrentThread());
982 Status = STATUS_SYSTEM_SHUTDOWN;
983 goto Exit;
984
985 }
986 else
987 {
988 /* Do the shutdown inline */
989 PopGracefulShutdown(NULL);
990 }
991 }
992
993 /* You should not have made it this far */
994 // ASSERTMSG("System is still up and running?!\n", FALSE);
995 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action);
996 break;
997 }
998
999 Exit:
1000 /* We're done, return */
1001 return Status;
1002 }