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