-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/po/power.c
* PURPOSE: Power Manager
- *
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * Hervé Poussineau (hpoussin@reactos.com)
*/
+/* INCLUDES ******************************************************************/
+
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+typedef struct _REQUEST_POWER_ITEM
+{
+ PREQUEST_POWER_COMPLETE CompletionRoutine;
+ POWER_STATE PowerState;
+ PVOID Context;
+} REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
BOOLEAN PopAcpiPresent = FALSE;
+POP_POWER_ACTION PopAction;
+WORK_QUEUE_ITEM PopShutdownWorkItem;
-/*
- * @implemented
- */
+/* PRIVATE FUNCTIONS *********************************************************/
+
+static
NTSTATUS
-STDCALL
-PoCallDriver(
- IN PDEVICE_OBJECT DeviceObject,
- IN OUT PIRP Irp)
+NTAPI
+PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PIO_STACK_LOCATION Stack;
+ PREQUEST_POWER_ITEM RequestPowerItem;
+
+ Stack = IoGetNextIrpStackLocation(Irp);
+ RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
+
+ RequestPowerItem->CompletionRoutine(DeviceObject,
+ Stack->MinorFunction,
+ RequestPowerItem->PowerState,
+ RequestPowerItem->Context,
+ &Irp->IoStatus);
+
+ ExFreePool(Context);
+
+ IoFreeIrp(Irp);
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+PopCleanupPowerState(IN PPOWER_STATE PowerState)
+{
+ //UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PDEVICE_OBJECT DeviceObject;
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_OBJECT Fdo;
+ NTSTATUS Status;
+ KEVENT Event;
+ PIRP Irp;
+
+ if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
+
+ Status = IopGetSystemPowerDeviceObject(&DeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No system power driver available\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Fdo = IoGetAttachedDeviceReference(DeviceObject);
+
+ if (Fdo == DeviceObject)
+ {
+ DPRINT("An FDO was not attached\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ KeInitializeEvent(&Event,
+ NotificationEvent,
+ FALSE);
+
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
+ Fdo,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &IoStatusBlock);
+
+ IrpSp = IoGetNextIrpStackLocation(Irp);
+ IrpSp->MinorFunction = IRP_MN_SET_POWER;
+ IrpSp->Parameters.Power.Type = SystemPowerState;
+ IrpSp->Parameters.Power.State.SystemState = PowerState;
+
+ DPRINT("Calling ACPI driver");
+ Status = PoCallDriver(Fdo, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ ObDereferenceObject(Fdo);
+
+ return Status;
+}
+
+BOOLEAN
+NTAPI
+PoInitSystem(IN ULONG BootPhase)
+{
+ PVOID NotificationEntry;
+ PCHAR CommandLine;
+ BOOLEAN ForceAcpiDisable = FALSE;
+
+ /* Check if this is phase 1 init */
+ if (BootPhase == 1)
+ {
+ /* Registry power button notification */
+ IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
+ 0, /* The registry has not been initialized yet */
+ (PVOID)&GUID_DEVICE_SYS_BUTTON,
+ IopRootDeviceNode->
+ PhysicalDeviceObject->DriverObject,
+ PopAddRemoveSysCapsCallback,
+ NULL,
+ &NotificationEntry);
+ return TRUE;
+ }
+
+ /* Get the Command Line */
+ CommandLine = KeLoaderBlock->LoadOptions;
+
+ /* Upcase it */
+ _strupr(CommandLine);
+
+ /* Check for ACPI disable */
+ if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
+
+ if (ForceAcpiDisable)
+ {
+ /* Set the ACPI State to False if it's been forced that way */
+ PopAcpiPresent = FALSE;
+ }
+ else
+ {
+ /* Otherwise check if the LoaderBlock has a ACPI Table */
+ PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
+ }
+
+
+ /* Initialize volume support */
+ InitializeListHead(&PopVolumeDevices);
+ KeInitializeGuardedMutex(&PopVolumeLock);
+
+ /* Initialize support for dope */
+ KeInitializeSpinLock(&PopDopeGlobalLock);
+ return TRUE;
+}
+
+VOID
+NTAPI
+PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
{
- NTSTATUS Status;
+ DPRINT1("PerfIdle function: %p\n", PowerState);
+}
- Status = IoCallDriver(DeviceObject, Irp);
+VOID
+NTAPI
+PopPerfIdleDpc(IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
+{
+ /* Call the Perf Idle function */
+ PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
+}
- return Status;
+VOID
+FASTCALL
+PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
+{
+ /* FIXME: Extremly naive implementation */
+ HalProcessorIdle();
+}
+
+VOID
+NTAPI
+PoInitializePrcb(IN PKPRCB Prcb)
+{
+ /* Initialize the Power State */
+ RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
+ Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
+ Prcb->PowerState.CurrentThrottle = 100;
+ Prcb->PowerState.CurrentThrottleIndex = 0;
+ Prcb->PowerState.IdleFunction = PopIdle0;
+
+ /* Initialize the Perf DPC and Timer */
+ KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
+ KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
+ KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
}
+/* PUBLIC FUNCTIONS **********************************************************/
+
/*
* @unimplemented
*/
-PULONG
-STDCALL
-PoRegisterDeviceForIdleDetection(
- IN PDEVICE_OBJECT DeviceObject,
- IN ULONG ConservationIdleTime,
- IN ULONG PerformanceIdleTime,
- IN DEVICE_POWER_STATE State)
+NTSTATUS
+NTAPI
+PoCancelDeviceNotify(IN PVOID NotifyBlock)
{
- return NULL;
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
-PVOID
-STDCALL
-PoRegisterSystemState(
- IN PVOID StateHandle,
- IN EXECUTION_STATE Flags)
+NTSTATUS
+NTAPI
+PoRegisterDeviceNotify(OUT PVOID Unknown0,
+ IN ULONG Unknown1,
+ IN ULONG Unknown2,
+ IN ULONG Unknown3,
+ IN PVOID Unknown4,
+ IN PVOID Unknown5)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+NTAPI
+PoShutdownBugCheck(IN BOOLEAN LogError,
+ IN ULONG BugCheckCode,
+ IN ULONG_PTR BugCheckParameter1,
+ IN ULONG_PTR BugCheckParameter2,
+ IN ULONG_PTR BugCheckParameter3,
+ IN ULONG_PTR BugCheckParameter4)
{
- return NULL;
+ DPRINT1("PoShutdownBugCheck called\n");
+
+ /* FIXME: Log error if requested */
+ /* FIXME: Initiate a shutdown */
+
+ /* Bugcheck the system */
+ KeBugCheckEx(BugCheckCode,
+ BugCheckParameter1,
+ BugCheckParameter2,
+ BugCheckParameter3,
+ BugCheckParameter4);
}
/*
* @unimplemented
*/
NTSTATUS
-STDCALL
-PoRequestPowerIrp(
- IN PDEVICE_OBJECT DeviceObject,
- IN UCHAR MinorFunction,
- IN POWER_STATE PowerState,
- IN PREQUEST_POWER_COMPLETE CompletionFunction,
- IN PVOID Context,
- OUT PIRP *Irp OPTIONAL)
+NTAPI
+PoRequestShutdownEvent(OUT PVOID *Event)
{
- return STATUS_NOT_IMPLEMENTED;
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
+/*
+ * @unimplemented
+ */
VOID
-STDCALL
-PoSetDeviceBusy(
- PULONG IdlePointer)
+NTAPI
+PoSetHiberRange(IN PVOID HiberContext,
+ IN ULONG Flags,
+ IN OUT PVOID StartPage,
+ IN ULONG Length,
+ IN ULONG PageTag)
{
+ UNIMPLEMENTED;
+ return;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PIRP Irp)
+{
+ NTSTATUS Status;
+
+ /* Forward to Io -- FIXME! */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ /* Return status */
+ return Status;
}
/*
* @unimplemented
*/
-POWER_STATE
-STDCALL
-PoSetPowerState(
- IN PDEVICE_OBJECT DeviceObject,
- IN POWER_STATE_TYPE Type,
- IN POWER_STATE State)
+PULONG
+NTAPI
+PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG ConservationIdleTime,
+ IN ULONG PerformanceIdleTime,
+ IN DEVICE_POWER_STATE State)
+{
+ UNIMPLEMENTED;
+ return NULL;
+}
+
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+PoRegisterSystemState(IN PVOID StateHandle,
+ IN EXECUTION_STATE Flags)
{
- POWER_STATE ps;
+ UNIMPLEMENTED;
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PREQUEST_POWER_COMPLETE CompletionFunction,
+ IN PVOID Context,
+ OUT PIRP *pIrp OPTIONAL)
+{
+ PDEVICE_OBJECT TopDeviceObject;
+ PIO_STACK_LOCATION Stack;
+ PIRP Irp;
+ PREQUEST_POWER_ITEM RequestPowerItem;
+ NTSTATUS Status;
+
+ if (MinorFunction != IRP_MN_QUERY_POWER
+ && MinorFunction != IRP_MN_SET_POWER
+ && MinorFunction != IRP_MN_WAIT_WAKE)
+ return STATUS_INVALID_PARAMETER_2;
+
+ RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
+ if (!RequestPowerItem)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Always call the top of the device stack */
+ TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
+
+ Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER,
+ TopDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (!Irp)
+ {
+ ExFreePool(RequestPowerItem);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* POWER IRPs are always initialized with a status code of
+ STATUS_NOT_IMPLEMENTED */
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ Irp->IoStatus.Information = 0;
+
+ Stack = IoGetNextIrpStackLocation(Irp);
+ Stack->MinorFunction = MinorFunction;
+ if (MinorFunction == IRP_MN_WAIT_WAKE)
+ Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
+ else
+ {
+ Stack->Parameters.Power.Type = DevicePowerState;
+ Stack->Parameters.Power.State = PowerState.DeviceState;
+ }
- ASSERT_IRQL(DISPATCH_LEVEL);
+ RequestPowerItem->CompletionRoutine = CompletionFunction;
+ RequestPowerItem->PowerState = PowerState;
+ RequestPowerItem->Context = Context;
+
+ if (pIrp != NULL)
+ *pIrp = Irp;
+
+ IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
+ Status = IoCallDriver(TopDeviceObject, Irp);
+
+ /* Always return STATUS_PENDING. The completion routine
+ * will call CompletionFunction and complete the Irp.
+ */
+ return STATUS_PENDING;
+}
+
+/*
+ * @unimplemented
+ */
+POWER_STATE
+NTAPI
+PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
+ IN POWER_STATE_TYPE Type,
+ IN POWER_STATE State)
+{
+ POWER_STATE ps;
+
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
- ps.SystemState = PowerSystemWorking; // Fully on
- ps.DeviceState = PowerDeviceD0; // Fully on
+ ps.SystemState = PowerSystemWorking; // Fully on
+ ps.DeviceState = PowerDeviceD0; // Fully on
- return ps;
+ return ps;
}
/*
* @unimplemented
*/
VOID
-STDCALL
-PoSetSystemState(
- IN EXECUTION_STATE Flags)
+NTAPI
+PoSetSystemState(IN EXECUTION_STATE Flags)
{
+ UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
-STDCALL
-PoStartNextPowerIrp(
- IN PIRP Irp)
+NTAPI
+PoStartNextPowerIrp(IN PIRP Irp)
{
+ UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
-STDCALL
-PoUnregisterSystemState(
- IN PVOID StateHandle)
+NTAPI
+PoUnregisterSystemState(IN PVOID StateHandle)
{
+ UNIMPLEMENTED;
}
+/*
+ * @unimplemented
+ */
NTSTATUS
-PopSetSystemPowerState(
- SYSTEM_POWER_STATE PowerState)
-{
- IO_STATUS_BLOCK IoStatusBlock;
- PDEVICE_OBJECT DeviceObject;
- PIO_STACK_LOCATION IrpSp;
- PDEVICE_OBJECT Fdo;
- NTSTATUS Status;
- KEVENT Event;
- PIRP Irp;
-
- if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
+NTAPI
+PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem)
+{
+ PAGED_CODE();
+
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtInitiatePowerAction (IN POWER_ACTION SystemAction,
+ IN SYSTEM_POWER_STATE MinSystemState,
+ IN ULONG Flags,
+ IN BOOLEAN Asynchronous)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
- Status = IopGetSystemPowerDeviceObject(&DeviceObject);
- if (!NT_SUCCESS(Status)) {
- CPRINT("No system power driver available\n");
- return STATUS_UNSUCCESSFUL;
- }
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength)
+{
+ NTSTATUS Status;
- Fdo = IoGetAttachedDeviceReference(DeviceObject);
+ PAGED_CODE();
- if (Fdo == DeviceObject)
+ DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
+ "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
+ PowerInformationLevel,
+ InputBuffer, InputBufferLength,
+ OutputBuffer, OutputBufferLength);
+
+ switch (PowerInformationLevel)
{
- DPRINT("An FDO was not attached\n");
- return STATUS_UNSUCCESSFUL;
+ case SystemBatteryState:
+ {
+ PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
+
+ if (InputBuffer != NULL)
+ return STATUS_INVALID_PARAMETER;
+ if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
+ RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
+ BatteryState->EstimatedTime = MAXULONG;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ case SystemPowerCapabilities:
+ {
+ PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
+
+ if (InputBuffer != NULL)
+ return STATUS_INVALID_PARAMETER;
+ if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
+ RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
+ //PowerCapabilities->SystemBatteriesPresent = 0;
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
+ DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
+ PowerInformationLevel);
+ break;
}
- KeInitializeEvent(&Event,
- NotificationEvent,
- FALSE);
-
- Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
- Fdo,
- NULL,
- 0,
- NULL,
- &Event,
- &IoStatusBlock);
-
- IrpSp = IoGetNextIrpStackLocation(Irp);
- IrpSp->MinorFunction = IRP_MN_SET_POWER;
- IrpSp->Parameters.Power.Type = SystemPowerState;
- IrpSp->Parameters.Power.State.SystemState = PowerState;
-
- Status = PoCallDriver(Fdo, Irp);
- if (Status == STATUS_PENDING)
- {
- KeWaitForSingleObject(&Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
- Status = IoStatusBlock.Status;
- }
+ return Status;
+}
- ObDereferenceObject(Fdo);
+NTSTATUS
+NTAPI
+NtGetDevicePowerState(IN HANDLE Device,
+ IN PDEVICE_POWER_STATE PowerState)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
- return Status;
+BOOLEAN
+NTAPI
+NtIsSystemResumeAutomatic(VOID)
+{
+ UNIMPLEMENTED;
+ return FALSE;
}
-VOID
-INIT_FUNCTION
-PoInit(PLOADER_PARAMETER_BLOCK LoaderBlock,
- BOOLEAN ForceAcpiDisable)
+NTSTATUS
+NTAPI
+NtRequestWakeupLatency(IN LATENCY_TIME Latency)
{
- if (ForceAcpiDisable)
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
+ OUT EXECUTION_STATE *PreviousFlags)
+{
+ PKTHREAD Thread = KeGetCurrentThread();
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ EXECUTION_STATE PreviousState;
+ PAGED_CODE();
+
+ /* Validate flags */
+ if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
+ {
+ /* Fail the request */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check for user parameters */
+ if (PreviousMode != KernelMode)
{
- /* Set the ACPI State to False if it's been forced that way */
- PopAcpiPresent = FALSE;
+ /* Protect the probes */
+ _SEH2_TRY
+ {
+ /* Check if the pointer is valid */
+ ProbeForWriteUlong(PreviousFlags);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* It isn't -- fail */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
- else
+
+ /* Save the previous state, always masking in the continous flag */
+ PreviousState = Thread->PowerState | ES_CONTINUOUS;
+
+ /* Check if we need to update the power state */
+ if (esFlags & ES_CONTINUOUS) Thread->PowerState = esFlags;
+
+ /* Protect the write back to user mode */
+ _SEH2_TRY
{
- /* Otherwise check the LoaderBlock's Flag */
- PopAcpiPresent = (LoaderBlock->Flags & MB_FLAGS_ACPI_TABLE) ? TRUE : FALSE;
+ /* Return the previous flags */
+ *PreviousFlags = PreviousState;
}
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Something's wrong, fail */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* All is good */
+ return STATUS_SUCCESS;
}
-/*
- * @unimplemented
- */
NTSTATUS
-STDCALL
-NtInitiatePowerAction (
- IN POWER_ACTION SystemAction,
- IN SYSTEM_POWER_STATE MinSystemState,
- IN ULONG Flags,
- IN BOOLEAN Asynchronous)
+NTAPI
+NtSetSystemPowerState(IN POWER_ACTION SystemAction,
+ IN SYSTEM_POWER_STATE MinSystemState,
+ IN ULONG Flags)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ POP_POWER_ACTION Action = {0};
+ NTSTATUS Status;
+
+ /* 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;
+ }
-/*
- * @unimplemented
- */
-NTSTATUS
-STDCALL
-NtPowerInformation(
- IN POWER_INFORMATION_LEVEL PowerInformationLevel,
- IN PVOID InputBuffer OPTIONAL,
- IN ULONG InputBufferLength,
- OUT PVOID OutputBuffer OPTIONAL,
- IN ULONG OutputBufferLength
- )
-{
- NTSTATUS Status;
-
- PAGED_CODE();
-
- DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
- "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
- PowerInformationLevel,
- InputBuffer, InputBufferLength,
- OutputBuffer, OutputBufferLength);
- switch (PowerInformationLevel)
- {
- case SystemBatteryState:
- {
- PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
-
- if (InputBuffer != NULL)
- return STATUS_INVALID_PARAMETER;
- if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
- return STATUS_BUFFER_TOO_SMALL;
-
- /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
- RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
- BatteryState->EstimatedTime = (ULONG)-1;
-
- Status = STATUS_SUCCESS;
- break;
- }
-
- default:
- Status = STATUS_NOT_IMPLEMENTED;
- DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
- PowerInformationLevel);
- for (;;);
- break;
- }
-
- return Status;
-}
+ /* 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);
+ }
-/* EOF */
+ /* 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;
+
+ /* Flush all volumes and the registry */
+ DPRINT1("Flushing volumes\n");
+ 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;
+}