Partial merge of condrv_restructure branch r65657.
[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 _REQUEST_POWER_ITEM
19 {
20 PREQUEST_POWER_COMPLETE CompletionRoutine;
21 POWER_STATE PowerState;
22 PVOID Context;
23 PDEVICE_OBJECT TopDeviceObject;
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 IoFreeIrp(Irp);
60
61 ObDereferenceObject(RequestPowerItem->TopDeviceObject);
62 ExFreePool(Context);
63
64 return STATUS_MORE_PROCESSING_REQUIRED;
65 }
66
67 VOID
68 NTAPI
69 PopCleanupPowerState(IN PPOWER_STATE PowerState)
70 {
71 //UNIMPLEMENTED;
72 }
73
74 NTSTATUS
75 PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
76 {
77 KEVENT Event;
78 IO_STATUS_BLOCK IoStatusBlock;
79 PIO_STACK_LOCATION IrpSp;
80 PIRP Irp;
81 NTSTATUS Status;
82
83 KeInitializeEvent(&Event,
84 NotificationEvent,
85 FALSE);
86
87 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
88 DeviceObject,
89 NULL,
90 0,
91 NULL,
92 &Event,
93 &IoStatusBlock);
94 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
95
96 IrpSp = IoGetNextIrpStackLocation(Irp);
97 IrpSp->MinorFunction = IRP_MN_QUERY_POWER;
98 IrpSp->Parameters.Power.Type = SystemPowerState;
99 IrpSp->Parameters.Power.State.SystemState = SystemState;
100 IrpSp->Parameters.Power.ShutdownType = PowerAction;
101
102 Status = PoCallDriver(DeviceObject, Irp);
103 if (Status == STATUS_PENDING)
104 {
105 KeWaitForSingleObject(&Event,
106 Executive,
107 KernelMode,
108 FALSE,
109 NULL);
110 Status = IoStatusBlock.Status;
111 }
112
113 return Status;
114 }
115
116 NTSTATUS
117 PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
118 {
119 KEVENT Event;
120 IO_STATUS_BLOCK IoStatusBlock;
121 PIO_STACK_LOCATION IrpSp;
122 PIRP Irp;
123 NTSTATUS Status;
124
125 KeInitializeEvent(&Event,
126 NotificationEvent,
127 FALSE);
128
129 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
130 DeviceObject,
131 NULL,
132 0,
133 NULL,
134 &Event,
135 &IoStatusBlock);
136 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
137
138 IrpSp = IoGetNextIrpStackLocation(Irp);
139 IrpSp->MinorFunction = IRP_MN_SET_POWER;
140 IrpSp->Parameters.Power.Type = SystemPowerState;
141 IrpSp->Parameters.Power.State.SystemState = SystemState;
142 IrpSp->Parameters.Power.ShutdownType = PowerAction;
143
144 Status = PoCallDriver(DeviceObject, Irp);
145 if (Status == STATUS_PENDING)
146 {
147 KeWaitForSingleObject(&Event,
148 Executive,
149 KernelMode,
150 FALSE,
151 NULL);
152 Status = IoStatusBlock.Status;
153 }
154
155 return Status;
156 }
157
158 NTSTATUS
159 PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
160 PVOID Context)
161 {
162 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
163 NTSTATUS Status;
164
165 DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
166
167 if (DeviceNode == IopRootDeviceNode)
168 return STATUS_SUCCESS;
169
170 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
171 return STATUS_SUCCESS;
172
173 Status = PopSendQuerySystemPowerState(DeviceNode->PhysicalDeviceObject,
174 PowerStateContext->SystemPowerState,
175 PowerStateContext->PowerAction);
176 if (!NT_SUCCESS(Status))
177 {
178 DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
179 }
180
181 #if 0
182 return Status;
183 #else
184 return STATUS_SUCCESS;
185 #endif
186 }
187
188 NTSTATUS
189 PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
190 PVOID Context)
191 {
192 PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
193 NTSTATUS Status;
194
195 DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
196
197 if (DeviceNode == IopRootDeviceNode)
198 return STATUS_SUCCESS;
199
200 if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
201 return STATUS_SUCCESS;
202
203 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
204 return STATUS_SUCCESS;
205
206 Status = PopSendSetSystemPowerState(DeviceNode->PhysicalDeviceObject,
207 PowerStateContext->SystemPowerState,
208 PowerStateContext->PowerAction);
209 if (!NT_SUCCESS(Status))
210 {
211 DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
212 }
213
214 #if 0
215 return Status;
216 #else
217 return STATUS_SUCCESS;
218 #endif
219 }
220
221 NTSTATUS
222 NTAPI
223 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
224 {
225 PDEVICE_OBJECT DeviceObject;
226 PDEVICE_OBJECT Fdo;
227 NTSTATUS Status;
228 DEVICETREE_TRAVERSE_CONTEXT Context;
229 POWER_STATE_TRAVERSE_CONTEXT PowerContext;
230
231 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
232 if (!NT_SUCCESS(Status))
233 {
234 DPRINT1("No system power driver available\n");
235 Fdo = NULL;
236 }
237 else
238 {
239 Fdo = IoGetAttachedDeviceReference(DeviceObject);
240 if (Fdo == DeviceObject)
241 {
242 DPRINT("An FDO was not attached\n");
243 return STATUS_UNSUCCESSFUL;
244 }
245 }
246
247 /* Set up context */
248 PowerContext.PowerAction = PowerAction;
249 PowerContext.SystemPowerState = PowerState;
250 PowerContext.PowerDevice = Fdo;
251
252 /* Query for system power change */
253 IopInitDeviceTreeTraverseContext(&Context,
254 IopRootDeviceNode,
255 PopQuerySystemPowerStateTraverse,
256 &PowerContext);
257
258 Status = IopTraverseDeviceTree(&Context);
259 if (!NT_SUCCESS(Status))
260 {
261 DPRINT1("Query system power state failed; changing state anyway\n");
262 }
263
264 /* Set system power change */
265 IopInitDeviceTreeTraverseContext(&Context,
266 IopRootDeviceNode,
267 PopSetSystemPowerStateTraverse,
268 &PowerContext);
269
270 IopTraverseDeviceTree(&Context);
271
272 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
273
274 if (Fdo != NULL)
275 {
276 if (PowerAction != PowerActionShutdownReset)
277 PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
278
279 ObDereferenceObject(Fdo);
280 }
281
282 return Status;
283 }
284
285 BOOLEAN
286 NTAPI
287 INIT_FUNCTION
288 PoInitSystem(IN ULONG BootPhase)
289 {
290 PVOID NotificationEntry;
291 PCHAR CommandLine;
292 BOOLEAN ForceAcpiDisable = FALSE;
293
294 /* Check if this is phase 1 init */
295 if (BootPhase == 1)
296 {
297 /* Register power button notification */
298 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
299 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
300 (PVOID)&GUID_DEVICE_SYS_BUTTON,
301 IopRootDeviceNode->
302 PhysicalDeviceObject->DriverObject,
303 PopAddRemoveSysCapsCallback,
304 NULL,
305 &NotificationEntry);
306
307 /* Register lid notification */
308 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
309 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
310 (PVOID)&GUID_DEVICE_LID,
311 IopRootDeviceNode->
312 PhysicalDeviceObject->DriverObject,
313 PopAddRemoveSysCapsCallback,
314 NULL,
315 &NotificationEntry);
316 return TRUE;
317 }
318
319 /* Get the Command Line */
320 CommandLine = KeLoaderBlock->LoadOptions;
321
322 /* Upcase it */
323 _strupr(CommandLine);
324
325 /* Check for ACPI disable */
326 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
327
328 if (ForceAcpiDisable)
329 {
330 /* Set the ACPI State to False if it's been forced that way */
331 PopAcpiPresent = FALSE;
332 }
333 else
334 {
335 /* Otherwise check if the LoaderBlock has a ACPI Table */
336 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
337 }
338
339
340 /* Initialize volume support */
341 InitializeListHead(&PopVolumeDevices);
342 KeInitializeGuardedMutex(&PopVolumeLock);
343
344 /* Initialize support for dope */
345 KeInitializeSpinLock(&PopDopeGlobalLock);
346
347 /* Initialize support for shutdown waits and work-items */
348 PopInitShutdownList();
349
350 return TRUE;
351 }
352
353 VOID
354 NTAPI
355 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
356 {
357 DPRINT1("PerfIdle function: %p\n", PowerState);
358 }
359
360 VOID
361 NTAPI
362 PopPerfIdleDpc(IN PKDPC Dpc,
363 IN PVOID DeferredContext,
364 IN PVOID SystemArgument1,
365 IN PVOID SystemArgument2)
366 {
367 /* Call the Perf Idle function */
368 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
369 }
370
371 VOID
372 FASTCALL
373 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
374 {
375 /* FIXME: Extremly naive implementation */
376 HalProcessorIdle();
377 }
378
379 VOID
380 NTAPI
381 INIT_FUNCTION
382 PoInitializePrcb(IN PKPRCB Prcb)
383 {
384 /* Initialize the Power State */
385 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
386 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
387 Prcb->PowerState.CurrentThrottle = 100;
388 Prcb->PowerState.CurrentThrottleIndex = 0;
389 Prcb->PowerState.IdleFunction = PopIdle0;
390
391 /* Initialize the Perf DPC and Timer */
392 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
393 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
394 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
395 }
396
397 /* PUBLIC FUNCTIONS **********************************************************/
398
399 /*
400 * @unimplemented
401 */
402 NTSTATUS
403 NTAPI
404 PoCancelDeviceNotify(IN PVOID NotifyBlock)
405 {
406 UNIMPLEMENTED;
407 return STATUS_NOT_IMPLEMENTED;
408 }
409
410 /*
411 * @unimplemented
412 */
413 NTSTATUS
414 NTAPI
415 PoRegisterDeviceNotify(OUT PVOID Unknown0,
416 IN ULONG Unknown1,
417 IN ULONG Unknown2,
418 IN ULONG Unknown3,
419 IN PVOID Unknown4,
420 IN PVOID Unknown5)
421 {
422 UNIMPLEMENTED;
423 return STATUS_NOT_IMPLEMENTED;
424 }
425
426 /*
427 * @unimplemented
428 */
429 VOID
430 NTAPI
431 PoShutdownBugCheck(IN BOOLEAN LogError,
432 IN ULONG BugCheckCode,
433 IN ULONG_PTR BugCheckParameter1,
434 IN ULONG_PTR BugCheckParameter2,
435 IN ULONG_PTR BugCheckParameter3,
436 IN ULONG_PTR BugCheckParameter4)
437 {
438 DPRINT1("PoShutdownBugCheck called\n");
439
440 /* FIXME: Log error if requested */
441 /* FIXME: Initiate a shutdown */
442
443 /* Bugcheck the system */
444 KeBugCheckEx(BugCheckCode,
445 BugCheckParameter1,
446 BugCheckParameter2,
447 BugCheckParameter3,
448 BugCheckParameter4);
449 }
450
451 /*
452 * @unimplemented
453 */
454 VOID
455 NTAPI
456 PoSetHiberRange(IN PVOID HiberContext,
457 IN ULONG Flags,
458 IN OUT PVOID StartPage,
459 IN ULONG Length,
460 IN ULONG PageTag)
461 {
462 UNIMPLEMENTED;
463 return;
464 }
465
466 /*
467 * @implemented
468 */
469 NTSTATUS
470 NTAPI
471 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
472 IN OUT PIRP Irp)
473 {
474 NTSTATUS Status;
475
476 /* Forward to Io -- FIXME! */
477 Status = IoCallDriver(DeviceObject, Irp);
478
479 /* Return status */
480 return Status;
481 }
482
483 /*
484 * @unimplemented
485 */
486 PULONG
487 NTAPI
488 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
489 IN ULONG ConservationIdleTime,
490 IN ULONG PerformanceIdleTime,
491 IN DEVICE_POWER_STATE State)
492 {
493 UNIMPLEMENTED;
494 return NULL;
495 }
496
497 /*
498 * @unimplemented
499 */
500 PVOID
501 NTAPI
502 PoRegisterSystemState(IN PVOID StateHandle,
503 IN EXECUTION_STATE Flags)
504 {
505 UNIMPLEMENTED;
506 return NULL;
507 }
508
509 /*
510 * @implemented
511 */
512 NTSTATUS
513 NTAPI
514 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
515 IN UCHAR MinorFunction,
516 IN POWER_STATE PowerState,
517 IN PREQUEST_POWER_COMPLETE CompletionFunction,
518 IN PVOID Context,
519 OUT PIRP *pIrp OPTIONAL)
520 {
521 PDEVICE_OBJECT TopDeviceObject;
522 PIO_STACK_LOCATION Stack;
523 PIRP Irp;
524 PREQUEST_POWER_ITEM RequestPowerItem;
525
526 if (MinorFunction != IRP_MN_QUERY_POWER
527 && MinorFunction != IRP_MN_SET_POWER
528 && MinorFunction != IRP_MN_WAIT_WAKE)
529 return STATUS_INVALID_PARAMETER_2;
530
531 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
532 if (!RequestPowerItem)
533 return STATUS_INSUFFICIENT_RESOURCES;
534
535 /* Always call the top of the device stack */
536 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
537
538 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER,
539 TopDeviceObject,
540 NULL,
541 0,
542 NULL,
543 NULL);
544 if (!Irp)
545 {
546 ObDereferenceObject(TopDeviceObject);
547 ExFreePool(RequestPowerItem);
548 return STATUS_INSUFFICIENT_RESOURCES;
549 }
550
551 /* POWER IRPs are always initialized with a status code of
552 STATUS_NOT_IMPLEMENTED */
553 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
554 Irp->IoStatus.Information = 0;
555
556 Stack = IoGetNextIrpStackLocation(Irp);
557 Stack->MinorFunction = MinorFunction;
558 if (MinorFunction == IRP_MN_WAIT_WAKE)
559 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
560 else
561 {
562 Stack->Parameters.Power.Type = DevicePowerState;
563 Stack->Parameters.Power.State = PowerState;
564 }
565
566 RequestPowerItem->CompletionRoutine = CompletionFunction;
567 RequestPowerItem->PowerState = PowerState;
568 RequestPowerItem->Context = Context;
569 RequestPowerItem->TopDeviceObject = TopDeviceObject;
570
571 if (pIrp != NULL)
572 *pIrp = Irp;
573
574 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
575 PoCallDriver(TopDeviceObject, Irp);
576
577 /* Always return STATUS_PENDING. The completion routine
578 * will call CompletionFunction and complete the Irp.
579 */
580 return STATUS_PENDING;
581 }
582
583 /*
584 * @unimplemented
585 */
586 POWER_STATE
587 NTAPI
588 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
589 IN POWER_STATE_TYPE Type,
590 IN POWER_STATE State)
591 {
592 POWER_STATE ps;
593
594 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
595
596 ps.SystemState = PowerSystemWorking; // Fully on
597 ps.DeviceState = PowerDeviceD0; // Fully on
598
599 return ps;
600 }
601
602 /*
603 * @unimplemented
604 */
605 VOID
606 NTAPI
607 PoSetSystemState(IN EXECUTION_STATE Flags)
608 {
609 UNIMPLEMENTED;
610 }
611
612 /*
613 * @unimplemented
614 */
615 VOID
616 NTAPI
617 PoStartNextPowerIrp(IN PIRP Irp)
618 {
619 UNIMPLEMENTED;
620 }
621
622 /*
623 * @unimplemented
624 */
625 VOID
626 NTAPI
627 PoUnregisterSystemState(IN PVOID StateHandle)
628 {
629 UNIMPLEMENTED;
630 }
631
632 /*
633 * @unimplemented
634 */
635 NTSTATUS
636 NTAPI
637 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
638 IN SYSTEM_POWER_STATE MinSystemState,
639 IN ULONG Flags,
640 IN BOOLEAN Asynchronous)
641 {
642 UNIMPLEMENTED;
643 return STATUS_NOT_IMPLEMENTED;
644 }
645
646 /*
647 * @unimplemented
648 */
649 NTSTATUS
650 NTAPI
651 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
652 IN PVOID InputBuffer OPTIONAL,
653 IN ULONG InputBufferLength,
654 OUT PVOID OutputBuffer OPTIONAL,
655 IN ULONG OutputBufferLength)
656 {
657 NTSTATUS Status;
658
659 PAGED_CODE();
660
661 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
662 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
663 PowerInformationLevel,
664 InputBuffer, InputBufferLength,
665 OutputBuffer, OutputBufferLength);
666
667 switch (PowerInformationLevel)
668 {
669 case SystemBatteryState:
670 {
671 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
672
673 if (InputBuffer != NULL)
674 return STATUS_INVALID_PARAMETER;
675 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
676 return STATUS_BUFFER_TOO_SMALL;
677
678 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
679 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
680 BatteryState->EstimatedTime = MAXULONG;
681
682 Status = STATUS_SUCCESS;
683 break;
684 }
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;
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 DPRINT("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 DPRINT("Notifying callbacks\n");
854 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
855
856 /* Swap in any worker thread stacks */
857 DPRINT("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 DPRINT("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 DPRINT("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 ASSERTMSG("System is still up and running?!", FALSE);
930 break;
931 }
932
933 Exit:
934 /* We're done, return */
935 return Status;
936 }