X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=ntoskrnl%2Fpo%2Fpower.c;h=359a035f29481504e9c89c720ca012ed48c47698;hp=f103898d2f53268ff16d1f05b6d526536e2e9a04;hb=406dfdbc870f3a6874c0959a87428c94f7526d3b;hpb=6afbc8f48353ab80737a6bc854b6c7e478be8e2d diff --git a/ntoskrnl/po/power.c b/ntoskrnl/po/power.c index f103898d2f5..359a035f294 100644 --- a/ntoskrnl/po/power.c +++ b/ntoskrnl/po/power.c @@ -24,6 +24,8 @@ typedef struct _REQUEST_POWER_ITEM PDEVICE_NODE PopSystemPowerDeviceNode = NULL; BOOLEAN PopAcpiPresent = FALSE; +POP_POWER_ACTION PopAction; +WORK_QUEUE_ITEM PopShutdownWorkItem; /* PRIVATE FUNCTIONS *********************************************************/ @@ -45,11 +47,12 @@ PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject, RequestPowerItem->PowerState, RequestPowerItem->Context, &Irp->IoStatus); - - ExFreePool(&Irp->IoStatus); + ExFreePool(Context); - return STATUS_SUCCESS; + IoFreeIrp(Irp); + + return STATUS_MORE_PROCESSING_REQUIRED; } VOID @@ -124,6 +127,7 @@ PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState) BOOLEAN NTAPI +INIT_FUNCTION PoInitSystem(IN ULONG BootPhase) { PVOID NotificationEntry; @@ -133,15 +137,25 @@ PoInitSystem(IN ULONG BootPhase) /* Check if this is phase 1 init */ if (BootPhase == 1) { - /* Registry power button notification */ + /* Register power button notification */ IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, - 0, /* The registry has not been initialized yet */ + PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, (PVOID)&GUID_DEVICE_SYS_BUTTON, IopRootDeviceNode-> PhysicalDeviceObject->DriverObject, PopAddRemoveSysCapsCallback, NULL, &NotificationEntry); + + /* Register lid notification */ + IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, + PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, + (PVOID)&GUID_DEVICE_LID, + IopRootDeviceNode-> + PhysicalDeviceObject->DriverObject, + PopAddRemoveSysCapsCallback, + NULL, + &NotificationEntry); return TRUE; } @@ -165,6 +179,13 @@ PoInitSystem(IN ULONG BootPhase) PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE; } + + /* Initialize volume support */ + InitializeListHead(&PopVolumeDevices); + KeInitializeGuardedMutex(&PopVolumeLock); + + /* Initialize support for dope */ + KeInitializeSpinLock(&PopDopeGlobalLock); return TRUE; } @@ -196,6 +217,7 @@ PopIdle0(IN PPROCESSOR_POWER_STATE PowerState) VOID NTAPI +INIT_FUNCTION PoInitializePrcb(IN PKPRCB Prcb) { /* Initialize the Power State */ @@ -349,9 +371,7 @@ PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject, PDEVICE_OBJECT TopDeviceObject; PIO_STACK_LOCATION Stack; PIRP Irp; - PIO_STATUS_BLOCK IoStatusBlock; PREQUEST_POWER_ITEM RequestPowerItem; - NTSTATUS Status; if (MinorFunction != IRP_MN_QUERY_POWER && MinorFunction != IRP_MN_SET_POWER @@ -361,27 +381,19 @@ PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject, RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM)); if (!RequestPowerItem) return STATUS_INSUFFICIENT_RESOURCES; - IoStatusBlock = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK)); - if (!IoStatusBlock) - { - ExFreePool(RequestPowerItem); - return STATUS_INSUFFICIENT_RESOURCES; - } /* Always call the top of the device stack */ TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); - Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, - TopDeviceObject, - NULL, - 0, - NULL, - NULL, - IoStatusBlock); + Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER, + TopDeviceObject, + NULL, + 0, + NULL, + NULL); if (!Irp) { ExFreePool(RequestPowerItem); - ExFreePool(IoStatusBlock); return STATUS_INSUFFICIENT_RESOURCES; } @@ -395,7 +407,10 @@ PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject, if (MinorFunction == IRP_MN_WAIT_WAKE) Stack->Parameters.WaitWake.PowerState = PowerState.SystemState; else - Stack->Parameters.WaitWake.PowerState = PowerState.DeviceState; + { + Stack->Parameters.Power.Type = DevicePowerState; + Stack->Parameters.Power.State = PowerState; + } RequestPowerItem->CompletionRoutine = CompletionFunction; RequestPowerItem->PowerState = PowerState; @@ -405,7 +420,7 @@ PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject, *pIrp = Irp; IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE); - Status = IoCallDriver(TopDeviceObject, Irp); + IoCallDriver(TopDeviceObject, Irp); /* Always return STATUS_PENDING. The completion routine * will call CompletionFunction and complete the Irp. @@ -636,3 +651,144 @@ NtSetThreadExecutionState(IN EXECUTION_STATE esFlags, /* All is good */ return STATUS_SUCCESS; } + +NTSTATUS +NTAPI +NtSetSystemPowerState(IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags) +{ + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + POP_POWER_ACTION Action = {0}; + NTSTATUS Status; + ULONG Dummy; + + /* Check for invalid parameter combinations */ + if ((MinSystemState >= PowerSystemMaximum) || + (MinSystemState <= PowerSystemUnspecified) || + (SystemAction > PowerActionWarmEject) || + (SystemAction < PowerActionReserved) || + (Flags & ~(POWER_ACTION_QUERY_ALLOWED | + POWER_ACTION_UI_ALLOWED | + POWER_ACTION_OVERRIDE_APPS | + POWER_ACTION_LIGHTEST_FIRST | + POWER_ACTION_LOCK_CONSOLE | + POWER_ACTION_DISABLE_WAKES | + POWER_ACTION_CRITICAL))) + { + DPRINT1("NtSetSystemPowerState: Bad parameters!\n"); + DPRINT1(" SystemAction: 0x%x\n", SystemAction); + DPRINT1(" MinSystemState: 0x%x\n", MinSystemState); + DPRINT1(" Flags: 0x%x\n", Flags); + return STATUS_INVALID_PARAMETER; + } + + /* Check for user caller */ + if (PreviousMode != KernelMode) + { + /* Check for shutdown permission */ + if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) + { + /* Not granted */ + DPRINT1("ERROR: Privilege not held for shutdown\n"); + //return STATUS_PRIVILEGE_NOT_HELD; HACK! + } + + /* Do it as a kernel-mode caller for consistency with system state */ + return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags); + } + + /* Read policy settings (partial shutdown vs. full shutdown) */ + if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy(); + + /* Disable lazy flushing of registry */ + DPRINT1("Stopping lazy flush\n"); + CmSetLazyFlushState(FALSE); + + /* Setup the power action */ + Action.Action = SystemAction; + Action.Flags = Flags; + + /* Notify callbacks */ + DPRINT1("Notifying callbacks\n"); + ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL); + + /* Swap in any worker thread stacks */ + DPRINT1("Swapping worker threads\n"); + ExSwapinWorkerThreads(FALSE); + + /* Make our action global */ + PopAction = Action; + + /* Start power loop */ + Status = STATUS_CANCELLED; + while (TRUE) + { + /* Break out if there's nothing to do */ + if (Action.Action == PowerActionNone) break; + + /* Check for first-pass or restart */ + if (Status == STATUS_CANCELLED) + { + /* Check for shutdown action */ + if ((PopAction.Action == PowerActionShutdown) || + (PopAction.Action == PowerActionShutdownReset) || + (PopAction.Action == PowerActionShutdownOff)) + { + /* Set the action */ + PopAction.Shutdown = TRUE; + } + + /* Now we are good to go */ + Status = STATUS_SUCCESS; + } + + /* Check if we're still in an invalid status */ + if (!NT_SUCCESS(Status)) break; + +#ifndef NEWCC + /* Flush dirty cache pages */ + CcRosFlushDirtyPages(-1, &Dummy); +#endif + + /* Flush all volumes and the registry */ + DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy); + PopFlushVolumes(PopAction.Shutdown); + + /* Set IRP for drivers */ + PopAction.IrpMinor = IRP_MN_SET_POWER; + if (PopAction.Shutdown) + { + DPRINT1("Queueing shutdown thread\n"); + /* Check if we are running in the system context */ + if (PsGetCurrentProcess() != PsInitialSystemProcess) + { + /* We're not, so use a worker thread for shutdown */ + ExInitializeWorkItem(&PopShutdownWorkItem, + &PopGracefulShutdown, + NULL); + + ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue); + + /* Spend us -- when we wake up, the system is good to go down */ + KeSuspendThread(KeGetCurrentThread()); + Status = STATUS_SYSTEM_SHUTDOWN; + goto Exit; + + } + else + { + /* Do the shutdown inline */ + PopGracefulShutdown(NULL); + } + } + + /* You should not have made it this far */ + ASSERT(FALSE && "System is still up and running?!"); + break; + } + +Exit: + /* We're done, return */ + return Status; +}