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