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