96a211b5680b5a7d5cb7327899e6dc3e3f85e79c
[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 } REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
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_ITEM RequestPowerItem;
41
42 Stack = IoGetNextIrpStackLocation(Irp);
43 RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
44
45 RequestPowerItem->CompletionRoutine(DeviceObject,
46 Stack->MinorFunction,
47 RequestPowerItem->PowerState,
48 RequestPowerItem->Context,
49 &Irp->IoStatus);
50
51 ExFreePool(&Irp->IoStatus);
52 ExFreePool(Context);
53
54 return STATUS_SUCCESS;
55 }
56
57 VOID
58 NTAPI
59 PopCleanupPowerState(IN PPOWER_STATE PowerState)
60 {
61 //UNIMPLEMENTED;
62 }
63
64 NTSTATUS
65 NTAPI
66 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState)
67 {
68 IO_STATUS_BLOCK IoStatusBlock;
69 PDEVICE_OBJECT DeviceObject;
70 PIO_STACK_LOCATION IrpSp;
71 PDEVICE_OBJECT Fdo;
72 NTSTATUS Status;
73 KEVENT Event;
74 PIRP Irp;
75
76 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
77
78 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT1("No system power driver available\n");
82 return STATUS_UNSUCCESSFUL;
83 }
84
85 Fdo = IoGetAttachedDeviceReference(DeviceObject);
86
87 if (Fdo == DeviceObject)
88 {
89 DPRINT("An FDO was not attached\n");
90 return STATUS_UNSUCCESSFUL;
91 }
92
93 KeInitializeEvent(&Event,
94 NotificationEvent,
95 FALSE);
96
97 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
98 Fdo,
99 NULL,
100 0,
101 NULL,
102 &Event,
103 &IoStatusBlock);
104
105 IrpSp = IoGetNextIrpStackLocation(Irp);
106 IrpSp->MinorFunction = IRP_MN_SET_POWER;
107 IrpSp->Parameters.Power.Type = SystemPowerState;
108 IrpSp->Parameters.Power.State.SystemState = PowerState;
109
110 DPRINT("Calling ACPI driver");
111 Status = PoCallDriver(Fdo, Irp);
112 if (Status == STATUS_PENDING)
113 {
114 KeWaitForSingleObject(&Event,
115 Executive,
116 KernelMode,
117 FALSE,
118 NULL);
119 Status = IoStatusBlock.Status;
120 }
121
122 ObDereferenceObject(Fdo);
123
124 return Status;
125 }
126
127 BOOLEAN
128 NTAPI
129 PoInitSystem(IN ULONG BootPhase)
130 {
131 PVOID NotificationEntry;
132 PCHAR CommandLine;
133 BOOLEAN ForceAcpiDisable = FALSE;
134
135 /* Check if this is phase 1 init */
136 if (BootPhase == 1)
137 {
138 /* Registry power button notification */
139 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
140 0, /* The registry has not been initialized yet */
141 (PVOID)&GUID_DEVICE_SYS_BUTTON,
142 IopRootDeviceNode->
143 PhysicalDeviceObject->DriverObject,
144 PopAddRemoveSysCapsCallback,
145 NULL,
146 &NotificationEntry);
147 return TRUE;
148 }
149
150 /* Get the Command Line */
151 CommandLine = KeLoaderBlock->LoadOptions;
152
153 /* Upcase it */
154 _strupr(CommandLine);
155
156 /* Check for ACPI disable */
157 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
158
159 if (ForceAcpiDisable)
160 {
161 /* Set the ACPI State to False if it's been forced that way */
162 PopAcpiPresent = FALSE;
163 }
164 else
165 {
166 /* Otherwise check if the LoaderBlock has a ACPI Table */
167 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
168 }
169
170
171 /* Initialize volume support */
172 InitializeListHead(&PopVolumeDevices);
173 KeInitializeGuardedMutex(&PopVolumeLock);
174
175 /* Initialize support for dope */
176 KeInitializeSpinLock(&PopDopeGlobalLock);
177 return TRUE;
178 }
179
180 VOID
181 NTAPI
182 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
183 {
184 DPRINT1("PerfIdle function: %p\n", PowerState);
185 }
186
187 VOID
188 NTAPI
189 PopPerfIdleDpc(IN PKDPC Dpc,
190 IN PVOID DeferredContext,
191 IN PVOID SystemArgument1,
192 IN PVOID SystemArgument2)
193 {
194 /* Call the Perf Idle function */
195 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
196 }
197
198 VOID
199 FASTCALL
200 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
201 {
202 /* FIXME: Extremly naive implementation */
203 HalProcessorIdle();
204 }
205
206 VOID
207 NTAPI
208 PoInitializePrcb(IN PKPRCB Prcb)
209 {
210 /* Initialize the Power State */
211 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
212 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
213 Prcb->PowerState.CurrentThrottle = 100;
214 Prcb->PowerState.CurrentThrottleIndex = 0;
215 Prcb->PowerState.IdleFunction = PopIdle0;
216
217 /* Initialize the Perf DPC and Timer */
218 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
219 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
220 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
221 }
222
223 /* PUBLIC FUNCTIONS **********************************************************/
224
225 /*
226 * @unimplemented
227 */
228 NTSTATUS
229 NTAPI
230 PoCancelDeviceNotify(IN PVOID NotifyBlock)
231 {
232 UNIMPLEMENTED;
233 return STATUS_NOT_IMPLEMENTED;
234 }
235
236 /*
237 * @unimplemented
238 */
239 NTSTATUS
240 NTAPI
241 PoRegisterDeviceNotify(OUT PVOID Unknown0,
242 IN ULONG Unknown1,
243 IN ULONG Unknown2,
244 IN ULONG Unknown3,
245 IN PVOID Unknown4,
246 IN PVOID Unknown5)
247 {
248 UNIMPLEMENTED;
249 return STATUS_NOT_IMPLEMENTED;
250 }
251
252 /*
253 * @unimplemented
254 */
255 VOID
256 NTAPI
257 PoShutdownBugCheck(IN BOOLEAN LogError,
258 IN ULONG BugCheckCode,
259 IN ULONG_PTR BugCheckParameter1,
260 IN ULONG_PTR BugCheckParameter2,
261 IN ULONG_PTR BugCheckParameter3,
262 IN ULONG_PTR BugCheckParameter4)
263 {
264 DPRINT1("PoShutdownBugCheck called\n");
265
266 /* FIXME: Log error if requested */
267 /* FIXME: Initiate a shutdown */
268
269 /* Bugcheck the system */
270 KeBugCheckEx(BugCheckCode,
271 BugCheckParameter1,
272 BugCheckParameter2,
273 BugCheckParameter3,
274 BugCheckParameter4);
275 }
276
277 /*
278 * @unimplemented
279 */
280 NTSTATUS
281 NTAPI
282 PoRequestShutdownEvent(OUT PVOID *Event)
283 {
284 UNIMPLEMENTED;
285 return STATUS_NOT_IMPLEMENTED;
286 }
287
288 /*
289 * @unimplemented
290 */
291 VOID
292 NTAPI
293 PoSetHiberRange(IN PVOID HiberContext,
294 IN ULONG Flags,
295 IN OUT PVOID StartPage,
296 IN ULONG Length,
297 IN ULONG PageTag)
298 {
299 UNIMPLEMENTED;
300 return;
301 }
302
303 /*
304 * @implemented
305 */
306 NTSTATUS
307 NTAPI
308 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
309 IN OUT PIRP Irp)
310 {
311 NTSTATUS Status;
312
313 /* Forward to Io -- FIXME! */
314 Status = IoCallDriver(DeviceObject, Irp);
315
316 /* Return status */
317 return Status;
318 }
319
320 /*
321 * @unimplemented
322 */
323 PULONG
324 NTAPI
325 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
326 IN ULONG ConservationIdleTime,
327 IN ULONG PerformanceIdleTime,
328 IN DEVICE_POWER_STATE State)
329 {
330 UNIMPLEMENTED;
331 return NULL;
332 }
333
334 /*
335 * @unimplemented
336 */
337 PVOID
338 NTAPI
339 PoRegisterSystemState(IN PVOID StateHandle,
340 IN EXECUTION_STATE Flags)
341 {
342 UNIMPLEMENTED;
343 return NULL;
344 }
345
346 /*
347 * @implemented
348 */
349 NTSTATUS
350 NTAPI
351 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
352 IN UCHAR MinorFunction,
353 IN POWER_STATE PowerState,
354 IN PREQUEST_POWER_COMPLETE CompletionFunction,
355 IN PVOID Context,
356 OUT PIRP *pIrp OPTIONAL)
357 {
358 PDEVICE_OBJECT TopDeviceObject;
359 PIO_STACK_LOCATION Stack;
360 PIRP Irp;
361 PIO_STATUS_BLOCK IoStatusBlock;
362 PREQUEST_POWER_ITEM RequestPowerItem;
363 NTSTATUS Status;
364
365 if (MinorFunction != IRP_MN_QUERY_POWER
366 && MinorFunction != IRP_MN_SET_POWER
367 && MinorFunction != IRP_MN_WAIT_WAKE)
368 return STATUS_INVALID_PARAMETER_2;
369
370 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
371 if (!RequestPowerItem)
372 return STATUS_INSUFFICIENT_RESOURCES;
373 IoStatusBlock = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
374 if (!IoStatusBlock)
375 {
376 ExFreePool(RequestPowerItem);
377 return STATUS_INSUFFICIENT_RESOURCES;
378 }
379
380 /* Always call the top of the device stack */
381 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
382
383 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
384 TopDeviceObject,
385 NULL,
386 0,
387 NULL,
388 NULL,
389 IoStatusBlock);
390 if (!Irp)
391 {
392 ExFreePool(RequestPowerItem);
393 ExFreePool(IoStatusBlock);
394 return STATUS_INSUFFICIENT_RESOURCES;
395 }
396
397 /* POWER IRPs are always initialized with a status code of
398 STATUS_NOT_IMPLEMENTED */
399 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
400 Irp->IoStatus.Information = 0;
401
402 Stack = IoGetNextIrpStackLocation(Irp);
403 Stack->MinorFunction = MinorFunction;
404 if (MinorFunction == IRP_MN_WAIT_WAKE)
405 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
406 else
407 Stack->Parameters.WaitWake.PowerState = PowerState.DeviceState;
408
409 RequestPowerItem->CompletionRoutine = CompletionFunction;
410 RequestPowerItem->PowerState = PowerState;
411 RequestPowerItem->Context = Context;
412
413 if (pIrp != NULL)
414 *pIrp = Irp;
415
416 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
417 Status = IoCallDriver(TopDeviceObject, Irp);
418
419 /* Always return STATUS_PENDING. The completion routine
420 * will call CompletionFunction and complete the Irp.
421 */
422 return STATUS_PENDING;
423 }
424
425 /*
426 * @unimplemented
427 */
428 POWER_STATE
429 NTAPI
430 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
431 IN POWER_STATE_TYPE Type,
432 IN POWER_STATE State)
433 {
434 POWER_STATE ps;
435
436 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
437
438 ps.SystemState = PowerSystemWorking; // Fully on
439 ps.DeviceState = PowerDeviceD0; // Fully on
440
441 return ps;
442 }
443
444 /*
445 * @unimplemented
446 */
447 VOID
448 NTAPI
449 PoSetSystemState(IN EXECUTION_STATE Flags)
450 {
451 UNIMPLEMENTED;
452 }
453
454 /*
455 * @unimplemented
456 */
457 VOID
458 NTAPI
459 PoStartNextPowerIrp(IN PIRP Irp)
460 {
461 UNIMPLEMENTED;
462 }
463
464 /*
465 * @unimplemented
466 */
467 VOID
468 NTAPI
469 PoUnregisterSystemState(IN PVOID StateHandle)
470 {
471 UNIMPLEMENTED;
472 }
473
474 /*
475 * @unimplemented
476 */
477 NTSTATUS
478 NTAPI
479 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem)
480 {
481 PAGED_CODE();
482
483 UNIMPLEMENTED;
484 return STATUS_NOT_IMPLEMENTED;
485 }
486
487 /*
488 * @unimplemented
489 */
490 NTSTATUS
491 NTAPI
492 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
493 IN SYSTEM_POWER_STATE MinSystemState,
494 IN ULONG Flags,
495 IN BOOLEAN Asynchronous)
496 {
497 UNIMPLEMENTED;
498 return STATUS_NOT_IMPLEMENTED;
499 }
500
501 /*
502 * @unimplemented
503 */
504 NTSTATUS
505 NTAPI
506 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
507 IN PVOID InputBuffer OPTIONAL,
508 IN ULONG InputBufferLength,
509 OUT PVOID OutputBuffer OPTIONAL,
510 IN ULONG OutputBufferLength)
511 {
512 NTSTATUS Status;
513
514 PAGED_CODE();
515
516 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
517 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
518 PowerInformationLevel,
519 InputBuffer, InputBufferLength,
520 OutputBuffer, OutputBufferLength);
521
522 switch (PowerInformationLevel)
523 {
524 case SystemBatteryState:
525 {
526 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
527
528 if (InputBuffer != NULL)
529 return STATUS_INVALID_PARAMETER;
530 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
531 return STATUS_BUFFER_TOO_SMALL;
532
533 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
534 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
535 BatteryState->EstimatedTime = MAXULONG;
536
537 Status = STATUS_SUCCESS;
538 break;
539 }
540 case SystemPowerCapabilities:
541 {
542 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
543
544 if (InputBuffer != NULL)
545 return STATUS_INVALID_PARAMETER;
546 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
547 return STATUS_BUFFER_TOO_SMALL;
548
549 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
550 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
551 //PowerCapabilities->SystemBatteriesPresent = 0;
552
553 Status = STATUS_SUCCESS;
554 break;
555 }
556
557 default:
558 Status = STATUS_NOT_IMPLEMENTED;
559 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
560 PowerInformationLevel);
561 break;
562 }
563
564 return Status;
565 }
566
567 NTSTATUS
568 NTAPI
569 NtGetDevicePowerState(IN HANDLE Device,
570 IN PDEVICE_POWER_STATE PowerState)
571 {
572 UNIMPLEMENTED;
573 return STATUS_NOT_IMPLEMENTED;
574 }
575
576 BOOLEAN
577 NTAPI
578 NtIsSystemResumeAutomatic(VOID)
579 {
580 UNIMPLEMENTED;
581 return FALSE;
582 }
583
584 NTSTATUS
585 NTAPI
586 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
587 {
588 UNIMPLEMENTED;
589 return STATUS_NOT_IMPLEMENTED;
590 }
591
592 NTSTATUS
593 NTAPI
594 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
595 OUT EXECUTION_STATE *PreviousFlags)
596 {
597 PKTHREAD Thread = KeGetCurrentThread();
598 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
599 EXECUTION_STATE PreviousState;
600 PAGED_CODE();
601
602 /* Validate flags */
603 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
604 {
605 /* Fail the request */
606 return STATUS_INVALID_PARAMETER;
607 }
608
609 /* Check for user parameters */
610 if (PreviousMode != KernelMode)
611 {
612 /* Protect the probes */
613 _SEH2_TRY
614 {
615 /* Check if the pointer is valid */
616 ProbeForWriteUlong(PreviousFlags);
617 }
618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
619 {
620 /* It isn't -- fail */
621 _SEH2_YIELD(return _SEH2_GetExceptionCode());
622 }
623 _SEH2_END;
624 }
625
626 /* Save the previous state, always masking in the continous flag */
627 PreviousState = Thread->PowerState | ES_CONTINUOUS;
628
629 /* Check if we need to update the power state */
630 if (esFlags & ES_CONTINUOUS) Thread->PowerState = esFlags;
631
632 /* Protect the write back to user mode */
633 _SEH2_TRY
634 {
635 /* Return the previous flags */
636 *PreviousFlags = PreviousState;
637 }
638 _SEH2_EXCEPT(ExSystemExceptionFilter())
639 {
640 /* Something's wrong, fail */
641 _SEH2_YIELD(return _SEH2_GetExceptionCode());
642 }
643 _SEH2_END;
644
645 /* All is good */
646 return STATUS_SUCCESS;
647 }
648
649 NTSTATUS
650 NTAPI
651 NtSetSystemPowerState(IN POWER_ACTION SystemAction,
652 IN SYSTEM_POWER_STATE MinSystemState,
653 IN ULONG Flags)
654 {
655 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
656 POP_POWER_ACTION Action = {0};
657 NTSTATUS Status;
658
659 /* Check for invalid parameter combinations */
660 if ((MinSystemState >= PowerSystemMaximum) ||
661 (MinSystemState <= PowerSystemUnspecified) ||
662 (SystemAction > PowerActionWarmEject) ||
663 (SystemAction < PowerActionReserved) ||
664 (Flags & ~(POWER_ACTION_QUERY_ALLOWED |
665 POWER_ACTION_UI_ALLOWED |
666 POWER_ACTION_OVERRIDE_APPS |
667 POWER_ACTION_LIGHTEST_FIRST |
668 POWER_ACTION_LOCK_CONSOLE |
669 POWER_ACTION_DISABLE_WAKES |
670 POWER_ACTION_CRITICAL)))
671 {
672 DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
673 DPRINT1(" SystemAction: 0x%x\n", SystemAction);
674 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
675 DPRINT1(" Flags: 0x%x\n", Flags);
676 return STATUS_INVALID_PARAMETER;
677 }
678
679 /* Check for user caller */
680 if (PreviousMode != KernelMode)
681 {
682 /* Check for shutdown permission */
683 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
684 {
685 /* Not granted */
686 DPRINT1("ERROR: Privilege not held for shutdown\n");
687 //return STATUS_PRIVILEGE_NOT_HELD; HACK!
688 }
689
690 /* Do it as a kernel-mode caller for consistency with system state */
691 return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags);
692 }
693
694 /* Read policy settings (partial shutdown vs. full shutdown) */
695 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
696
697 /* Disable lazy flushing of registry */
698 DPRINT1("Stopping lazy flush\n");
699 CmSetLazyFlushState(FALSE);
700
701 /* Setup the power action */
702 Action.Action = SystemAction;
703 Action.Flags = Flags;
704
705 /* Notify callbacks */
706 DPRINT1("Notifying callbacks\n");
707 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
708
709 /* Swap in any worker thread stacks */
710 DPRINT1("Swapping worker threads\n");
711 ExSwapinWorkerThreads(FALSE);
712
713 /* Make our action global */
714 PopAction = Action;
715
716 /* Start power loop */
717 Status = STATUS_CANCELLED;
718 while (TRUE)
719 {
720 /* Break out if there's nothing to do */
721 if (Action.Action == PowerActionNone) break;
722
723 /* Check for first-pass or restart */
724 if (Status == STATUS_CANCELLED)
725 {
726 /* Check for shutdown action */
727 if ((PopAction.Action == PowerActionShutdown) ||
728 (PopAction.Action == PowerActionShutdownReset) ||
729 (PopAction.Action == PowerActionShutdownOff))
730 {
731 /* Set the action */
732 PopAction.Shutdown = TRUE;
733 }
734
735 /* Now we are good to go */
736 Status = STATUS_SUCCESS;
737 }
738
739 /* Check if we're still in an invalid status */
740 if (!NT_SUCCESS(Status)) break;
741
742 /* Flush all volumes and the registry */
743 DPRINT1("Flushing volumes\n");
744 PopFlushVolumes(PopAction.Shutdown);
745
746 /* Set IRP for drivers */
747 PopAction.IrpMinor = IRP_MN_SET_POWER;
748 if (PopAction.Shutdown)
749 {
750 DPRINT1("Queueing shutdown thread\n");
751 /* Check if we are running in the system context */
752 if (PsGetCurrentProcess() != PsInitialSystemProcess)
753 {
754 /* We're not, so use a worker thread for shutdown */
755 ExInitializeWorkItem(&PopShutdownWorkItem,
756 &PopGracefulShutdown,
757 NULL);
758
759 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
760
761 /* Spend us -- when we wake up, the system is good to go down */
762 KeSuspendThread(KeGetCurrentThread());
763 Status = STATUS_SYSTEM_SHUTDOWN;
764 goto Exit;
765
766 }
767 else
768 {
769 /* Do the shutdown inline */
770 PopGracefulShutdown(NULL);
771 }
772 }
773
774 /* You should not have made it this far */
775 ASSERT(FALSE && "System is still up and running?!");
776 break;
777 }
778
779 Exit:
780 /* We're done, return */
781 return Status;
782 }