Sync with trunk rev.61910 to get latest improvements and bugfixes.
[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
348 /* Initialize support for shutdown waits and work-items */
349 PopInitShutdownList();
350
351 return TRUE;
352 }
353
354 VOID
355 NTAPI
356 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
357 {
358 DPRINT1("PerfIdle function: %p\n", PowerState);
359 }
360
361 VOID
362 NTAPI
363 PopPerfIdleDpc(IN PKDPC Dpc,
364 IN PVOID DeferredContext,
365 IN PVOID SystemArgument1,
366 IN PVOID SystemArgument2)
367 {
368 /* Call the Perf Idle function */
369 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
370 }
371
372 VOID
373 FASTCALL
374 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
375 {
376 /* FIXME: Extremly naive implementation */
377 HalProcessorIdle();
378 }
379
380 VOID
381 NTAPI
382 INIT_FUNCTION
383 PoInitializePrcb(IN PKPRCB Prcb)
384 {
385 /* Initialize the Power State */
386 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
387 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
388 Prcb->PowerState.CurrentThrottle = 100;
389 Prcb->PowerState.CurrentThrottleIndex = 0;
390 Prcb->PowerState.IdleFunction = PopIdle0;
391
392 /* Initialize the Perf DPC and Timer */
393 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
394 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
395 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
396 }
397
398 /* PUBLIC FUNCTIONS **********************************************************/
399
400 /*
401 * @unimplemented
402 */
403 NTSTATUS
404 NTAPI
405 PoCancelDeviceNotify(IN PVOID NotifyBlock)
406 {
407 UNIMPLEMENTED;
408 return STATUS_NOT_IMPLEMENTED;
409 }
410
411 /*
412 * @unimplemented
413 */
414 NTSTATUS
415 NTAPI
416 PoRegisterDeviceNotify(OUT PVOID Unknown0,
417 IN ULONG Unknown1,
418 IN ULONG Unknown2,
419 IN ULONG Unknown3,
420 IN PVOID Unknown4,
421 IN PVOID Unknown5)
422 {
423 UNIMPLEMENTED;
424 return STATUS_NOT_IMPLEMENTED;
425 }
426
427 /*
428 * @unimplemented
429 */
430 VOID
431 NTAPI
432 PoShutdownBugCheck(IN BOOLEAN LogError,
433 IN ULONG BugCheckCode,
434 IN ULONG_PTR BugCheckParameter1,
435 IN ULONG_PTR BugCheckParameter2,
436 IN ULONG_PTR BugCheckParameter3,
437 IN ULONG_PTR BugCheckParameter4)
438 {
439 DPRINT1("PoShutdownBugCheck called\n");
440
441 /* FIXME: Log error if requested */
442 /* FIXME: Initiate a shutdown */
443
444 /* Bugcheck the system */
445 KeBugCheckEx(BugCheckCode,
446 BugCheckParameter1,
447 BugCheckParameter2,
448 BugCheckParameter3,
449 BugCheckParameter4);
450 }
451
452 /*
453 * @unimplemented
454 */
455 VOID
456 NTAPI
457 PoSetHiberRange(IN PVOID HiberContext,
458 IN ULONG Flags,
459 IN OUT PVOID StartPage,
460 IN ULONG Length,
461 IN ULONG PageTag)
462 {
463 UNIMPLEMENTED;
464 return;
465 }
466
467 /*
468 * @implemented
469 */
470 NTSTATUS
471 NTAPI
472 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
473 IN OUT PIRP Irp)
474 {
475 NTSTATUS Status;
476
477 /* Forward to Io -- FIXME! */
478 Status = IoCallDriver(DeviceObject, Irp);
479
480 /* Return status */
481 return Status;
482 }
483
484 /*
485 * @unimplemented
486 */
487 PULONG
488 NTAPI
489 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
490 IN ULONG ConservationIdleTime,
491 IN ULONG PerformanceIdleTime,
492 IN DEVICE_POWER_STATE State)
493 {
494 UNIMPLEMENTED;
495 return NULL;
496 }
497
498 /*
499 * @unimplemented
500 */
501 PVOID
502 NTAPI
503 PoRegisterSystemState(IN PVOID StateHandle,
504 IN EXECUTION_STATE Flags)
505 {
506 UNIMPLEMENTED;
507 return NULL;
508 }
509
510 /*
511 * @implemented
512 */
513 NTSTATUS
514 NTAPI
515 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
516 IN UCHAR MinorFunction,
517 IN POWER_STATE PowerState,
518 IN PREQUEST_POWER_COMPLETE CompletionFunction,
519 IN PVOID Context,
520 OUT PIRP *pIrp OPTIONAL)
521 {
522 PDEVICE_OBJECT TopDeviceObject;
523 PIO_STACK_LOCATION Stack;
524 PIRP Irp;
525 PREQUEST_POWER_ITEM RequestPowerItem;
526
527 if (MinorFunction != IRP_MN_QUERY_POWER
528 && MinorFunction != IRP_MN_SET_POWER
529 && MinorFunction != IRP_MN_WAIT_WAKE)
530 return STATUS_INVALID_PARAMETER_2;
531
532 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
533 if (!RequestPowerItem)
534 return STATUS_INSUFFICIENT_RESOURCES;
535
536 /* Always call the top of the device stack */
537 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
538
539 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER,
540 TopDeviceObject,
541 NULL,
542 0,
543 NULL,
544 NULL);
545 if (!Irp)
546 {
547 ObDereferenceObject(TopDeviceObject);
548 ExFreePool(RequestPowerItem);
549 return STATUS_INSUFFICIENT_RESOURCES;
550 }
551
552 /* POWER IRPs are always initialized with a status code of
553 STATUS_NOT_IMPLEMENTED */
554 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
555 Irp->IoStatus.Information = 0;
556
557 Stack = IoGetNextIrpStackLocation(Irp);
558 Stack->MinorFunction = MinorFunction;
559 if (MinorFunction == IRP_MN_WAIT_WAKE)
560 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
561 else
562 {
563 Stack->Parameters.Power.Type = DevicePowerState;
564 Stack->Parameters.Power.State = PowerState;
565 }
566
567 RequestPowerItem->CompletionRoutine = CompletionFunction;
568 RequestPowerItem->PowerState = PowerState;
569 RequestPowerItem->Context = Context;
570 RequestPowerItem->TopDeviceObject = TopDeviceObject;
571
572 if (pIrp != NULL)
573 *pIrp = Irp;
574
575 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
576 PoCallDriver(TopDeviceObject, Irp);
577
578 /* Always return STATUS_PENDING. The completion routine
579 * will call CompletionFunction and complete the Irp.
580 */
581 return STATUS_PENDING;
582 }
583
584 /*
585 * @unimplemented
586 */
587 POWER_STATE
588 NTAPI
589 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
590 IN POWER_STATE_TYPE Type,
591 IN POWER_STATE State)
592 {
593 POWER_STATE ps;
594
595 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
596
597 ps.SystemState = PowerSystemWorking; // Fully on
598 ps.DeviceState = PowerDeviceD0; // Fully on
599
600 return ps;
601 }
602
603 /*
604 * @unimplemented
605 */
606 VOID
607 NTAPI
608 PoSetSystemState(IN EXECUTION_STATE Flags)
609 {
610 UNIMPLEMENTED;
611 }
612
613 /*
614 * @unimplemented
615 */
616 VOID
617 NTAPI
618 PoStartNextPowerIrp(IN PIRP Irp)
619 {
620 UNIMPLEMENTED;
621 }
622
623 /*
624 * @unimplemented
625 */
626 VOID
627 NTAPI
628 PoUnregisterSystemState(IN PVOID StateHandle)
629 {
630 UNIMPLEMENTED;
631 }
632
633 /*
634 * @unimplemented
635 */
636 NTSTATUS
637 NTAPI
638 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
639 IN SYSTEM_POWER_STATE MinSystemState,
640 IN ULONG Flags,
641 IN BOOLEAN Asynchronous)
642 {
643 UNIMPLEMENTED;
644 return STATUS_NOT_IMPLEMENTED;
645 }
646
647 /*
648 * @unimplemented
649 */
650 NTSTATUS
651 NTAPI
652 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
653 IN PVOID InputBuffer OPTIONAL,
654 IN ULONG InputBufferLength,
655 OUT PVOID OutputBuffer OPTIONAL,
656 IN ULONG OutputBufferLength)
657 {
658 NTSTATUS Status;
659
660 PAGED_CODE();
661
662 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
663 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
664 PowerInformationLevel,
665 InputBuffer, InputBufferLength,
666 OutputBuffer, OutputBufferLength);
667
668 switch (PowerInformationLevel)
669 {
670 case SystemBatteryState:
671 {
672 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
673
674 if (InputBuffer != NULL)
675 return STATUS_INVALID_PARAMETER;
676 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
677 return STATUS_BUFFER_TOO_SMALL;
678
679 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
680 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
681 BatteryState->EstimatedTime = MAXULONG;
682
683 Status = STATUS_SUCCESS;
684 break;
685 }
686 case SystemPowerCapabilities:
687 {
688 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
689
690 if (InputBuffer != NULL)
691 return STATUS_INVALID_PARAMETER;
692 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
693 return STATUS_BUFFER_TOO_SMALL;
694
695 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
696 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
697 //PowerCapabilities->SystemBatteriesPresent = 0;
698
699 Status = STATUS_SUCCESS;
700 break;
701 }
702
703 default:
704 Status = STATUS_NOT_IMPLEMENTED;
705 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
706 PowerInformationLevel);
707 break;
708 }
709
710 return Status;
711 }
712
713 NTSTATUS
714 NTAPI
715 NtGetDevicePowerState(IN HANDLE Device,
716 IN PDEVICE_POWER_STATE PowerState)
717 {
718 UNIMPLEMENTED;
719 return STATUS_NOT_IMPLEMENTED;
720 }
721
722 BOOLEAN
723 NTAPI
724 NtIsSystemResumeAutomatic(VOID)
725 {
726 UNIMPLEMENTED;
727 return FALSE;
728 }
729
730 NTSTATUS
731 NTAPI
732 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
733 {
734 UNIMPLEMENTED;
735 return STATUS_NOT_IMPLEMENTED;
736 }
737
738 NTSTATUS
739 NTAPI
740 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
741 OUT EXECUTION_STATE *PreviousFlags)
742 {
743 PKTHREAD Thread = KeGetCurrentThread();
744 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
745 EXECUTION_STATE PreviousState;
746 PAGED_CODE();
747
748 /* Validate flags */
749 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
750 {
751 /* Fail the request */
752 return STATUS_INVALID_PARAMETER;
753 }
754
755 /* Check for user parameters */
756 if (PreviousMode != KernelMode)
757 {
758 /* Protect the probes */
759 _SEH2_TRY
760 {
761 /* Check if the pointer is valid */
762 ProbeForWriteUlong(PreviousFlags);
763 }
764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
765 {
766 /* It isn't -- fail */
767 _SEH2_YIELD(return _SEH2_GetExceptionCode());
768 }
769 _SEH2_END;
770 }
771
772 /* Save the previous state, always masking in the continous flag */
773 PreviousState = Thread->PowerState | ES_CONTINUOUS;
774
775 /* Check if we need to update the power state */
776 if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
777
778 /* Protect the write back to user mode */
779 _SEH2_TRY
780 {
781 /* Return the previous flags */
782 *PreviousFlags = PreviousState;
783 }
784 _SEH2_EXCEPT(ExSystemExceptionFilter())
785 {
786 /* Something's wrong, fail */
787 _SEH2_YIELD(return _SEH2_GetExceptionCode());
788 }
789 _SEH2_END;
790
791 /* All is good */
792 return STATUS_SUCCESS;
793 }
794
795 NTSTATUS
796 NTAPI
797 NtSetSystemPowerState(IN POWER_ACTION SystemAction,
798 IN SYSTEM_POWER_STATE MinSystemState,
799 IN ULONG Flags)
800 {
801 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
802 POP_POWER_ACTION Action = {0};
803 NTSTATUS Status;
804 ULONG Dummy;
805
806 /* Check for invalid parameter combinations */
807 if ((MinSystemState >= PowerSystemMaximum) ||
808 (MinSystemState <= PowerSystemUnspecified) ||
809 (SystemAction > PowerActionWarmEject) ||
810 (SystemAction < PowerActionReserved) ||
811 (Flags & ~(POWER_ACTION_QUERY_ALLOWED |
812 POWER_ACTION_UI_ALLOWED |
813 POWER_ACTION_OVERRIDE_APPS |
814 POWER_ACTION_LIGHTEST_FIRST |
815 POWER_ACTION_LOCK_CONSOLE |
816 POWER_ACTION_DISABLE_WAKES |
817 POWER_ACTION_CRITICAL)))
818 {
819 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
820 DPRINT1(" SystemAction: 0x%x\n", SystemAction);
821 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
822 DPRINT1(" Flags: 0x%x\n", Flags);
823 return STATUS_INVALID_PARAMETER;
824 }
825
826 /* Check for user caller */
827 if (PreviousMode != KernelMode)
828 {
829 /* Check for shutdown permission */
830 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
831 {
832 /* Not granted */
833 DPRINT1("ERROR: Privilege not held for shutdown\n");
834 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
835 }
836
837 /* Do it as a kernel-mode caller for consistency with system state */
838 return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags);
839 }
840
841 /* Read policy settings (partial shutdown vs. full shutdown) */
842 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
843
844 /* Disable lazy flushing of registry */
845 DPRINT1("Stopping lazy flush\n");
846 CmSetLazyFlushState(FALSE);
847
848 /* Setup the power action */
849 Action.Action = SystemAction;
850 Action.Flags = Flags;
851
852 /* Notify callbacks */
853 DPRINT1("Notifying callbacks\n");
854 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
855
856 /* Swap in any worker thread stacks */
857 DPRINT1("Swapping worker threads\n");
858 ExSwapinWorkerThreads(FALSE);
859
860 /* Make our action global */
861 PopAction = Action;
862
863 /* Start power loop */
864 Status = STATUS_CANCELLED;
865 while (TRUE)
866 {
867 /* Break out if there's nothing to do */
868 if (Action.Action == PowerActionNone) break;
869
870 /* Check for first-pass or restart */
871 if (Status == STATUS_CANCELLED)
872 {
873 /* Check for shutdown action */
874 if ((PopAction.Action == PowerActionShutdown) ||
875 (PopAction.Action == PowerActionShutdownReset) ||
876 (PopAction.Action == PowerActionShutdownOff))
877 {
878 /* Set the action */
879 PopAction.Shutdown = TRUE;
880 }
881
882 /* Now we are good to go */
883 Status = STATUS_SUCCESS;
884 }
885
886 /* Check if we're still in an invalid status */
887 if (!NT_SUCCESS(Status)) break;
888
889 #ifndef NEWCC
890 /* Flush dirty cache pages */
891 CcRosFlushDirtyPages(-1, &Dummy, FALSE); //HACK: We really should wait here!
892 #else
893 Dummy = 0;
894 #endif
895
896 /* Flush all volumes and the registry */
897 DPRINT1("Flushing volumes, cache flushed %lu pages\n", Dummy);
898 PopFlushVolumes(PopAction.Shutdown);
899
900 /* Set IRP for drivers */
901 PopAction.IrpMinor = IRP_MN_SET_POWER;
902 if (PopAction.Shutdown)
903 {
904 DPRINT1("Queueing shutdown thread\n");
905 /* Check if we are running in the system context */
906 if (PsGetCurrentProcess() != PsInitialSystemProcess)
907 {
908 /* We're not, so use a worker thread for shutdown */
909 ExInitializeWorkItem(&PopShutdownWorkItem,
910 &PopGracefulShutdown,
911 NULL);
912
913 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
914
915 /* Spend us -- when we wake up, the system is good to go down */
916 KeSuspendThread(KeGetCurrentThread());
917 Status = STATUS_SYSTEM_SHUTDOWN;
918 goto Exit;
919
920 }
921 else
922 {
923 /* Do the shutdown inline */
924 PopGracefulShutdown(NULL);
925 }
926 }
927
928 /* You should not have made it this far */
929 ASSERT(FALSE && "System is still up and running?!");
930 break;
931 }
932
933 Exit:
934 /* We're done, return */
935 return Status;
936 }