684a25ef9f48531a167e9772f27c9389c4089ad0
[reactos.git] / reactos / ntoskrnl / po / power.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/po/power.c
5 * PURPOSE: Power Manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 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 NTSTATUS Status;
157
158 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
159
160 if (DeviceNode == IopRootDeviceNode)
161 return STATUS_SUCCESS;
162
163 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
164 return STATUS_SUCCESS;
165
166 Status = PopSendQuerySystemPowerState(DeviceNode->PhysicalDeviceObject,
167 PowerStateContext->SystemPowerState,
168 PowerStateContext->PowerAction);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
172 }
173
174 #if 0
175 return Status;
176 #else
177 return STATUS_SUCCESS;
178 #endif
179 }
180
181 NTSTATUS
182 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
183 PVOID Context)
184 {
185 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
186 NTSTATUS Status;
187
188 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
189
190 if (DeviceNode == IopRootDeviceNode)
191 return STATUS_SUCCESS;
192
193 if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
194 return STATUS_SUCCESS;
195
196 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
197 return STATUS_SUCCESS;
198
199 Status = PopSendSetSystemPowerState(DeviceNode->PhysicalDeviceObject,
200 PowerStateContext->SystemPowerState,
201 PowerStateContext->PowerAction);
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
205 }
206
207 #if 0
208 return Status;
209 #else
210 return STATUS_SUCCESS;
211 #endif
212 }
213
214 NTSTATUS
215 NTAPI
216 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
217 {
218 PDEVICE_OBJECT DeviceObject;
219 PDEVICE_OBJECT Fdo;
220 NTSTATUS Status;
221 DEVICETREE_TRAVERSE_CONTEXT Context;
222 POWER_STATE_TRAVERSE_CONTEXT PowerContext;
223
224 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
225 if (!NT_SUCCESS(Status))
226 {
227 DPRINT1("No system power driver available\n");
228 Fdo = NULL;
229 }
230 else
231 {
232 Fdo = IoGetAttachedDeviceReference(DeviceObject);
233 if (Fdo == DeviceObject)
234 {
235 DPRINT("An FDO was not attached\n");
236 return STATUS_UNSUCCESSFUL;
237 }
238 }
239
240 /* Set up context */
241 PowerContext.PowerAction = PowerAction;
242 PowerContext.SystemPowerState = PowerState;
243 PowerContext.PowerDevice = Fdo;
244
245 /* Query for system power change */
246 IopInitDeviceTreeTraverseContext(&Context,
247 IopRootDeviceNode,
248 PopQuerySystemPowerStateTraverse,
249 &PowerContext);
250
251 Status = IopTraverseDeviceTree(&Context);
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT1("Query system power state failed; changing state anyway\n");
255 }
256
257 /* Set system power change */
258 IopInitDeviceTreeTraverseContext(&Context,
259 IopRootDeviceNode,
260 PopSetSystemPowerStateTraverse,
261 &PowerContext);
262
263 IopTraverseDeviceTree(&Context);
264
265 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
266
267 if (Fdo != NULL)
268 {
269 if (PowerAction != PowerActionShutdownReset)
270 PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
271
272 ObDereferenceObject(Fdo);
273 }
274
275 return Status;
276 }
277
278 BOOLEAN
279 NTAPI
280 INIT_FUNCTION
281 PoInitSystem(IN ULONG BootPhase)
282 {
283 PVOID NotificationEntry;
284 PCHAR CommandLine;
285 BOOLEAN ForceAcpiDisable = FALSE;
286
287 /* Check if this is phase 1 init */
288 if (BootPhase == 1)
289 {
290 /* Register power button notification */
291 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
292 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
293 (PVOID)&GUID_DEVICE_SYS_BUTTON,
294 IopRootDeviceNode->
295 PhysicalDeviceObject->DriverObject,
296 PopAddRemoveSysCapsCallback,
297 NULL,
298 &NotificationEntry);
299
300 /* Register lid notification */
301 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
302 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
303 (PVOID)&GUID_DEVICE_LID,
304 IopRootDeviceNode->
305 PhysicalDeviceObject->DriverObject,
306 PopAddRemoveSysCapsCallback,
307 NULL,
308 &NotificationEntry);
309 return TRUE;
310 }
311
312 /* Get the Command Line */
313 CommandLine = KeLoaderBlock->LoadOptions;
314
315 /* Upcase it */
316 _strupr(CommandLine);
317
318 /* Check for ACPI disable */
319 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
320
321 if (ForceAcpiDisable)
322 {
323 /* Set the ACPI State to False if it's been forced that way */
324 PopAcpiPresent = FALSE;
325 }
326 else
327 {
328 /* Otherwise check if the LoaderBlock has a ACPI Table */
329 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
330 }
331
332
333 /* Initialize volume support */
334 InitializeListHead(&PopVolumeDevices);
335 KeInitializeGuardedMutex(&PopVolumeLock);
336
337 /* Initialize support for dope */
338 KeInitializeSpinLock(&PopDopeGlobalLock);
339
340 /* Initialize support for shutdown waits and work-items */
341 PopInitShutdownList();
342
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 VOID
448 NTAPI
449 PoSetHiberRange(IN PVOID HiberContext,
450 IN ULONG Flags,
451 IN OUT PVOID StartPage,
452 IN ULONG Length,
453 IN ULONG PageTag)
454 {
455 UNIMPLEMENTED;
456 return;
457 }
458
459 /*
460 * @implemented
461 */
462 NTSTATUS
463 NTAPI
464 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
465 IN OUT PIRP Irp)
466 {
467 NTSTATUS Status;
468
469 /* Forward to Io -- FIXME! */
470 Status = IoCallDriver(DeviceObject, Irp);
471
472 /* Return status */
473 return Status;
474 }
475
476 /*
477 * @unimplemented
478 */
479 PULONG
480 NTAPI
481 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
482 IN ULONG ConservationIdleTime,
483 IN ULONG PerformanceIdleTime,
484 IN DEVICE_POWER_STATE State)
485 {
486 UNIMPLEMENTED;
487 return NULL;
488 }
489
490 /*
491 * @unimplemented
492 */
493 PVOID
494 NTAPI
495 PoRegisterSystemState(IN PVOID StateHandle,
496 IN EXECUTION_STATE Flags)
497 {
498 UNIMPLEMENTED;
499 return NULL;
500 }
501
502 /*
503 * @implemented
504 */
505 NTSTATUS
506 NTAPI
507 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
508 IN UCHAR MinorFunction,
509 IN POWER_STATE PowerState,
510 IN PREQUEST_POWER_COMPLETE CompletionFunction,
511 IN PVOID Context,
512 OUT PIRP *pIrp OPTIONAL)
513 {
514 PDEVICE_OBJECT TopDeviceObject;
515 PIO_STACK_LOCATION Stack;
516 PIRP Irp;
517
518 if (MinorFunction != IRP_MN_QUERY_POWER
519 && MinorFunction != IRP_MN_SET_POWER
520 && MinorFunction != IRP_MN_WAIT_WAKE)
521 return STATUS_INVALID_PARAMETER_2;
522
523 /* Always call the top of the device stack */
524 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
525
526 Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
527 if (!Irp)
528 {
529 ObDereferenceObject(TopDeviceObject);
530 return STATUS_INSUFFICIENT_RESOURCES;
531 }
532
533 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
534 Irp->IoStatus.Information = 0;
535
536 IoSetNextIrpStackLocation(Irp);
537
538 Stack = IoGetNextIrpStackLocation(Irp);
539 Stack->Parameters.Others.Argument1 = DeviceObject;
540 Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
541 Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
542 Stack->Parameters.Others.Argument4 = Context;
543 Stack->DeviceObject = TopDeviceObject;
544 IoSetNextIrpStackLocation(Irp);
545
546 Stack = IoGetNextIrpStackLocation(Irp);
547 Stack->MajorFunction = IRP_MJ_POWER;
548 Stack->MinorFunction = MinorFunction;
549 if (MinorFunction == IRP_MN_WAIT_WAKE)
550 {
551 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
552 }
553 else
554 {
555 Stack->Parameters.Power.Type = DevicePowerState;
556 Stack->Parameters.Power.State = PowerState;
557 }
558
559 if (pIrp != NULL)
560 *pIrp = Irp;
561
562 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
563 PoCallDriver(TopDeviceObject, Irp);
564
565 /* Always return STATUS_PENDING. The completion routine
566 * will call CompletionFunction and complete the Irp.
567 */
568 return STATUS_PENDING;
569 }
570
571 /*
572 * @unimplemented
573 */
574 POWER_STATE
575 NTAPI
576 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
577 IN POWER_STATE_TYPE Type,
578 IN POWER_STATE State)
579 {
580 POWER_STATE ps;
581
582 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
583
584 ps.SystemState = PowerSystemWorking; // Fully on
585 ps.DeviceState = PowerDeviceD0; // Fully on
586
587 return ps;
588 }
589
590 /*
591 * @unimplemented
592 */
593 VOID
594 NTAPI
595 PoSetSystemState(IN EXECUTION_STATE Flags)
596 {
597 UNIMPLEMENTED;
598 }
599
600 /*
601 * @unimplemented
602 */
603 VOID
604 NTAPI
605 PoStartNextPowerIrp(IN PIRP Irp)
606 {
607 UNIMPLEMENTED;
608 }
609
610 /*
611 * @unimplemented
612 */
613 VOID
614 NTAPI
615 PoUnregisterSystemState(IN PVOID StateHandle)
616 {
617 UNIMPLEMENTED;
618 }
619
620 /*
621 * @unimplemented
622 */
623 NTSTATUS
624 NTAPI
625 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
626 IN SYSTEM_POWER_STATE MinSystemState,
627 IN ULONG Flags,
628 IN BOOLEAN Asynchronous)
629 {
630 UNIMPLEMENTED;
631 return STATUS_NOT_IMPLEMENTED;
632 }
633
634 /*
635 * @unimplemented
636 */
637 NTSTATUS
638 NTAPI
639 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
640 IN PVOID InputBuffer OPTIONAL,
641 IN ULONG InputBufferLength,
642 OUT PVOID OutputBuffer OPTIONAL,
643 IN ULONG OutputBufferLength)
644 {
645 NTSTATUS Status;
646
647 PAGED_CODE();
648
649 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
650 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
651 PowerInformationLevel,
652 InputBuffer, InputBufferLength,
653 OutputBuffer, OutputBufferLength);
654
655 switch (PowerInformationLevel)
656 {
657 case SystemBatteryState:
658 {
659 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
660
661 if (InputBuffer != NULL)
662 return STATUS_INVALID_PARAMETER;
663 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
664 return STATUS_BUFFER_TOO_SMALL;
665
666 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
667 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
668 BatteryState->EstimatedTime = MAXULONG;
669
670 Status = STATUS_SUCCESS;
671 break;
672 }
673
674 case SystemPowerCapabilities:
675 {
676 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
677
678 if (InputBuffer != NULL)
679 return STATUS_INVALID_PARAMETER;
680 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
681 return STATUS_BUFFER_TOO_SMALL;
682
683 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
684 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
685 //PowerCapabilities->SystemBatteriesPresent = 0;
686
687 Status = STATUS_SUCCESS;
688 break;
689 }
690
691 default:
692 Status = STATUS_NOT_IMPLEMENTED;
693 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
694 PowerInformationLevel);
695 break;
696 }
697
698 return Status;
699 }
700
701 NTSTATUS
702 NTAPI
703 NtGetDevicePowerState(IN HANDLE Device,
704 IN PDEVICE_POWER_STATE PowerState)
705 {
706 UNIMPLEMENTED;
707 return STATUS_NOT_IMPLEMENTED;
708 }
709
710 BOOLEAN
711 NTAPI
712 NtIsSystemResumeAutomatic(VOID)
713 {
714 UNIMPLEMENTED;
715 return FALSE;
716 }
717
718 NTSTATUS
719 NTAPI
720 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
721 {
722 UNIMPLEMENTED;
723 return STATUS_NOT_IMPLEMENTED;
724 }
725
726 NTSTATUS
727 NTAPI
728 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
729 OUT EXECUTION_STATE *PreviousFlags)
730 {
731 PKTHREAD Thread = KeGetCurrentThread();
732 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
733 EXECUTION_STATE PreviousState;
734 PAGED_CODE();
735
736 /* Validate flags */
737 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
738 {
739 /* Fail the request */
740 return STATUS_INVALID_PARAMETER;
741 }
742
743 /* Check for user parameters */
744 if (PreviousMode != KernelMode)
745 {
746 /* Protect the probes */
747 _SEH2_TRY
748 {
749 /* Check if the pointer is valid */
750 ProbeForWriteUlong(PreviousFlags);
751 }
752 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
753 {
754 /* It isn't -- fail */
755 _SEH2_YIELD(return _SEH2_GetExceptionCode());
756 }
757 _SEH2_END;
758 }
759
760 /* Save the previous state, always masking in the continous flag */
761 PreviousState = Thread->PowerState | ES_CONTINUOUS;
762
763 /* Check if we need to update the power state */
764 if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
765
766 /* Protect the write back to user mode */
767 _SEH2_TRY
768 {
769 /* Return the previous flags */
770 *PreviousFlags = PreviousState;
771 }
772 _SEH2_EXCEPT(ExSystemExceptionFilter())
773 {
774 /* Something's wrong, fail */
775 _SEH2_YIELD(return _SEH2_GetExceptionCode());
776 }
777 _SEH2_END;
778
779 /* All is good */
780 return STATUS_SUCCESS;
781 }
782
783 NTSTATUS
784 NTAPI
785 NtSetSystemPowerState(IN POWER_ACTION SystemAction,
786 IN SYSTEM_POWER_STATE MinSystemState,
787 IN ULONG Flags)
788 {
789 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
790 POP_POWER_ACTION Action = {0};
791 NTSTATUS Status;
792 ULONG Dummy;
793
794 /* Check for invalid parameter combinations */
795 if ((MinSystemState >= PowerSystemMaximum) ||
796 (MinSystemState <= PowerSystemUnspecified) ||
797 (SystemAction > PowerActionWarmEject) ||
798 (SystemAction < PowerActionReserved) ||
799 (Flags & ~(POWER_ACTION_QUERY_ALLOWED |
800 POWER_ACTION_UI_ALLOWED |
801 POWER_ACTION_OVERRIDE_APPS |
802 POWER_ACTION_LIGHTEST_FIRST |
803 POWER_ACTION_LOCK_CONSOLE |
804 POWER_ACTION_DISABLE_WAKES |
805 POWER_ACTION_CRITICAL)))
806 {
807 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
808 DPRINT1(" SystemAction: 0x%x\n", SystemAction);
809 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
810 DPRINT1(" Flags: 0x%x\n", Flags);
811 return STATUS_INVALID_PARAMETER;
812 }
813
814 /* Check for user caller */
815 if (PreviousMode != KernelMode)
816 {
817 /* Check for shutdown permission */
818 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
819 {
820 /* Not granted */
821 DPRINT1("ERROR: Privilege not held for shutdown\n");
822 return STATUS_PRIVILEGE_NOT_HELD;
823 }
824
825 /* Do it as a kernel-mode caller for consistency with system state */
826 return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags);
827 }
828
829 /* Read policy settings (partial shutdown vs. full shutdown) */
830 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
831
832 /* Disable lazy flushing of registry */
833 DPRINT("Stopping lazy flush\n");
834 CmSetLazyFlushState(FALSE);
835
836 /* Setup the power action */
837 Action.Action = SystemAction;
838 Action.Flags = Flags;
839
840 /* Notify callbacks */
841 DPRINT("Notifying callbacks\n");
842 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
843
844 /* Swap in any worker thread stacks */
845 DPRINT("Swapping worker threads\n");
846 ExSwapinWorkerThreads(FALSE);
847
848 /* Make our action global */
849 PopAction = Action;
850
851 /* Start power loop */
852 Status = STATUS_CANCELLED;
853 while (TRUE)
854 {
855 /* Break out if there's nothing to do */
856 if (Action.Action == PowerActionNone) break;
857
858 /* Check for first-pass or restart */
859 if (Status == STATUS_CANCELLED)
860 {
861 /* Check for shutdown action */
862 if ((PopAction.Action == PowerActionShutdown) ||
863 (PopAction.Action == PowerActionShutdownReset) ||
864 (PopAction.Action == PowerActionShutdownOff))
865 {
866 /* Set the action */
867 PopAction.Shutdown = TRUE;
868 }
869
870 /* Now we are good to go */
871 Status = STATUS_SUCCESS;
872 }
873
874 /* Check if we're still in an invalid status */
875 if (!NT_SUCCESS(Status)) break;
876
877 #ifndef NEWCC
878 /* Flush dirty cache pages */
879 CcRosFlushDirtyPages(-1, &Dummy, FALSE); //HACK: We really should wait here!
880 #else
881 Dummy = 0;
882 #endif
883
884 /* Flush all volumes and the registry */
885 DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy);
886 PopFlushVolumes(PopAction.Shutdown);
887
888 /* Set IRP for drivers */
889 PopAction.IrpMinor = IRP_MN_SET_POWER;
890 if (PopAction.Shutdown)
891 {
892 DPRINT("Queueing shutdown thread\n");
893 /* Check if we are running in the system context */
894 if (PsGetCurrentProcess() != PsInitialSystemProcess)
895 {
896 /* We're not, so use a worker thread for shutdown */
897 ExInitializeWorkItem(&PopShutdownWorkItem,
898 &PopGracefulShutdown,
899 NULL);
900
901 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
902
903 /* Spend us -- when we wake up, the system is good to go down */
904 KeSuspendThread(KeGetCurrentThread());
905 Status = STATUS_SYSTEM_SHUTDOWN;
906 goto Exit;
907
908 }
909 else
910 {
911 /* Do the shutdown inline */
912 PopGracefulShutdown(NULL);
913 }
914 }
915
916 /* You should not have made it this far */
917 // ASSERTMSG("System is still up and running?!", FALSE);
918 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action);
919 break;
920 }
921
922 Exit:
923 /* We're done, return */
924 return Status;
925 }