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