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